1*bbecb9d1SAndroid Build Coastguard Worker /*
2*bbecb9d1SAndroid Build Coastguard Worker * Copyright 2021 Google LLC
3*bbecb9d1SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
4*bbecb9d1SAndroid Build Coastguard Worker */
5*bbecb9d1SAndroid Build Coastguard Worker
6*bbecb9d1SAndroid Build Coastguard Worker #include "proxy_context.h"
7*bbecb9d1SAndroid Build Coastguard Worker
8*bbecb9d1SAndroid Build Coastguard Worker #include <fcntl.h>
9*bbecb9d1SAndroid Build Coastguard Worker #include <poll.h>
10*bbecb9d1SAndroid Build Coastguard Worker #include <sys/mman.h>
11*bbecb9d1SAndroid Build Coastguard Worker #include <unistd.h>
12*bbecb9d1SAndroid Build Coastguard Worker
13*bbecb9d1SAndroid Build Coastguard Worker #include "server/render_protocol.h"
14*bbecb9d1SAndroid Build Coastguard Worker #include "util/anon_file.h"
15*bbecb9d1SAndroid Build Coastguard Worker #include "util/bitscan.h"
16*bbecb9d1SAndroid Build Coastguard Worker
17*bbecb9d1SAndroid Build Coastguard Worker #include "proxy_client.h"
18*bbecb9d1SAndroid Build Coastguard Worker
19*bbecb9d1SAndroid Build Coastguard Worker struct proxy_fence {
20*bbecb9d1SAndroid Build Coastguard Worker uint32_t flags;
21*bbecb9d1SAndroid Build Coastguard Worker uint32_t seqno;
22*bbecb9d1SAndroid Build Coastguard Worker uint64_t fence_id;
23*bbecb9d1SAndroid Build Coastguard Worker struct list_head head;
24*bbecb9d1SAndroid Build Coastguard Worker };
25*bbecb9d1SAndroid Build Coastguard Worker
26*bbecb9d1SAndroid Build Coastguard Worker static inline void
proxy_context_resource_add(struct proxy_context * ctx,uint32_t res_id)27*bbecb9d1SAndroid Build Coastguard Worker proxy_context_resource_add(struct proxy_context *ctx, uint32_t res_id)
28*bbecb9d1SAndroid Build Coastguard Worker {
29*bbecb9d1SAndroid Build Coastguard Worker assert(!_mesa_hash_table_search(ctx->resource_table, (void *)(uintptr_t)res_id));
30*bbecb9d1SAndroid Build Coastguard Worker _mesa_hash_table_insert(ctx->resource_table, (void *)(uintptr_t)res_id, NULL);
31*bbecb9d1SAndroid Build Coastguard Worker }
32*bbecb9d1SAndroid Build Coastguard Worker
33*bbecb9d1SAndroid Build Coastguard Worker static inline bool
proxy_context_resource_find(struct proxy_context * ctx,uint32_t res_id)34*bbecb9d1SAndroid Build Coastguard Worker proxy_context_resource_find(struct proxy_context *ctx, uint32_t res_id)
35*bbecb9d1SAndroid Build Coastguard Worker {
36*bbecb9d1SAndroid Build Coastguard Worker return _mesa_hash_table_search(ctx->resource_table, (void *)(uintptr_t)res_id);
37*bbecb9d1SAndroid Build Coastguard Worker }
38*bbecb9d1SAndroid Build Coastguard Worker
39*bbecb9d1SAndroid Build Coastguard Worker static inline void
proxy_context_resource_remove(struct proxy_context * ctx,uint32_t res_id)40*bbecb9d1SAndroid Build Coastguard Worker proxy_context_resource_remove(struct proxy_context *ctx, uint32_t res_id)
41*bbecb9d1SAndroid Build Coastguard Worker {
42*bbecb9d1SAndroid Build Coastguard Worker _mesa_hash_table_remove_key(ctx->resource_table, (void *)(uintptr_t)res_id);
43*bbecb9d1SAndroid Build Coastguard Worker }
44*bbecb9d1SAndroid Build Coastguard Worker
45*bbecb9d1SAndroid Build Coastguard Worker static inline bool
proxy_context_resource_table_init(struct proxy_context * ctx)46*bbecb9d1SAndroid Build Coastguard Worker proxy_context_resource_table_init(struct proxy_context *ctx)
47*bbecb9d1SAndroid Build Coastguard Worker {
48*bbecb9d1SAndroid Build Coastguard Worker ctx->resource_table = _mesa_hash_table_create_u32_keys(NULL);
49*bbecb9d1SAndroid Build Coastguard Worker return ctx->resource_table;
50*bbecb9d1SAndroid Build Coastguard Worker }
51*bbecb9d1SAndroid Build Coastguard Worker
52*bbecb9d1SAndroid Build Coastguard Worker static inline void
proxy_context_resource_table_fini(struct proxy_context * ctx)53*bbecb9d1SAndroid Build Coastguard Worker proxy_context_resource_table_fini(struct proxy_context *ctx)
54*bbecb9d1SAndroid Build Coastguard Worker {
55*bbecb9d1SAndroid Build Coastguard Worker _mesa_hash_table_destroy(ctx->resource_table, NULL);
56*bbecb9d1SAndroid Build Coastguard Worker }
57*bbecb9d1SAndroid Build Coastguard Worker
58*bbecb9d1SAndroid Build Coastguard Worker static bool
proxy_fence_is_signaled(const struct proxy_fence * fence,uint32_t cur_seqno)59*bbecb9d1SAndroid Build Coastguard Worker proxy_fence_is_signaled(const struct proxy_fence *fence, uint32_t cur_seqno)
60*bbecb9d1SAndroid Build Coastguard Worker {
61*bbecb9d1SAndroid Build Coastguard Worker /* takes wrapping into account */
62*bbecb9d1SAndroid Build Coastguard Worker const uint32_t d = cur_seqno - fence->seqno;
63*bbecb9d1SAndroid Build Coastguard Worker return d < INT32_MAX;
64*bbecb9d1SAndroid Build Coastguard Worker }
65*bbecb9d1SAndroid Build Coastguard Worker
66*bbecb9d1SAndroid Build Coastguard Worker static struct proxy_fence *
proxy_context_alloc_fence(struct proxy_context * ctx)67*bbecb9d1SAndroid Build Coastguard Worker proxy_context_alloc_fence(struct proxy_context *ctx)
68*bbecb9d1SAndroid Build Coastguard Worker {
69*bbecb9d1SAndroid Build Coastguard Worker struct proxy_fence *fence = NULL;
70*bbecb9d1SAndroid Build Coastguard Worker
71*bbecb9d1SAndroid Build Coastguard Worker if (proxy_renderer.flags & VIRGL_RENDERER_ASYNC_FENCE_CB)
72*bbecb9d1SAndroid Build Coastguard Worker mtx_lock(&ctx->free_fences_mutex);
73*bbecb9d1SAndroid Build Coastguard Worker
74*bbecb9d1SAndroid Build Coastguard Worker if (!list_is_empty(&ctx->free_fences)) {
75*bbecb9d1SAndroid Build Coastguard Worker fence = list_first_entry(&ctx->free_fences, struct proxy_fence, head);
76*bbecb9d1SAndroid Build Coastguard Worker list_del(&fence->head);
77*bbecb9d1SAndroid Build Coastguard Worker }
78*bbecb9d1SAndroid Build Coastguard Worker
79*bbecb9d1SAndroid Build Coastguard Worker if (proxy_renderer.flags & VIRGL_RENDERER_ASYNC_FENCE_CB)
80*bbecb9d1SAndroid Build Coastguard Worker mtx_unlock(&ctx->free_fences_mutex);
81*bbecb9d1SAndroid Build Coastguard Worker
82*bbecb9d1SAndroid Build Coastguard Worker return fence ? fence : malloc(sizeof(*fence));
83*bbecb9d1SAndroid Build Coastguard Worker }
84*bbecb9d1SAndroid Build Coastguard Worker
85*bbecb9d1SAndroid Build Coastguard Worker static void
proxy_context_free_fence(struct proxy_context * ctx,struct proxy_fence * fence)86*bbecb9d1SAndroid Build Coastguard Worker proxy_context_free_fence(struct proxy_context *ctx, struct proxy_fence *fence)
87*bbecb9d1SAndroid Build Coastguard Worker {
88*bbecb9d1SAndroid Build Coastguard Worker if (proxy_renderer.flags & VIRGL_RENDERER_ASYNC_FENCE_CB)
89*bbecb9d1SAndroid Build Coastguard Worker mtx_lock(&ctx->free_fences_mutex);
90*bbecb9d1SAndroid Build Coastguard Worker
91*bbecb9d1SAndroid Build Coastguard Worker list_add(&fence->head, &ctx->free_fences);
92*bbecb9d1SAndroid Build Coastguard Worker
93*bbecb9d1SAndroid Build Coastguard Worker if (proxy_renderer.flags & VIRGL_RENDERER_ASYNC_FENCE_CB)
94*bbecb9d1SAndroid Build Coastguard Worker mtx_unlock(&ctx->free_fences_mutex);
95*bbecb9d1SAndroid Build Coastguard Worker }
96*bbecb9d1SAndroid Build Coastguard Worker
97*bbecb9d1SAndroid Build Coastguard Worker static uint32_t
proxy_context_load_timeline_seqno(struct proxy_context * ctx,uint32_t ring_idx)98*bbecb9d1SAndroid Build Coastguard Worker proxy_context_load_timeline_seqno(struct proxy_context *ctx, uint32_t ring_idx)
99*bbecb9d1SAndroid Build Coastguard Worker {
100*bbecb9d1SAndroid Build Coastguard Worker return atomic_load(&ctx->timeline_seqnos[ring_idx]);
101*bbecb9d1SAndroid Build Coastguard Worker }
102*bbecb9d1SAndroid Build Coastguard Worker
103*bbecb9d1SAndroid Build Coastguard Worker static bool
proxy_context_retire_timeline_fences_locked(struct proxy_context * ctx,uint32_t ring_idx,uint32_t cur_seqno)104*bbecb9d1SAndroid Build Coastguard Worker proxy_context_retire_timeline_fences_locked(struct proxy_context *ctx,
105*bbecb9d1SAndroid Build Coastguard Worker uint32_t ring_idx,
106*bbecb9d1SAndroid Build Coastguard Worker uint32_t cur_seqno)
107*bbecb9d1SAndroid Build Coastguard Worker {
108*bbecb9d1SAndroid Build Coastguard Worker struct proxy_timeline *timeline = &ctx->timelines[ring_idx];
109*bbecb9d1SAndroid Build Coastguard Worker bool force_retire_all = false;
110*bbecb9d1SAndroid Build Coastguard Worker
111*bbecb9d1SAndroid Build Coastguard Worker /* check if the socket has been disconnected (i.e., the other end has
112*bbecb9d1SAndroid Build Coastguard Worker * crashed) if no progress is made after a while
113*bbecb9d1SAndroid Build Coastguard Worker */
114*bbecb9d1SAndroid Build Coastguard Worker if (timeline->cur_seqno == cur_seqno && !list_is_empty(&timeline->fences)) {
115*bbecb9d1SAndroid Build Coastguard Worker timeline->cur_seqno_stall_count++;
116*bbecb9d1SAndroid Build Coastguard Worker if (timeline->cur_seqno_stall_count < 100 ||
117*bbecb9d1SAndroid Build Coastguard Worker proxy_socket_is_connected(&ctx->socket))
118*bbecb9d1SAndroid Build Coastguard Worker return false;
119*bbecb9d1SAndroid Build Coastguard Worker
120*bbecb9d1SAndroid Build Coastguard Worker /* socket has been disconnected */
121*bbecb9d1SAndroid Build Coastguard Worker force_retire_all = true;
122*bbecb9d1SAndroid Build Coastguard Worker }
123*bbecb9d1SAndroid Build Coastguard Worker
124*bbecb9d1SAndroid Build Coastguard Worker timeline->cur_seqno = cur_seqno;
125*bbecb9d1SAndroid Build Coastguard Worker timeline->cur_seqno_stall_count = 0;
126*bbecb9d1SAndroid Build Coastguard Worker
127*bbecb9d1SAndroid Build Coastguard Worker list_for_each_entry_safe (struct proxy_fence, fence, &timeline->fences, head) {
128*bbecb9d1SAndroid Build Coastguard Worker if (!proxy_fence_is_signaled(fence, timeline->cur_seqno) && !force_retire_all)
129*bbecb9d1SAndroid Build Coastguard Worker return false;
130*bbecb9d1SAndroid Build Coastguard Worker
131*bbecb9d1SAndroid Build Coastguard Worker ctx->base.fence_retire(&ctx->base, ring_idx, fence->fence_id);
132*bbecb9d1SAndroid Build Coastguard Worker
133*bbecb9d1SAndroid Build Coastguard Worker list_del(&fence->head);
134*bbecb9d1SAndroid Build Coastguard Worker proxy_context_free_fence(ctx, fence);
135*bbecb9d1SAndroid Build Coastguard Worker }
136*bbecb9d1SAndroid Build Coastguard Worker
137*bbecb9d1SAndroid Build Coastguard Worker return true;
138*bbecb9d1SAndroid Build Coastguard Worker }
139*bbecb9d1SAndroid Build Coastguard Worker
140*bbecb9d1SAndroid Build Coastguard Worker static void
proxy_context_retire_fences_internal(struct proxy_context * ctx)141*bbecb9d1SAndroid Build Coastguard Worker proxy_context_retire_fences_internal(struct proxy_context *ctx)
142*bbecb9d1SAndroid Build Coastguard Worker {
143*bbecb9d1SAndroid Build Coastguard Worker if (ctx->sync_thread.fence_eventfd >= 0)
144*bbecb9d1SAndroid Build Coastguard Worker flush_eventfd(ctx->sync_thread.fence_eventfd);
145*bbecb9d1SAndroid Build Coastguard Worker
146*bbecb9d1SAndroid Build Coastguard Worker if (proxy_renderer.flags & VIRGL_RENDERER_ASYNC_FENCE_CB)
147*bbecb9d1SAndroid Build Coastguard Worker mtx_lock(&ctx->timeline_mutex);
148*bbecb9d1SAndroid Build Coastguard Worker
149*bbecb9d1SAndroid Build Coastguard Worker uint64_t new_busy_mask = 0;
150*bbecb9d1SAndroid Build Coastguard Worker uint64_t old_busy_mask = ctx->timeline_busy_mask;
151*bbecb9d1SAndroid Build Coastguard Worker while (old_busy_mask) {
152*bbecb9d1SAndroid Build Coastguard Worker const uint32_t ring_idx = u_bit_scan64(&old_busy_mask);
153*bbecb9d1SAndroid Build Coastguard Worker const uint32_t cur_seqno = proxy_context_load_timeline_seqno(ctx, ring_idx);
154*bbecb9d1SAndroid Build Coastguard Worker if (!proxy_context_retire_timeline_fences_locked(ctx, ring_idx, cur_seqno))
155*bbecb9d1SAndroid Build Coastguard Worker new_busy_mask |= 1ull << ring_idx;
156*bbecb9d1SAndroid Build Coastguard Worker }
157*bbecb9d1SAndroid Build Coastguard Worker
158*bbecb9d1SAndroid Build Coastguard Worker ctx->timeline_busy_mask = new_busy_mask;
159*bbecb9d1SAndroid Build Coastguard Worker
160*bbecb9d1SAndroid Build Coastguard Worker if (proxy_renderer.flags & VIRGL_RENDERER_ASYNC_FENCE_CB)
161*bbecb9d1SAndroid Build Coastguard Worker mtx_unlock(&ctx->timeline_mutex);
162*bbecb9d1SAndroid Build Coastguard Worker }
163*bbecb9d1SAndroid Build Coastguard Worker
164*bbecb9d1SAndroid Build Coastguard Worker static int
proxy_context_sync_thread(void * arg)165*bbecb9d1SAndroid Build Coastguard Worker proxy_context_sync_thread(void *arg)
166*bbecb9d1SAndroid Build Coastguard Worker {
167*bbecb9d1SAndroid Build Coastguard Worker struct proxy_context *ctx = arg;
168*bbecb9d1SAndroid Build Coastguard Worker struct pollfd poll_fds[2] = {
169*bbecb9d1SAndroid Build Coastguard Worker [0] = {
170*bbecb9d1SAndroid Build Coastguard Worker .fd = ctx->sync_thread.fence_eventfd,
171*bbecb9d1SAndroid Build Coastguard Worker .events = POLLIN,
172*bbecb9d1SAndroid Build Coastguard Worker },
173*bbecb9d1SAndroid Build Coastguard Worker [1] = {
174*bbecb9d1SAndroid Build Coastguard Worker .fd = ctx->socket.fd,
175*bbecb9d1SAndroid Build Coastguard Worker },
176*bbecb9d1SAndroid Build Coastguard Worker };
177*bbecb9d1SAndroid Build Coastguard Worker
178*bbecb9d1SAndroid Build Coastguard Worker assert(proxy_renderer.flags & VIRGL_RENDERER_ASYNC_FENCE_CB);
179*bbecb9d1SAndroid Build Coastguard Worker
180*bbecb9d1SAndroid Build Coastguard Worker while (!ctx->sync_thread.stop) {
181*bbecb9d1SAndroid Build Coastguard Worker const int ret = poll(poll_fds, ARRAY_SIZE(poll_fds), -1);
182*bbecb9d1SAndroid Build Coastguard Worker if (ret <= 0) {
183*bbecb9d1SAndroid Build Coastguard Worker if (ret < 0 && (errno == EINTR || errno == EAGAIN))
184*bbecb9d1SAndroid Build Coastguard Worker continue;
185*bbecb9d1SAndroid Build Coastguard Worker
186*bbecb9d1SAndroid Build Coastguard Worker proxy_log("failed to poll fence eventfd");
187*bbecb9d1SAndroid Build Coastguard Worker break;
188*bbecb9d1SAndroid Build Coastguard Worker }
189*bbecb9d1SAndroid Build Coastguard Worker
190*bbecb9d1SAndroid Build Coastguard Worker proxy_context_retire_fences_internal(ctx);
191*bbecb9d1SAndroid Build Coastguard Worker }
192*bbecb9d1SAndroid Build Coastguard Worker
193*bbecb9d1SAndroid Build Coastguard Worker return 0;
194*bbecb9d1SAndroid Build Coastguard Worker }
195*bbecb9d1SAndroid Build Coastguard Worker
196*bbecb9d1SAndroid Build Coastguard Worker static int
proxy_context_submit_fence(struct virgl_context * base,uint32_t flags,uint32_t ring_idx,uint64_t fence_id)197*bbecb9d1SAndroid Build Coastguard Worker proxy_context_submit_fence(struct virgl_context *base,
198*bbecb9d1SAndroid Build Coastguard Worker uint32_t flags,
199*bbecb9d1SAndroid Build Coastguard Worker uint32_t ring_idx,
200*bbecb9d1SAndroid Build Coastguard Worker uint64_t fence_id)
201*bbecb9d1SAndroid Build Coastguard Worker {
202*bbecb9d1SAndroid Build Coastguard Worker struct proxy_context *ctx = (struct proxy_context *)base;
203*bbecb9d1SAndroid Build Coastguard Worker const uint64_t old_busy_mask = ctx->timeline_busy_mask;
204*bbecb9d1SAndroid Build Coastguard Worker
205*bbecb9d1SAndroid Build Coastguard Worker if (ring_idx >= PROXY_CONTEXT_TIMELINE_COUNT)
206*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
207*bbecb9d1SAndroid Build Coastguard Worker
208*bbecb9d1SAndroid Build Coastguard Worker struct proxy_timeline *timeline = &ctx->timelines[ring_idx];
209*bbecb9d1SAndroid Build Coastguard Worker struct proxy_fence *fence = proxy_context_alloc_fence(ctx);
210*bbecb9d1SAndroid Build Coastguard Worker if (!fence)
211*bbecb9d1SAndroid Build Coastguard Worker return -ENOMEM;
212*bbecb9d1SAndroid Build Coastguard Worker
213*bbecb9d1SAndroid Build Coastguard Worker fence->flags = flags;
214*bbecb9d1SAndroid Build Coastguard Worker fence->seqno = timeline->next_seqno++;
215*bbecb9d1SAndroid Build Coastguard Worker fence->fence_id = fence_id;
216*bbecb9d1SAndroid Build Coastguard Worker
217*bbecb9d1SAndroid Build Coastguard Worker if (proxy_renderer.flags & VIRGL_RENDERER_ASYNC_FENCE_CB)
218*bbecb9d1SAndroid Build Coastguard Worker mtx_lock(&ctx->timeline_mutex);
219*bbecb9d1SAndroid Build Coastguard Worker
220*bbecb9d1SAndroid Build Coastguard Worker list_addtail(&fence->head, &timeline->fences);
221*bbecb9d1SAndroid Build Coastguard Worker ctx->timeline_busy_mask |= 1ull << ring_idx;
222*bbecb9d1SAndroid Build Coastguard Worker
223*bbecb9d1SAndroid Build Coastguard Worker if (proxy_renderer.flags & VIRGL_RENDERER_ASYNC_FENCE_CB)
224*bbecb9d1SAndroid Build Coastguard Worker mtx_unlock(&ctx->timeline_mutex);
225*bbecb9d1SAndroid Build Coastguard Worker
226*bbecb9d1SAndroid Build Coastguard Worker const struct render_context_op_submit_fence_request req = {
227*bbecb9d1SAndroid Build Coastguard Worker .header.op = RENDER_CONTEXT_OP_SUBMIT_FENCE,
228*bbecb9d1SAndroid Build Coastguard Worker .flags = flags,
229*bbecb9d1SAndroid Build Coastguard Worker .ring_index = ring_idx,
230*bbecb9d1SAndroid Build Coastguard Worker .seqno = fence->seqno,
231*bbecb9d1SAndroid Build Coastguard Worker };
232*bbecb9d1SAndroid Build Coastguard Worker if (proxy_socket_send_request(&ctx->socket, &req, sizeof(req)))
233*bbecb9d1SAndroid Build Coastguard Worker return 0;
234*bbecb9d1SAndroid Build Coastguard Worker
235*bbecb9d1SAndroid Build Coastguard Worker /* recover timeline fences and busy_mask on submit_fence request failure */
236*bbecb9d1SAndroid Build Coastguard Worker if (proxy_renderer.flags & VIRGL_RENDERER_ASYNC_FENCE_CB)
237*bbecb9d1SAndroid Build Coastguard Worker mtx_lock(&ctx->timeline_mutex);
238*bbecb9d1SAndroid Build Coastguard Worker
239*bbecb9d1SAndroid Build Coastguard Worker list_del(&fence->head);
240*bbecb9d1SAndroid Build Coastguard Worker ctx->timeline_busy_mask = old_busy_mask;
241*bbecb9d1SAndroid Build Coastguard Worker
242*bbecb9d1SAndroid Build Coastguard Worker if (proxy_renderer.flags & VIRGL_RENDERER_ASYNC_FENCE_CB)
243*bbecb9d1SAndroid Build Coastguard Worker mtx_unlock(&ctx->timeline_mutex);
244*bbecb9d1SAndroid Build Coastguard Worker
245*bbecb9d1SAndroid Build Coastguard Worker proxy_context_free_fence(ctx, fence);
246*bbecb9d1SAndroid Build Coastguard Worker proxy_log("failed to submit fence");
247*bbecb9d1SAndroid Build Coastguard Worker return -1;
248*bbecb9d1SAndroid Build Coastguard Worker }
249*bbecb9d1SAndroid Build Coastguard Worker
250*bbecb9d1SAndroid Build Coastguard Worker static void
proxy_context_retire_fences(struct virgl_context * base)251*bbecb9d1SAndroid Build Coastguard Worker proxy_context_retire_fences(struct virgl_context *base)
252*bbecb9d1SAndroid Build Coastguard Worker {
253*bbecb9d1SAndroid Build Coastguard Worker struct proxy_context *ctx = (struct proxy_context *)base;
254*bbecb9d1SAndroid Build Coastguard Worker
255*bbecb9d1SAndroid Build Coastguard Worker assert(!(proxy_renderer.flags & VIRGL_RENDERER_ASYNC_FENCE_CB));
256*bbecb9d1SAndroid Build Coastguard Worker proxy_context_retire_fences_internal(ctx);
257*bbecb9d1SAndroid Build Coastguard Worker }
258*bbecb9d1SAndroid Build Coastguard Worker
259*bbecb9d1SAndroid Build Coastguard Worker static int
proxy_context_get_fencing_fd(struct virgl_context * base)260*bbecb9d1SAndroid Build Coastguard Worker proxy_context_get_fencing_fd(struct virgl_context *base)
261*bbecb9d1SAndroid Build Coastguard Worker {
262*bbecb9d1SAndroid Build Coastguard Worker struct proxy_context *ctx = (struct proxy_context *)base;
263*bbecb9d1SAndroid Build Coastguard Worker
264*bbecb9d1SAndroid Build Coastguard Worker assert(!(proxy_renderer.flags & VIRGL_RENDERER_ASYNC_FENCE_CB));
265*bbecb9d1SAndroid Build Coastguard Worker return ctx->sync_thread.fence_eventfd;
266*bbecb9d1SAndroid Build Coastguard Worker }
267*bbecb9d1SAndroid Build Coastguard Worker
268*bbecb9d1SAndroid Build Coastguard Worker static int
proxy_context_submit_cmd(struct virgl_context * base,const void * buffer,size_t size)269*bbecb9d1SAndroid Build Coastguard Worker proxy_context_submit_cmd(struct virgl_context *base, const void *buffer, size_t size)
270*bbecb9d1SAndroid Build Coastguard Worker {
271*bbecb9d1SAndroid Build Coastguard Worker struct proxy_context *ctx = (struct proxy_context *)base;
272*bbecb9d1SAndroid Build Coastguard Worker
273*bbecb9d1SAndroid Build Coastguard Worker if (!size)
274*bbecb9d1SAndroid Build Coastguard Worker return 0;
275*bbecb9d1SAndroid Build Coastguard Worker
276*bbecb9d1SAndroid Build Coastguard Worker struct render_context_op_submit_cmd_request req = {
277*bbecb9d1SAndroid Build Coastguard Worker .header.op = RENDER_CONTEXT_OP_SUBMIT_CMD,
278*bbecb9d1SAndroid Build Coastguard Worker .size = size,
279*bbecb9d1SAndroid Build Coastguard Worker };
280*bbecb9d1SAndroid Build Coastguard Worker
281*bbecb9d1SAndroid Build Coastguard Worker const size_t inlined = MIN2(size, sizeof(req.cmd));
282*bbecb9d1SAndroid Build Coastguard Worker memcpy(req.cmd, buffer, inlined);
283*bbecb9d1SAndroid Build Coastguard Worker
284*bbecb9d1SAndroid Build Coastguard Worker if (!proxy_socket_send_request(&ctx->socket, &req, sizeof(req))) {
285*bbecb9d1SAndroid Build Coastguard Worker proxy_log("failed to submit cmd");
286*bbecb9d1SAndroid Build Coastguard Worker return -1;
287*bbecb9d1SAndroid Build Coastguard Worker }
288*bbecb9d1SAndroid Build Coastguard Worker
289*bbecb9d1SAndroid Build Coastguard Worker if (size > inlined) {
290*bbecb9d1SAndroid Build Coastguard Worker if (!proxy_socket_send_request(&ctx->socket, (const char *)buffer + inlined,
291*bbecb9d1SAndroid Build Coastguard Worker size - inlined)) {
292*bbecb9d1SAndroid Build Coastguard Worker proxy_log("failed to submit large cmd buffer");
293*bbecb9d1SAndroid Build Coastguard Worker return -1;
294*bbecb9d1SAndroid Build Coastguard Worker }
295*bbecb9d1SAndroid Build Coastguard Worker }
296*bbecb9d1SAndroid Build Coastguard Worker
297*bbecb9d1SAndroid Build Coastguard Worker /* XXX this is forced a roundtrip to avoid surprises; vtest requires this
298*bbecb9d1SAndroid Build Coastguard Worker * at least
299*bbecb9d1SAndroid Build Coastguard Worker */
300*bbecb9d1SAndroid Build Coastguard Worker struct render_context_op_submit_cmd_reply reply;
301*bbecb9d1SAndroid Build Coastguard Worker if (!proxy_socket_receive_reply(&ctx->socket, &reply, sizeof(reply))) {
302*bbecb9d1SAndroid Build Coastguard Worker proxy_log("failed to get submit result");
303*bbecb9d1SAndroid Build Coastguard Worker return -1;
304*bbecb9d1SAndroid Build Coastguard Worker }
305*bbecb9d1SAndroid Build Coastguard Worker
306*bbecb9d1SAndroid Build Coastguard Worker return reply.ok ? 0 : -1;
307*bbecb9d1SAndroid Build Coastguard Worker }
308*bbecb9d1SAndroid Build Coastguard Worker
309*bbecb9d1SAndroid Build Coastguard Worker static bool
validate_resource_fd_shm(int fd,uint64_t expected_size)310*bbecb9d1SAndroid Build Coastguard Worker validate_resource_fd_shm(int fd, uint64_t expected_size)
311*bbecb9d1SAndroid Build Coastguard Worker {
312*bbecb9d1SAndroid Build Coastguard Worker static const int blocked_seals = F_SEAL_WRITE;
313*bbecb9d1SAndroid Build Coastguard Worker
314*bbecb9d1SAndroid Build Coastguard Worker const int seals = fcntl(fd, F_GET_SEALS);
315*bbecb9d1SAndroid Build Coastguard Worker if (seals & blocked_seals) {
316*bbecb9d1SAndroid Build Coastguard Worker proxy_log("failed to validate shm seals(%d): blocked(%d)", seals, blocked_seals);
317*bbecb9d1SAndroid Build Coastguard Worker return false;
318*bbecb9d1SAndroid Build Coastguard Worker }
319*bbecb9d1SAndroid Build Coastguard Worker
320*bbecb9d1SAndroid Build Coastguard Worker const uint64_t size = lseek(fd, 0, SEEK_END);
321*bbecb9d1SAndroid Build Coastguard Worker if (size != expected_size) {
322*bbecb9d1SAndroid Build Coastguard Worker proxy_log("failed to validate shm size(%" PRIu64 ") expected(%" PRIu64 ")", size,
323*bbecb9d1SAndroid Build Coastguard Worker expected_size);
324*bbecb9d1SAndroid Build Coastguard Worker return false;
325*bbecb9d1SAndroid Build Coastguard Worker }
326*bbecb9d1SAndroid Build Coastguard Worker
327*bbecb9d1SAndroid Build Coastguard Worker return true;
328*bbecb9d1SAndroid Build Coastguard Worker }
329*bbecb9d1SAndroid Build Coastguard Worker
330*bbecb9d1SAndroid Build Coastguard Worker static inline int
add_required_seals_to_fd(int fd)331*bbecb9d1SAndroid Build Coastguard Worker add_required_seals_to_fd(int fd)
332*bbecb9d1SAndroid Build Coastguard Worker {
333*bbecb9d1SAndroid Build Coastguard Worker return fcntl(fd, F_ADD_SEALS, F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW);
334*bbecb9d1SAndroid Build Coastguard Worker }
335*bbecb9d1SAndroid Build Coastguard Worker
336*bbecb9d1SAndroid Build Coastguard Worker static int
proxy_context_get_blob(struct virgl_context * base,uint32_t res_id,uint64_t blob_id,uint64_t blob_size,uint32_t blob_flags,struct virgl_context_blob * blob)337*bbecb9d1SAndroid Build Coastguard Worker proxy_context_get_blob(struct virgl_context *base,
338*bbecb9d1SAndroid Build Coastguard Worker uint32_t res_id,
339*bbecb9d1SAndroid Build Coastguard Worker uint64_t blob_id,
340*bbecb9d1SAndroid Build Coastguard Worker uint64_t blob_size,
341*bbecb9d1SAndroid Build Coastguard Worker uint32_t blob_flags,
342*bbecb9d1SAndroid Build Coastguard Worker struct virgl_context_blob *blob)
343*bbecb9d1SAndroid Build Coastguard Worker {
344*bbecb9d1SAndroid Build Coastguard Worker /* RENDER_CONTEXT_OP_CREATE_RESOURCE implies resource attach, thus proxy tracks
345*bbecb9d1SAndroid Build Coastguard Worker * resources created here to avoid double attaching the same resource when proxy is on
346*bbecb9d1SAndroid Build Coastguard Worker * attach_resource callback.
347*bbecb9d1SAndroid Build Coastguard Worker */
348*bbecb9d1SAndroid Build Coastguard Worker struct proxy_context *ctx = (struct proxy_context *)base;
349*bbecb9d1SAndroid Build Coastguard Worker
350*bbecb9d1SAndroid Build Coastguard Worker const struct render_context_op_create_resource_request req = {
351*bbecb9d1SAndroid Build Coastguard Worker .header.op = RENDER_CONTEXT_OP_CREATE_RESOURCE,
352*bbecb9d1SAndroid Build Coastguard Worker .res_id = res_id,
353*bbecb9d1SAndroid Build Coastguard Worker .blob_id = blob_id,
354*bbecb9d1SAndroid Build Coastguard Worker .blob_size = blob_size,
355*bbecb9d1SAndroid Build Coastguard Worker .blob_flags = blob_flags,
356*bbecb9d1SAndroid Build Coastguard Worker };
357*bbecb9d1SAndroid Build Coastguard Worker if (!proxy_socket_send_request(&ctx->socket, &req, sizeof(req))) {
358*bbecb9d1SAndroid Build Coastguard Worker proxy_log("failed to get blob %" PRIu64, blob_id);
359*bbecb9d1SAndroid Build Coastguard Worker return -1;
360*bbecb9d1SAndroid Build Coastguard Worker }
361*bbecb9d1SAndroid Build Coastguard Worker
362*bbecb9d1SAndroid Build Coastguard Worker struct render_context_op_create_resource_reply reply;
363*bbecb9d1SAndroid Build Coastguard Worker int reply_fd;
364*bbecb9d1SAndroid Build Coastguard Worker int reply_fd_count;
365*bbecb9d1SAndroid Build Coastguard Worker if (!proxy_socket_receive_reply_with_fds(&ctx->socket, &reply, sizeof(reply),
366*bbecb9d1SAndroid Build Coastguard Worker &reply_fd, 1, &reply_fd_count)) {
367*bbecb9d1SAndroid Build Coastguard Worker proxy_log("failed to get reply of blob %" PRIu64, blob_id);
368*bbecb9d1SAndroid Build Coastguard Worker return -1;
369*bbecb9d1SAndroid Build Coastguard Worker }
370*bbecb9d1SAndroid Build Coastguard Worker
371*bbecb9d1SAndroid Build Coastguard Worker if (!reply_fd_count) {
372*bbecb9d1SAndroid Build Coastguard Worker proxy_log("invalid reply for blob %" PRIu64, blob_id);
373*bbecb9d1SAndroid Build Coastguard Worker return -1;
374*bbecb9d1SAndroid Build Coastguard Worker }
375*bbecb9d1SAndroid Build Coastguard Worker
376*bbecb9d1SAndroid Build Coastguard Worker bool reply_fd_valid = false;
377*bbecb9d1SAndroid Build Coastguard Worker switch (reply.fd_type) {
378*bbecb9d1SAndroid Build Coastguard Worker case VIRGL_RESOURCE_FD_DMABUF:
379*bbecb9d1SAndroid Build Coastguard Worker /* TODO validate the fd is dmabuf >= blob_size */
380*bbecb9d1SAndroid Build Coastguard Worker reply_fd_valid = true;
381*bbecb9d1SAndroid Build Coastguard Worker break;
382*bbecb9d1SAndroid Build Coastguard Worker case VIRGL_RESOURCE_FD_OPAQUE:
383*bbecb9d1SAndroid Build Coastguard Worker /* this will be validated when imported by the client */
384*bbecb9d1SAndroid Build Coastguard Worker reply_fd_valid = true;
385*bbecb9d1SAndroid Build Coastguard Worker break;
386*bbecb9d1SAndroid Build Coastguard Worker case VIRGL_RESOURCE_FD_SHM:
387*bbecb9d1SAndroid Build Coastguard Worker /* validate the seals and size here */
388*bbecb9d1SAndroid Build Coastguard Worker reply_fd_valid = !add_required_seals_to_fd(reply_fd) &&
389*bbecb9d1SAndroid Build Coastguard Worker validate_resource_fd_shm(reply_fd, blob_size);
390*bbecb9d1SAndroid Build Coastguard Worker break;
391*bbecb9d1SAndroid Build Coastguard Worker default:
392*bbecb9d1SAndroid Build Coastguard Worker break;
393*bbecb9d1SAndroid Build Coastguard Worker }
394*bbecb9d1SAndroid Build Coastguard Worker if (!reply_fd_valid) {
395*bbecb9d1SAndroid Build Coastguard Worker proxy_log("invalid fd type %d for blob %" PRIu64, reply.fd_type, blob_id);
396*bbecb9d1SAndroid Build Coastguard Worker close(reply_fd);
397*bbecb9d1SAndroid Build Coastguard Worker return -1;
398*bbecb9d1SAndroid Build Coastguard Worker }
399*bbecb9d1SAndroid Build Coastguard Worker
400*bbecb9d1SAndroid Build Coastguard Worker blob->type = reply.fd_type;
401*bbecb9d1SAndroid Build Coastguard Worker blob->u.fd = reply_fd;
402*bbecb9d1SAndroid Build Coastguard Worker blob->map_info = reply.map_info;
403*bbecb9d1SAndroid Build Coastguard Worker
404*bbecb9d1SAndroid Build Coastguard Worker proxy_context_resource_add(ctx, res_id);
405*bbecb9d1SAndroid Build Coastguard Worker
406*bbecb9d1SAndroid Build Coastguard Worker return 0;
407*bbecb9d1SAndroid Build Coastguard Worker }
408*bbecb9d1SAndroid Build Coastguard Worker
409*bbecb9d1SAndroid Build Coastguard Worker static int
proxy_context_transfer_3d(struct virgl_context * base,struct virgl_resource * res,UNUSED const struct vrend_transfer_info * info,UNUSED int transfer_mode)410*bbecb9d1SAndroid Build Coastguard Worker proxy_context_transfer_3d(struct virgl_context *base,
411*bbecb9d1SAndroid Build Coastguard Worker struct virgl_resource *res,
412*bbecb9d1SAndroid Build Coastguard Worker UNUSED const struct vrend_transfer_info *info,
413*bbecb9d1SAndroid Build Coastguard Worker UNUSED int transfer_mode)
414*bbecb9d1SAndroid Build Coastguard Worker {
415*bbecb9d1SAndroid Build Coastguard Worker struct proxy_context *ctx = (struct proxy_context *)base;
416*bbecb9d1SAndroid Build Coastguard Worker
417*bbecb9d1SAndroid Build Coastguard Worker proxy_log("no transfer support for ctx %d and res %d", ctx->base.ctx_id, res->res_id);
418*bbecb9d1SAndroid Build Coastguard Worker return -1;
419*bbecb9d1SAndroid Build Coastguard Worker }
420*bbecb9d1SAndroid Build Coastguard Worker
421*bbecb9d1SAndroid Build Coastguard Worker static void
proxy_context_detach_resource(struct virgl_context * base,struct virgl_resource * res)422*bbecb9d1SAndroid Build Coastguard Worker proxy_context_detach_resource(struct virgl_context *base, struct virgl_resource *res)
423*bbecb9d1SAndroid Build Coastguard Worker {
424*bbecb9d1SAndroid Build Coastguard Worker struct proxy_context *ctx = (struct proxy_context *)base;
425*bbecb9d1SAndroid Build Coastguard Worker const uint32_t res_id = res->res_id;
426*bbecb9d1SAndroid Build Coastguard Worker
427*bbecb9d1SAndroid Build Coastguard Worker const struct render_context_op_destroy_resource_request req = {
428*bbecb9d1SAndroid Build Coastguard Worker .header.op = RENDER_CONTEXT_OP_DESTROY_RESOURCE,
429*bbecb9d1SAndroid Build Coastguard Worker .res_id = res_id,
430*bbecb9d1SAndroid Build Coastguard Worker };
431*bbecb9d1SAndroid Build Coastguard Worker if (!proxy_socket_send_request(&ctx->socket, &req, sizeof(req)))
432*bbecb9d1SAndroid Build Coastguard Worker proxy_log("failed to detach res %d", res_id);
433*bbecb9d1SAndroid Build Coastguard Worker
434*bbecb9d1SAndroid Build Coastguard Worker proxy_context_resource_remove(ctx, res_id);
435*bbecb9d1SAndroid Build Coastguard Worker }
436*bbecb9d1SAndroid Build Coastguard Worker
437*bbecb9d1SAndroid Build Coastguard Worker static void
proxy_context_attach_resource(struct virgl_context * base,struct virgl_resource * res)438*bbecb9d1SAndroid Build Coastguard Worker proxy_context_attach_resource(struct virgl_context *base, struct virgl_resource *res)
439*bbecb9d1SAndroid Build Coastguard Worker {
440*bbecb9d1SAndroid Build Coastguard Worker struct proxy_context *ctx = (struct proxy_context *)base;
441*bbecb9d1SAndroid Build Coastguard Worker const uint32_t res_id = res->res_id;
442*bbecb9d1SAndroid Build Coastguard Worker
443*bbecb9d1SAndroid Build Coastguard Worker /* avoid importing resources created from RENDER_CONTEXT_OP_CREATE_RESOURCE */
444*bbecb9d1SAndroid Build Coastguard Worker if (proxy_context_resource_find(ctx, res_id))
445*bbecb9d1SAndroid Build Coastguard Worker return;
446*bbecb9d1SAndroid Build Coastguard Worker
447*bbecb9d1SAndroid Build Coastguard Worker enum virgl_resource_fd_type res_fd_type = res->fd_type;
448*bbecb9d1SAndroid Build Coastguard Worker int res_fd = res->fd;
449*bbecb9d1SAndroid Build Coastguard Worker bool close_res_fd = false;
450*bbecb9d1SAndroid Build Coastguard Worker if (res_fd_type == VIRGL_RESOURCE_FD_INVALID) {
451*bbecb9d1SAndroid Build Coastguard Worker res_fd_type = virgl_resource_export_fd(res, &res_fd);
452*bbecb9d1SAndroid Build Coastguard Worker if (res_fd_type == VIRGL_RESOURCE_FD_INVALID) {
453*bbecb9d1SAndroid Build Coastguard Worker proxy_log("failed to export res %d", res_id);
454*bbecb9d1SAndroid Build Coastguard Worker return;
455*bbecb9d1SAndroid Build Coastguard Worker }
456*bbecb9d1SAndroid Build Coastguard Worker
457*bbecb9d1SAndroid Build Coastguard Worker close_res_fd = true;
458*bbecb9d1SAndroid Build Coastguard Worker }
459*bbecb9d1SAndroid Build Coastguard Worker
460*bbecb9d1SAndroid Build Coastguard Worker /* the proxy ignores iovs since transfer_3d is not supported */
461*bbecb9d1SAndroid Build Coastguard Worker const struct render_context_op_import_resource_request req = {
462*bbecb9d1SAndroid Build Coastguard Worker .header.op = RENDER_CONTEXT_OP_IMPORT_RESOURCE,
463*bbecb9d1SAndroid Build Coastguard Worker .res_id = res_id,
464*bbecb9d1SAndroid Build Coastguard Worker .fd_type = res_fd_type,
465*bbecb9d1SAndroid Build Coastguard Worker .size = virgl_resource_get_size(res),
466*bbecb9d1SAndroid Build Coastguard Worker };
467*bbecb9d1SAndroid Build Coastguard Worker if (!proxy_socket_send_request_with_fds(&ctx->socket, &req, sizeof(req), &res_fd, 1))
468*bbecb9d1SAndroid Build Coastguard Worker proxy_log("failed to attach res %d", res_id);
469*bbecb9d1SAndroid Build Coastguard Worker
470*bbecb9d1SAndroid Build Coastguard Worker if (res_fd >= 0 && close_res_fd)
471*bbecb9d1SAndroid Build Coastguard Worker close(res_fd);
472*bbecb9d1SAndroid Build Coastguard Worker
473*bbecb9d1SAndroid Build Coastguard Worker proxy_context_resource_add(ctx, res_id);
474*bbecb9d1SAndroid Build Coastguard Worker }
475*bbecb9d1SAndroid Build Coastguard Worker
476*bbecb9d1SAndroid Build Coastguard Worker static void
proxy_context_destroy(struct virgl_context * base)477*bbecb9d1SAndroid Build Coastguard Worker proxy_context_destroy(struct virgl_context *base)
478*bbecb9d1SAndroid Build Coastguard Worker {
479*bbecb9d1SAndroid Build Coastguard Worker struct proxy_context *ctx = (struct proxy_context *)base;
480*bbecb9d1SAndroid Build Coastguard Worker
481*bbecb9d1SAndroid Build Coastguard Worker /* ask the server process to terminate the context process */
482*bbecb9d1SAndroid Build Coastguard Worker if (!proxy_client_destroy_context(ctx->client, ctx->base.ctx_id))
483*bbecb9d1SAndroid Build Coastguard Worker proxy_log("failed to destroy ctx %d", ctx->base.ctx_id);
484*bbecb9d1SAndroid Build Coastguard Worker
485*bbecb9d1SAndroid Build Coastguard Worker if (ctx->sync_thread.fence_eventfd >= 0) {
486*bbecb9d1SAndroid Build Coastguard Worker if (ctx->sync_thread.created) {
487*bbecb9d1SAndroid Build Coastguard Worker ctx->sync_thread.stop = true;
488*bbecb9d1SAndroid Build Coastguard Worker write_eventfd(ctx->sync_thread.fence_eventfd, 1);
489*bbecb9d1SAndroid Build Coastguard Worker thrd_join(ctx->sync_thread.thread, NULL);
490*bbecb9d1SAndroid Build Coastguard Worker }
491*bbecb9d1SAndroid Build Coastguard Worker
492*bbecb9d1SAndroid Build Coastguard Worker close(ctx->sync_thread.fence_eventfd);
493*bbecb9d1SAndroid Build Coastguard Worker }
494*bbecb9d1SAndroid Build Coastguard Worker
495*bbecb9d1SAndroid Build Coastguard Worker if (ctx->shmem.ptr)
496*bbecb9d1SAndroid Build Coastguard Worker munmap(ctx->shmem.ptr, ctx->shmem.size);
497*bbecb9d1SAndroid Build Coastguard Worker if (ctx->shmem.fd >= 0)
498*bbecb9d1SAndroid Build Coastguard Worker close(ctx->shmem.fd);
499*bbecb9d1SAndroid Build Coastguard Worker
500*bbecb9d1SAndroid Build Coastguard Worker if (ctx->timeline_seqnos) {
501*bbecb9d1SAndroid Build Coastguard Worker for (uint32_t i = 0; i < PROXY_CONTEXT_TIMELINE_COUNT; i++) {
502*bbecb9d1SAndroid Build Coastguard Worker struct proxy_timeline *timeline = &ctx->timelines[i];
503*bbecb9d1SAndroid Build Coastguard Worker list_for_each_entry_safe (struct proxy_fence, fence, &timeline->fences, head)
504*bbecb9d1SAndroid Build Coastguard Worker free(fence);
505*bbecb9d1SAndroid Build Coastguard Worker }
506*bbecb9d1SAndroid Build Coastguard Worker }
507*bbecb9d1SAndroid Build Coastguard Worker mtx_destroy(&ctx->timeline_mutex);
508*bbecb9d1SAndroid Build Coastguard Worker
509*bbecb9d1SAndroid Build Coastguard Worker list_for_each_entry_safe (struct proxy_fence, fence, &ctx->free_fences, head)
510*bbecb9d1SAndroid Build Coastguard Worker free(fence);
511*bbecb9d1SAndroid Build Coastguard Worker mtx_destroy(&ctx->free_fences_mutex);
512*bbecb9d1SAndroid Build Coastguard Worker
513*bbecb9d1SAndroid Build Coastguard Worker proxy_context_resource_table_fini(ctx);
514*bbecb9d1SAndroid Build Coastguard Worker
515*bbecb9d1SAndroid Build Coastguard Worker proxy_socket_fini(&ctx->socket);
516*bbecb9d1SAndroid Build Coastguard Worker
517*bbecb9d1SAndroid Build Coastguard Worker free(ctx);
518*bbecb9d1SAndroid Build Coastguard Worker }
519*bbecb9d1SAndroid Build Coastguard Worker
520*bbecb9d1SAndroid Build Coastguard Worker static void
proxy_context_init_base(struct proxy_context * ctx)521*bbecb9d1SAndroid Build Coastguard Worker proxy_context_init_base(struct proxy_context *ctx)
522*bbecb9d1SAndroid Build Coastguard Worker {
523*bbecb9d1SAndroid Build Coastguard Worker ctx->base.destroy = proxy_context_destroy;
524*bbecb9d1SAndroid Build Coastguard Worker ctx->base.attach_resource = proxy_context_attach_resource;
525*bbecb9d1SAndroid Build Coastguard Worker ctx->base.detach_resource = proxy_context_detach_resource;
526*bbecb9d1SAndroid Build Coastguard Worker ctx->base.transfer_3d = proxy_context_transfer_3d;
527*bbecb9d1SAndroid Build Coastguard Worker ctx->base.get_blob = proxy_context_get_blob;
528*bbecb9d1SAndroid Build Coastguard Worker ctx->base.submit_cmd = proxy_context_submit_cmd;
529*bbecb9d1SAndroid Build Coastguard Worker
530*bbecb9d1SAndroid Build Coastguard Worker ctx->base.get_fencing_fd = proxy_context_get_fencing_fd;
531*bbecb9d1SAndroid Build Coastguard Worker ctx->base.retire_fences = proxy_context_retire_fences;
532*bbecb9d1SAndroid Build Coastguard Worker ctx->base.submit_fence = proxy_context_submit_fence;
533*bbecb9d1SAndroid Build Coastguard Worker }
534*bbecb9d1SAndroid Build Coastguard Worker
535*bbecb9d1SAndroid Build Coastguard Worker static bool
proxy_context_init_fencing(struct proxy_context * ctx)536*bbecb9d1SAndroid Build Coastguard Worker proxy_context_init_fencing(struct proxy_context *ctx)
537*bbecb9d1SAndroid Build Coastguard Worker {
538*bbecb9d1SAndroid Build Coastguard Worker /* The render server updates the shmem for the current seqnos and
539*bbecb9d1SAndroid Build Coastguard Worker * optionally notifies using the eventfd. That means, when only
540*bbecb9d1SAndroid Build Coastguard Worker * VIRGL_RENDERER_THREAD_SYNC is set, we just need to set up the eventfd.
541*bbecb9d1SAndroid Build Coastguard Worker * When VIRGL_RENDERER_ASYNC_FENCE_CB is also set, we need to create a sync
542*bbecb9d1SAndroid Build Coastguard Worker * thread as well.
543*bbecb9d1SAndroid Build Coastguard Worker *
544*bbecb9d1SAndroid Build Coastguard Worker * Fence polling can always check the shmem directly.
545*bbecb9d1SAndroid Build Coastguard Worker */
546*bbecb9d1SAndroid Build Coastguard Worker if (!(proxy_renderer.flags & VIRGL_RENDERER_THREAD_SYNC))
547*bbecb9d1SAndroid Build Coastguard Worker return true;
548*bbecb9d1SAndroid Build Coastguard Worker
549*bbecb9d1SAndroid Build Coastguard Worker ctx->sync_thread.fence_eventfd = create_eventfd(0);
550*bbecb9d1SAndroid Build Coastguard Worker if (ctx->sync_thread.fence_eventfd < 0) {
551*bbecb9d1SAndroid Build Coastguard Worker proxy_log("failed to create fence eventfd");
552*bbecb9d1SAndroid Build Coastguard Worker return false;
553*bbecb9d1SAndroid Build Coastguard Worker }
554*bbecb9d1SAndroid Build Coastguard Worker
555*bbecb9d1SAndroid Build Coastguard Worker if (proxy_renderer.flags & VIRGL_RENDERER_ASYNC_FENCE_CB) {
556*bbecb9d1SAndroid Build Coastguard Worker int ret = thrd_create(&ctx->sync_thread.thread, proxy_context_sync_thread, ctx);
557*bbecb9d1SAndroid Build Coastguard Worker if (ret != thrd_success) {
558*bbecb9d1SAndroid Build Coastguard Worker proxy_log("failed to create sync thread");
559*bbecb9d1SAndroid Build Coastguard Worker return false;
560*bbecb9d1SAndroid Build Coastguard Worker }
561*bbecb9d1SAndroid Build Coastguard Worker ctx->sync_thread.created = true;
562*bbecb9d1SAndroid Build Coastguard Worker }
563*bbecb9d1SAndroid Build Coastguard Worker
564*bbecb9d1SAndroid Build Coastguard Worker return true;
565*bbecb9d1SAndroid Build Coastguard Worker }
566*bbecb9d1SAndroid Build Coastguard Worker
567*bbecb9d1SAndroid Build Coastguard Worker static bool
proxy_context_init_timelines(struct proxy_context * ctx)568*bbecb9d1SAndroid Build Coastguard Worker proxy_context_init_timelines(struct proxy_context *ctx)
569*bbecb9d1SAndroid Build Coastguard Worker {
570*bbecb9d1SAndroid Build Coastguard Worker atomic_uint *timeline_seqnos = ctx->shmem.ptr;
571*bbecb9d1SAndroid Build Coastguard Worker for (uint32_t i = 0; i < ARRAY_SIZE(ctx->timelines); i++) {
572*bbecb9d1SAndroid Build Coastguard Worker atomic_init(&timeline_seqnos[i], 0);
573*bbecb9d1SAndroid Build Coastguard Worker
574*bbecb9d1SAndroid Build Coastguard Worker struct proxy_timeline *timeline = &ctx->timelines[i];
575*bbecb9d1SAndroid Build Coastguard Worker timeline->cur_seqno = 0;
576*bbecb9d1SAndroid Build Coastguard Worker timeline->next_seqno = 1;
577*bbecb9d1SAndroid Build Coastguard Worker list_inithead(&timeline->fences);
578*bbecb9d1SAndroid Build Coastguard Worker }
579*bbecb9d1SAndroid Build Coastguard Worker
580*bbecb9d1SAndroid Build Coastguard Worker ctx->timeline_seqnos = timeline_seqnos;
581*bbecb9d1SAndroid Build Coastguard Worker
582*bbecb9d1SAndroid Build Coastguard Worker return true;
583*bbecb9d1SAndroid Build Coastguard Worker }
584*bbecb9d1SAndroid Build Coastguard Worker
585*bbecb9d1SAndroid Build Coastguard Worker static int
alloc_memfd(const char * name,size_t size,void ** out_ptr)586*bbecb9d1SAndroid Build Coastguard Worker alloc_memfd(const char *name, size_t size, void **out_ptr)
587*bbecb9d1SAndroid Build Coastguard Worker {
588*bbecb9d1SAndroid Build Coastguard Worker int fd = os_create_anonymous_file(size, name);
589*bbecb9d1SAndroid Build Coastguard Worker if (fd < 0)
590*bbecb9d1SAndroid Build Coastguard Worker return -1;
591*bbecb9d1SAndroid Build Coastguard Worker
592*bbecb9d1SAndroid Build Coastguard Worker int ret = add_required_seals_to_fd(fd);
593*bbecb9d1SAndroid Build Coastguard Worker if (ret)
594*bbecb9d1SAndroid Build Coastguard Worker goto fail;
595*bbecb9d1SAndroid Build Coastguard Worker
596*bbecb9d1SAndroid Build Coastguard Worker if (!out_ptr)
597*bbecb9d1SAndroid Build Coastguard Worker return fd;
598*bbecb9d1SAndroid Build Coastguard Worker
599*bbecb9d1SAndroid Build Coastguard Worker void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
600*bbecb9d1SAndroid Build Coastguard Worker if (ptr == MAP_FAILED)
601*bbecb9d1SAndroid Build Coastguard Worker goto fail;
602*bbecb9d1SAndroid Build Coastguard Worker
603*bbecb9d1SAndroid Build Coastguard Worker *out_ptr = ptr;
604*bbecb9d1SAndroid Build Coastguard Worker return fd;
605*bbecb9d1SAndroid Build Coastguard Worker
606*bbecb9d1SAndroid Build Coastguard Worker fail:
607*bbecb9d1SAndroid Build Coastguard Worker close(fd);
608*bbecb9d1SAndroid Build Coastguard Worker return -1;
609*bbecb9d1SAndroid Build Coastguard Worker }
610*bbecb9d1SAndroid Build Coastguard Worker
611*bbecb9d1SAndroid Build Coastguard Worker static bool
proxy_context_init_shmem(struct proxy_context * ctx)612*bbecb9d1SAndroid Build Coastguard Worker proxy_context_init_shmem(struct proxy_context *ctx)
613*bbecb9d1SAndroid Build Coastguard Worker {
614*bbecb9d1SAndroid Build Coastguard Worker const size_t shmem_size = sizeof(*ctx->timeline_seqnos) * PROXY_CONTEXT_TIMELINE_COUNT;
615*bbecb9d1SAndroid Build Coastguard Worker ctx->shmem.fd = alloc_memfd("proxy-ctx", shmem_size, &ctx->shmem.ptr);
616*bbecb9d1SAndroid Build Coastguard Worker if (ctx->shmem.fd < 0)
617*bbecb9d1SAndroid Build Coastguard Worker return false;
618*bbecb9d1SAndroid Build Coastguard Worker
619*bbecb9d1SAndroid Build Coastguard Worker ctx->shmem.size = shmem_size;
620*bbecb9d1SAndroid Build Coastguard Worker
621*bbecb9d1SAndroid Build Coastguard Worker return true;
622*bbecb9d1SAndroid Build Coastguard Worker }
623*bbecb9d1SAndroid Build Coastguard Worker
624*bbecb9d1SAndroid Build Coastguard Worker static bool
proxy_context_init(struct proxy_context * ctx,uint32_t ctx_flags)625*bbecb9d1SAndroid Build Coastguard Worker proxy_context_init(struct proxy_context *ctx, uint32_t ctx_flags)
626*bbecb9d1SAndroid Build Coastguard Worker {
627*bbecb9d1SAndroid Build Coastguard Worker if (!proxy_context_init_shmem(ctx) || !proxy_context_init_timelines(ctx) ||
628*bbecb9d1SAndroid Build Coastguard Worker !proxy_context_init_fencing(ctx) || !proxy_context_resource_table_init(ctx))
629*bbecb9d1SAndroid Build Coastguard Worker return false;
630*bbecb9d1SAndroid Build Coastguard Worker
631*bbecb9d1SAndroid Build Coastguard Worker const struct render_context_op_init_request req = {
632*bbecb9d1SAndroid Build Coastguard Worker .header.op = RENDER_CONTEXT_OP_INIT,
633*bbecb9d1SAndroid Build Coastguard Worker .flags = ctx_flags,
634*bbecb9d1SAndroid Build Coastguard Worker .shmem_size = ctx->shmem.size,
635*bbecb9d1SAndroid Build Coastguard Worker };
636*bbecb9d1SAndroid Build Coastguard Worker const int req_fds[2] = { ctx->shmem.fd, ctx->sync_thread.fence_eventfd };
637*bbecb9d1SAndroid Build Coastguard Worker const int req_fd_count = req_fds[1] >= 0 ? 2 : 1;
638*bbecb9d1SAndroid Build Coastguard Worker if (!proxy_socket_send_request_with_fds(&ctx->socket, &req, sizeof(req), req_fds,
639*bbecb9d1SAndroid Build Coastguard Worker req_fd_count)) {
640*bbecb9d1SAndroid Build Coastguard Worker proxy_log("failed to initialize context");
641*bbecb9d1SAndroid Build Coastguard Worker return false;
642*bbecb9d1SAndroid Build Coastguard Worker }
643*bbecb9d1SAndroid Build Coastguard Worker
644*bbecb9d1SAndroid Build Coastguard Worker return true;
645*bbecb9d1SAndroid Build Coastguard Worker }
646*bbecb9d1SAndroid Build Coastguard Worker
647*bbecb9d1SAndroid Build Coastguard Worker struct virgl_context *
proxy_context_create(uint32_t ctx_id,uint32_t ctx_flags,size_t debug_len,const char * debug_name)648*bbecb9d1SAndroid Build Coastguard Worker proxy_context_create(uint32_t ctx_id,
649*bbecb9d1SAndroid Build Coastguard Worker uint32_t ctx_flags,
650*bbecb9d1SAndroid Build Coastguard Worker size_t debug_len,
651*bbecb9d1SAndroid Build Coastguard Worker const char *debug_name)
652*bbecb9d1SAndroid Build Coastguard Worker {
653*bbecb9d1SAndroid Build Coastguard Worker struct proxy_client *client = proxy_renderer.client;
654*bbecb9d1SAndroid Build Coastguard Worker struct proxy_context *ctx;
655*bbecb9d1SAndroid Build Coastguard Worker
656*bbecb9d1SAndroid Build Coastguard Worker int ctx_fd;
657*bbecb9d1SAndroid Build Coastguard Worker if (!proxy_client_create_context(client, ctx_id, debug_len, debug_name, &ctx_fd)) {
658*bbecb9d1SAndroid Build Coastguard Worker proxy_log("failed to create a context");
659*bbecb9d1SAndroid Build Coastguard Worker return NULL;
660*bbecb9d1SAndroid Build Coastguard Worker }
661*bbecb9d1SAndroid Build Coastguard Worker
662*bbecb9d1SAndroid Build Coastguard Worker ctx = calloc(1, sizeof(*ctx));
663*bbecb9d1SAndroid Build Coastguard Worker if (!ctx) {
664*bbecb9d1SAndroid Build Coastguard Worker close(ctx_fd);
665*bbecb9d1SAndroid Build Coastguard Worker return NULL;
666*bbecb9d1SAndroid Build Coastguard Worker }
667*bbecb9d1SAndroid Build Coastguard Worker
668*bbecb9d1SAndroid Build Coastguard Worker proxy_context_init_base(ctx);
669*bbecb9d1SAndroid Build Coastguard Worker ctx->client = client;
670*bbecb9d1SAndroid Build Coastguard Worker proxy_socket_init(&ctx->socket, ctx_fd);
671*bbecb9d1SAndroid Build Coastguard Worker ctx->shmem.fd = -1;
672*bbecb9d1SAndroid Build Coastguard Worker mtx_init(&ctx->timeline_mutex, mtx_plain);
673*bbecb9d1SAndroid Build Coastguard Worker mtx_init(&ctx->free_fences_mutex, mtx_plain);
674*bbecb9d1SAndroid Build Coastguard Worker list_inithead(&ctx->free_fences);
675*bbecb9d1SAndroid Build Coastguard Worker ctx->sync_thread.fence_eventfd = -1;
676*bbecb9d1SAndroid Build Coastguard Worker
677*bbecb9d1SAndroid Build Coastguard Worker if (!proxy_context_init(ctx, ctx_flags)) {
678*bbecb9d1SAndroid Build Coastguard Worker proxy_context_destroy(&ctx->base);
679*bbecb9d1SAndroid Build Coastguard Worker return NULL;
680*bbecb9d1SAndroid Build Coastguard Worker }
681*bbecb9d1SAndroid Build Coastguard Worker
682*bbecb9d1SAndroid Build Coastguard Worker return &ctx->base;
683*bbecb9d1SAndroid Build Coastguard Worker }
684