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