|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|