1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
/*
* Copyright 2021 Google LLC
* SPDX-License-Identifier: MIT
*/
#include "render_virgl.h"
#include "virglrenderer.h"
#include "render_context.h"
struct render_virgl render_virgl_internal = {
#ifdef ENABLE_RENDER_SERVER_WORKER_THREAD
.struct_mutex = _MTX_INITIALIZER_NP,
.dispatch_mutex = _MTX_INITIALIZER_NP,
#endif
.init_count = 0,
};
static struct render_virgl *
render_virgl_lock_struct(void)
{
#ifdef ENABLE_RENDER_SERVER_WORKER_THREAD
mtx_lock(&render_virgl_internal.struct_mutex);
#endif
return &render_virgl_internal;
}
static void
render_virgl_unlock_struct(void)
{
#ifdef ENABLE_RENDER_SERVER_WORKER_THREAD
mtx_unlock(&render_virgl_internal.struct_mutex);
#endif
}
static struct render_context *
render_virgl_lookup_context(uint32_t ctx_id)
{
const struct render_virgl *virgl = render_virgl_lock_struct();
struct render_context *ctx = NULL;
#ifdef ENABLE_RENDER_SERVER_WORKER_THREAD
list_for_each_entry (struct render_context, iter, &virgl->contexts, head) {
if (iter->ctx_id == ctx_id) {
ctx = iter;
break;
}
}
#else
assert(list_is_singular(&virgl->contexts));
ctx = list_first_entry(&virgl->contexts, struct render_context, head);
assert(ctx->ctx_id == ctx_id);
(void)ctx_id;
#endif
render_virgl_unlock_struct();
return ctx;
}
static void
render_virgl_debug_callback(const char *fmt, va_list ap)
{
char buf[1024];
vsnprintf(buf, sizeof(buf), fmt, ap);
render_log(buf);
}
static void
render_virgl_cb_write_context_fence(UNUSED void *cookie,
uint32_t ctx_id,
uint32_t ring_idx,
uint64_t fence_id)
{
struct render_context *ctx = render_virgl_lookup_context(ctx_id);
assert(ctx);
const uint32_t seqno = (uint32_t)fence_id;
render_context_update_timeline(ctx, ring_idx, seqno);
}
static const struct virgl_renderer_callbacks render_virgl_cbs = {
.version = VIRGL_RENDERER_CALLBACKS_VERSION,
.write_context_fence = render_virgl_cb_write_context_fence,
};
void
render_virgl_add_context(struct render_context *ctx)
{
struct render_virgl *virgl = render_virgl_lock_struct();
list_addtail(&ctx->head, &virgl->contexts);
render_virgl_unlock_struct();
}
void
render_virgl_remove_context(struct render_context *ctx)
{
render_virgl_lock_struct();
list_del(&ctx->head);
render_virgl_unlock_struct();
}
void
render_virgl_fini(void)
{
struct render_virgl *virgl = render_virgl_lock_struct();
if (virgl->init_count) {
virgl->init_count--;
if (!virgl->init_count) {
render_virgl_lock_dispatch();
virgl_renderer_cleanup(virgl);
render_virgl_unlock_dispatch();
}
}
render_virgl_unlock_struct();
}
bool
render_virgl_init(uint32_t init_flags)
{
/* we only care if virgl and/or venus are enabled */
init_flags &= VIRGL_RENDERER_VENUS | VIRGL_RENDERER_NO_VIRGL;
/* always use sync thread and async fence cb for low latency */
init_flags |= VIRGL_RENDERER_THREAD_SYNC | VIRGL_RENDERER_ASYNC_FENCE_CB |
VIRGL_RENDERER_USE_EXTERNAL_BLOB;
struct render_virgl *virgl = render_virgl_lock_struct();
if (virgl->init_count) {
if (virgl->init_flags != init_flags) {
render_log("failed to re-initialize with flags 0x%x", init_flags);
goto fail;
}
} else {
render_virgl_lock_dispatch();
virgl_set_debug_callback(render_virgl_debug_callback);
int ret = virgl_renderer_init(virgl, init_flags,
(struct virgl_renderer_callbacks *)&render_virgl_cbs);
render_virgl_unlock_dispatch();
if (ret) {
render_log("failed to initialize virglrenderer");
goto fail;
}
list_inithead(&virgl->contexts);
virgl->init_flags = init_flags;
}
virgl->init_count++;
render_virgl_unlock_struct();
return true;
fail:
render_virgl_unlock_struct();
return false;
}
|