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