You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
virglrenderer/server/render_virgl.c

164 lines
4.0 KiB

/*
* 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,
uint64_t queue_id,
void *fence_cookie)
{
struct render_context *ctx = render_virgl_lookup_context(ctx_id);
assert(ctx);
const uint32_t ring_idx = queue_id;
const uint32_t seqno = (uint32_t)pointer_to_uintptr(fence_cookie);
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;
}