xref: /aosp_15_r20/external/virglrenderer/server/render_client.c (revision bbecb9d118dfdb95f99bd754f8fa9be01f189df3)
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 "render_client.h"
7*bbecb9d1SAndroid Build Coastguard Worker 
8*bbecb9d1SAndroid Build Coastguard Worker #include <unistd.h>
9*bbecb9d1SAndroid Build Coastguard Worker #include <vulkan/vulkan.h>
10*bbecb9d1SAndroid Build Coastguard Worker 
11*bbecb9d1SAndroid Build Coastguard Worker #include "render_context.h"
12*bbecb9d1SAndroid Build Coastguard Worker #include "render_server.h"
13*bbecb9d1SAndroid Build Coastguard Worker #include "render_virgl.h"
14*bbecb9d1SAndroid Build Coastguard Worker #include "render_worker.h"
15*bbecb9d1SAndroid Build Coastguard Worker 
16*bbecb9d1SAndroid Build Coastguard Worker /* There is a render_context_record for each worker.
17*bbecb9d1SAndroid Build Coastguard Worker  *
18*bbecb9d1SAndroid Build Coastguard Worker  * When the client process destroys a context, it closes the connection to the
19*bbecb9d1SAndroid Build Coastguard Worker  * worker, which leads to worker termination.  It also sends a
20*bbecb9d1SAndroid Build Coastguard Worker  * RENDER_CLIENT_OP_DESTROY_CONTEXT to us to remove the record.  Because we
21*bbecb9d1SAndroid Build Coastguard Worker  * are responsible for cleaning up the worker, we don't care if the worker has
22*bbecb9d1SAndroid Build Coastguard Worker  * terminated or not.  We always kill, reap, and remove the record.
23*bbecb9d1SAndroid Build Coastguard Worker  */
24*bbecb9d1SAndroid Build Coastguard Worker struct render_context_record {
25*bbecb9d1SAndroid Build Coastguard Worker    uint32_t ctx_id;
26*bbecb9d1SAndroid Build Coastguard Worker    struct render_worker *worker;
27*bbecb9d1SAndroid Build Coastguard Worker 
28*bbecb9d1SAndroid Build Coastguard Worker    struct list_head head;
29*bbecb9d1SAndroid Build Coastguard Worker };
30*bbecb9d1SAndroid Build Coastguard Worker 
31*bbecb9d1SAndroid Build Coastguard Worker static struct render_context_record *
render_client_find_record(struct render_client * client,uint32_t ctx_id)32*bbecb9d1SAndroid Build Coastguard Worker render_client_find_record(struct render_client *client, uint32_t ctx_id)
33*bbecb9d1SAndroid Build Coastguard Worker {
34*bbecb9d1SAndroid Build Coastguard Worker    list_for_each_entry (struct render_context_record, rec, &client->context_records,
35*bbecb9d1SAndroid Build Coastguard Worker                         head) {
36*bbecb9d1SAndroid Build Coastguard Worker       if (rec->ctx_id == ctx_id)
37*bbecb9d1SAndroid Build Coastguard Worker          return rec;
38*bbecb9d1SAndroid Build Coastguard Worker    }
39*bbecb9d1SAndroid Build Coastguard Worker    return NULL;
40*bbecb9d1SAndroid Build Coastguard Worker }
41*bbecb9d1SAndroid Build Coastguard Worker 
42*bbecb9d1SAndroid Build Coastguard Worker static void
render_client_detach_all_records(struct render_client * client)43*bbecb9d1SAndroid Build Coastguard Worker render_client_detach_all_records(struct render_client *client)
44*bbecb9d1SAndroid Build Coastguard Worker {
45*bbecb9d1SAndroid Build Coastguard Worker    struct render_server *srv = client->server;
46*bbecb9d1SAndroid Build Coastguard Worker 
47*bbecb9d1SAndroid Build Coastguard Worker    /* free all render_workers without killing nor reaping */
48*bbecb9d1SAndroid Build Coastguard Worker    render_worker_jail_detach_workers(srv->worker_jail);
49*bbecb9d1SAndroid Build Coastguard Worker 
50*bbecb9d1SAndroid Build Coastguard Worker    list_for_each_entry_safe (struct render_context_record, rec, &client->context_records,
51*bbecb9d1SAndroid Build Coastguard Worker                              head)
52*bbecb9d1SAndroid Build Coastguard Worker       free(rec);
53*bbecb9d1SAndroid Build Coastguard Worker    list_inithead(&client->context_records);
54*bbecb9d1SAndroid Build Coastguard Worker }
55*bbecb9d1SAndroid Build Coastguard Worker 
56*bbecb9d1SAndroid Build Coastguard Worker static void
render_client_remove_record(struct render_client * client,struct render_context_record * rec)57*bbecb9d1SAndroid Build Coastguard Worker render_client_remove_record(struct render_client *client,
58*bbecb9d1SAndroid Build Coastguard Worker                             struct render_context_record *rec)
59*bbecb9d1SAndroid Build Coastguard Worker {
60*bbecb9d1SAndroid Build Coastguard Worker    struct render_server *srv = client->server;
61*bbecb9d1SAndroid Build Coastguard Worker 
62*bbecb9d1SAndroid Build Coastguard Worker    render_worker_destroy(srv->worker_jail, rec->worker);
63*bbecb9d1SAndroid Build Coastguard Worker 
64*bbecb9d1SAndroid Build Coastguard Worker    list_del(&rec->head);
65*bbecb9d1SAndroid Build Coastguard Worker    free(rec);
66*bbecb9d1SAndroid Build Coastguard Worker }
67*bbecb9d1SAndroid Build Coastguard Worker 
68*bbecb9d1SAndroid Build Coastguard Worker static void
render_client_clear_records(struct render_client * client)69*bbecb9d1SAndroid Build Coastguard Worker render_client_clear_records(struct render_client *client)
70*bbecb9d1SAndroid Build Coastguard Worker {
71*bbecb9d1SAndroid Build Coastguard Worker    list_for_each_entry_safe (struct render_context_record, rec, &client->context_records,
72*bbecb9d1SAndroid Build Coastguard Worker                              head)
73*bbecb9d1SAndroid Build Coastguard Worker       render_client_remove_record(client, rec);
74*bbecb9d1SAndroid Build Coastguard Worker }
75*bbecb9d1SAndroid Build Coastguard Worker 
76*bbecb9d1SAndroid Build Coastguard Worker static void
init_context_args(struct render_context_args * ctx_args,uint32_t init_flags,const struct render_client_op_create_context_request * req,int ctx_fd)77*bbecb9d1SAndroid Build Coastguard Worker init_context_args(struct render_context_args *ctx_args,
78*bbecb9d1SAndroid Build Coastguard Worker                   uint32_t init_flags,
79*bbecb9d1SAndroid Build Coastguard Worker                   const struct render_client_op_create_context_request *req,
80*bbecb9d1SAndroid Build Coastguard Worker                   int ctx_fd)
81*bbecb9d1SAndroid Build Coastguard Worker {
82*bbecb9d1SAndroid Build Coastguard Worker    *ctx_args = (struct render_context_args){
83*bbecb9d1SAndroid Build Coastguard Worker       .valid = true,
84*bbecb9d1SAndroid Build Coastguard Worker       .init_flags = init_flags,
85*bbecb9d1SAndroid Build Coastguard Worker       .ctx_id = req->ctx_id,
86*bbecb9d1SAndroid Build Coastguard Worker       .ctx_fd = ctx_fd,
87*bbecb9d1SAndroid Build Coastguard Worker    };
88*bbecb9d1SAndroid Build Coastguard Worker 
89*bbecb9d1SAndroid Build Coastguard Worker    static_assert(sizeof(ctx_args->ctx_name) == sizeof(req->ctx_name), "");
90*bbecb9d1SAndroid Build Coastguard Worker    memcpy(ctx_args->ctx_name, req->ctx_name, sizeof(req->ctx_name) - 1);
91*bbecb9d1SAndroid Build Coastguard Worker }
92*bbecb9d1SAndroid Build Coastguard Worker 
93*bbecb9d1SAndroid Build Coastguard Worker #ifdef ENABLE_RENDER_SERVER_WORKER_THREAD
94*bbecb9d1SAndroid Build Coastguard Worker 
95*bbecb9d1SAndroid Build Coastguard Worker static int
render_client_worker_thread(void * thread_data)96*bbecb9d1SAndroid Build Coastguard Worker render_client_worker_thread(void *thread_data)
97*bbecb9d1SAndroid Build Coastguard Worker {
98*bbecb9d1SAndroid Build Coastguard Worker    const struct render_context_args *ctx_args = thread_data;
99*bbecb9d1SAndroid Build Coastguard Worker    return render_context_main(ctx_args) ? 0 : -1;
100*bbecb9d1SAndroid Build Coastguard Worker }
101*bbecb9d1SAndroid Build Coastguard Worker 
102*bbecb9d1SAndroid Build Coastguard Worker #endif /* ENABLE_RENDER_SERVER_WORKER_THREAD */
103*bbecb9d1SAndroid Build Coastguard Worker 
104*bbecb9d1SAndroid Build Coastguard Worker static bool
render_client_create_context(struct render_client * client,const struct render_client_op_create_context_request * req,int * out_remote_fd)105*bbecb9d1SAndroid Build Coastguard Worker render_client_create_context(struct render_client *client,
106*bbecb9d1SAndroid Build Coastguard Worker                              const struct render_client_op_create_context_request *req,
107*bbecb9d1SAndroid Build Coastguard Worker                              int *out_remote_fd)
108*bbecb9d1SAndroid Build Coastguard Worker {
109*bbecb9d1SAndroid Build Coastguard Worker    struct render_server *srv = client->server;
110*bbecb9d1SAndroid Build Coastguard Worker 
111*bbecb9d1SAndroid Build Coastguard Worker    struct render_context_record *rec = calloc(1, sizeof(*rec));
112*bbecb9d1SAndroid Build Coastguard Worker    if (!rec)
113*bbecb9d1SAndroid Build Coastguard Worker       return false;
114*bbecb9d1SAndroid Build Coastguard Worker 
115*bbecb9d1SAndroid Build Coastguard Worker    int socket_fds[2];
116*bbecb9d1SAndroid Build Coastguard Worker    if (!render_socket_pair(socket_fds)) {
117*bbecb9d1SAndroid Build Coastguard Worker       free(rec);
118*bbecb9d1SAndroid Build Coastguard Worker       return false;
119*bbecb9d1SAndroid Build Coastguard Worker    }
120*bbecb9d1SAndroid Build Coastguard Worker    int ctx_fd = socket_fds[0];
121*bbecb9d1SAndroid Build Coastguard Worker    int remote_fd = socket_fds[1];
122*bbecb9d1SAndroid Build Coastguard Worker 
123*bbecb9d1SAndroid Build Coastguard Worker    struct render_context_args ctx_args;
124*bbecb9d1SAndroid Build Coastguard Worker    init_context_args(&ctx_args, client->init_flags, req, ctx_fd);
125*bbecb9d1SAndroid Build Coastguard Worker 
126*bbecb9d1SAndroid Build Coastguard Worker #ifdef ENABLE_RENDER_SERVER_WORKER_THREAD
127*bbecb9d1SAndroid Build Coastguard Worker    rec->worker = render_worker_create(srv->worker_jail, render_client_worker_thread,
128*bbecb9d1SAndroid Build Coastguard Worker                                       &ctx_args, sizeof(ctx_args));
129*bbecb9d1SAndroid Build Coastguard Worker    if (rec->worker)
130*bbecb9d1SAndroid Build Coastguard Worker       ctx_fd = -1; /* ownership transferred */
131*bbecb9d1SAndroid Build Coastguard Worker #else
132*bbecb9d1SAndroid Build Coastguard Worker    rec->worker = render_worker_create(srv->worker_jail, NULL, NULL, 0);
133*bbecb9d1SAndroid Build Coastguard Worker #endif
134*bbecb9d1SAndroid Build Coastguard Worker    if (!rec->worker) {
135*bbecb9d1SAndroid Build Coastguard Worker       render_log("failed to create a context worker");
136*bbecb9d1SAndroid Build Coastguard Worker       close(ctx_fd);
137*bbecb9d1SAndroid Build Coastguard Worker       close(remote_fd);
138*bbecb9d1SAndroid Build Coastguard Worker       free(rec);
139*bbecb9d1SAndroid Build Coastguard Worker       return false;
140*bbecb9d1SAndroid Build Coastguard Worker    }
141*bbecb9d1SAndroid Build Coastguard Worker 
142*bbecb9d1SAndroid Build Coastguard Worker    rec->ctx_id = req->ctx_id;
143*bbecb9d1SAndroid Build Coastguard Worker    list_addtail(&rec->head, &client->context_records);
144*bbecb9d1SAndroid Build Coastguard Worker 
145*bbecb9d1SAndroid Build Coastguard Worker    if (!render_worker_is_record(rec->worker)) {
146*bbecb9d1SAndroid Build Coastguard Worker       /* this is the child process */
147*bbecb9d1SAndroid Build Coastguard Worker       srv->state = RENDER_SERVER_STATE_SUBPROCESS;
148*bbecb9d1SAndroid Build Coastguard Worker       *srv->context_args = ctx_args;
149*bbecb9d1SAndroid Build Coastguard Worker 
150*bbecb9d1SAndroid Build Coastguard Worker       render_client_detach_all_records(client);
151*bbecb9d1SAndroid Build Coastguard Worker 
152*bbecb9d1SAndroid Build Coastguard Worker       /* ctx_fd ownership transferred */
153*bbecb9d1SAndroid Build Coastguard Worker       assert(srv->context_args->ctx_fd == ctx_fd);
154*bbecb9d1SAndroid Build Coastguard Worker 
155*bbecb9d1SAndroid Build Coastguard Worker       close(remote_fd);
156*bbecb9d1SAndroid Build Coastguard Worker       *out_remote_fd = -1;
157*bbecb9d1SAndroid Build Coastguard Worker 
158*bbecb9d1SAndroid Build Coastguard Worker       return true;
159*bbecb9d1SAndroid Build Coastguard Worker    }
160*bbecb9d1SAndroid Build Coastguard Worker 
161*bbecb9d1SAndroid Build Coastguard Worker    /* this is the parent process */
162*bbecb9d1SAndroid Build Coastguard Worker    if (ctx_fd >= 0)
163*bbecb9d1SAndroid Build Coastguard Worker       close(ctx_fd);
164*bbecb9d1SAndroid Build Coastguard Worker    *out_remote_fd = remote_fd;
165*bbecb9d1SAndroid Build Coastguard Worker 
166*bbecb9d1SAndroid Build Coastguard Worker    return true;
167*bbecb9d1SAndroid Build Coastguard Worker }
168*bbecb9d1SAndroid Build Coastguard Worker 
169*bbecb9d1SAndroid Build Coastguard Worker static bool
render_client_dispatch_destroy_context(struct render_client * client,const union render_client_op_request * req)170*bbecb9d1SAndroid Build Coastguard Worker render_client_dispatch_destroy_context(struct render_client *client,
171*bbecb9d1SAndroid Build Coastguard Worker                                        const union render_client_op_request *req)
172*bbecb9d1SAndroid Build Coastguard Worker {
173*bbecb9d1SAndroid Build Coastguard Worker    const uint32_t ctx_id = req->destroy_context.ctx_id;
174*bbecb9d1SAndroid Build Coastguard Worker    struct render_context_record *rec = render_client_find_record(client, ctx_id);
175*bbecb9d1SAndroid Build Coastguard Worker    if (rec)
176*bbecb9d1SAndroid Build Coastguard Worker       render_client_remove_record(client, rec);
177*bbecb9d1SAndroid Build Coastguard Worker 
178*bbecb9d1SAndroid Build Coastguard Worker    return true;
179*bbecb9d1SAndroid Build Coastguard Worker }
180*bbecb9d1SAndroid Build Coastguard Worker 
181*bbecb9d1SAndroid Build Coastguard Worker static bool
render_client_dispatch_create_context(struct render_client * client,const union render_client_op_request * req)182*bbecb9d1SAndroid Build Coastguard Worker render_client_dispatch_create_context(struct render_client *client,
183*bbecb9d1SAndroid Build Coastguard Worker                                       const union render_client_op_request *req)
184*bbecb9d1SAndroid Build Coastguard Worker {
185*bbecb9d1SAndroid Build Coastguard Worker    struct render_server *srv = client->server;
186*bbecb9d1SAndroid Build Coastguard Worker 
187*bbecb9d1SAndroid Build Coastguard Worker    int remote_fd;
188*bbecb9d1SAndroid Build Coastguard Worker    bool ok = render_client_create_context(client, &req->create_context, &remote_fd);
189*bbecb9d1SAndroid Build Coastguard Worker    if (!ok)
190*bbecb9d1SAndroid Build Coastguard Worker       return false;
191*bbecb9d1SAndroid Build Coastguard Worker 
192*bbecb9d1SAndroid Build Coastguard Worker    if (srv->state == RENDER_SERVER_STATE_SUBPROCESS) {
193*bbecb9d1SAndroid Build Coastguard Worker       assert(remote_fd < 0);
194*bbecb9d1SAndroid Build Coastguard Worker       return true;
195*bbecb9d1SAndroid Build Coastguard Worker    }
196*bbecb9d1SAndroid Build Coastguard Worker 
197*bbecb9d1SAndroid Build Coastguard Worker    const struct render_client_op_create_context_reply reply = {
198*bbecb9d1SAndroid Build Coastguard Worker       .ok = ok,
199*bbecb9d1SAndroid Build Coastguard Worker    };
200*bbecb9d1SAndroid Build Coastguard Worker    if (!ok)
201*bbecb9d1SAndroid Build Coastguard Worker       return render_socket_send_reply(&client->socket, &reply, sizeof(reply));
202*bbecb9d1SAndroid Build Coastguard Worker 
203*bbecb9d1SAndroid Build Coastguard Worker    ok = render_socket_send_reply_with_fds(&client->socket, &reply, sizeof(reply),
204*bbecb9d1SAndroid Build Coastguard Worker                                           &remote_fd, 1);
205*bbecb9d1SAndroid Build Coastguard Worker    close(remote_fd);
206*bbecb9d1SAndroid Build Coastguard Worker 
207*bbecb9d1SAndroid Build Coastguard Worker    return ok;
208*bbecb9d1SAndroid Build Coastguard Worker }
209*bbecb9d1SAndroid Build Coastguard Worker 
210*bbecb9d1SAndroid Build Coastguard Worker static bool
render_client_dispatch_reset(struct render_client * client,UNUSED const union render_client_op_request * req)211*bbecb9d1SAndroid Build Coastguard Worker render_client_dispatch_reset(struct render_client *client,
212*bbecb9d1SAndroid Build Coastguard Worker                              UNUSED const union render_client_op_request *req)
213*bbecb9d1SAndroid Build Coastguard Worker {
214*bbecb9d1SAndroid Build Coastguard Worker    render_client_clear_records(client);
215*bbecb9d1SAndroid Build Coastguard Worker    return true;
216*bbecb9d1SAndroid Build Coastguard Worker }
217*bbecb9d1SAndroid Build Coastguard Worker 
218*bbecb9d1SAndroid Build Coastguard Worker static bool
render_client_dispatch_init(struct render_client * client,const union render_client_op_request * req)219*bbecb9d1SAndroid Build Coastguard Worker render_client_dispatch_init(struct render_client *client,
220*bbecb9d1SAndroid Build Coastguard Worker                             const union render_client_op_request *req)
221*bbecb9d1SAndroid Build Coastguard Worker {
222*bbecb9d1SAndroid Build Coastguard Worker    client->init_flags = req->init.flags;
223*bbecb9d1SAndroid Build Coastguard Worker 
224*bbecb9d1SAndroid Build Coastguard Worker    /* init now to avoid doing it in each worker, but only when tracing is
225*bbecb9d1SAndroid Build Coastguard Worker     * disabled because perfetto can get confused
226*bbecb9d1SAndroid Build Coastguard Worker     */
227*bbecb9d1SAndroid Build Coastguard Worker #ifndef ENABLE_TRACING
228*bbecb9d1SAndroid Build Coastguard Worker    render_virgl_init(client->init_flags);
229*bbecb9d1SAndroid Build Coastguard Worker #endif
230*bbecb9d1SAndroid Build Coastguard Worker 
231*bbecb9d1SAndroid Build Coastguard Worker    /* this makes the Vulkan loader loads ICDs */
232*bbecb9d1SAndroid Build Coastguard Worker    uint32_t unused_count;
233*bbecb9d1SAndroid Build Coastguard Worker    vkEnumerateInstanceExtensionProperties(NULL, &unused_count, NULL);
234*bbecb9d1SAndroid Build Coastguard Worker 
235*bbecb9d1SAndroid Build Coastguard Worker    return true;
236*bbecb9d1SAndroid Build Coastguard Worker }
237*bbecb9d1SAndroid Build Coastguard Worker 
238*bbecb9d1SAndroid Build Coastguard Worker static bool
render_client_dispatch_nop(UNUSED struct render_client * client,UNUSED const union render_client_op_request * req)239*bbecb9d1SAndroid Build Coastguard Worker render_client_dispatch_nop(UNUSED struct render_client *client,
240*bbecb9d1SAndroid Build Coastguard Worker                            UNUSED const union render_client_op_request *req)
241*bbecb9d1SAndroid Build Coastguard Worker {
242*bbecb9d1SAndroid Build Coastguard Worker    return true;
243*bbecb9d1SAndroid Build Coastguard Worker }
244*bbecb9d1SAndroid Build Coastguard Worker 
245*bbecb9d1SAndroid Build Coastguard Worker struct render_client_dispatch_entry {
246*bbecb9d1SAndroid Build Coastguard Worker    size_t expect_size;
247*bbecb9d1SAndroid Build Coastguard Worker    bool (*dispatch)(struct render_client *client,
248*bbecb9d1SAndroid Build Coastguard Worker                     const union render_client_op_request *req);
249*bbecb9d1SAndroid Build Coastguard Worker };
250*bbecb9d1SAndroid Build Coastguard Worker 
251*bbecb9d1SAndroid Build Coastguard Worker static const struct render_client_dispatch_entry
252*bbecb9d1SAndroid Build Coastguard Worker    render_client_dispatch_table[RENDER_CLIENT_OP_COUNT] = {
253*bbecb9d1SAndroid Build Coastguard Worker #define RENDER_CLIENT_DISPATCH(NAME, name)                                               \
254*bbecb9d1SAndroid Build Coastguard Worker    [RENDER_CLIENT_OP_##                                                                  \
255*bbecb9d1SAndroid Build Coastguard Worker       NAME] = { .expect_size = sizeof(struct render_client_op_##name##_request),         \
256*bbecb9d1SAndroid Build Coastguard Worker                 .dispatch = render_client_dispatch_##name }
257*bbecb9d1SAndroid Build Coastguard Worker       RENDER_CLIENT_DISPATCH(NOP, nop),
258*bbecb9d1SAndroid Build Coastguard Worker       RENDER_CLIENT_DISPATCH(INIT, init),
259*bbecb9d1SAndroid Build Coastguard Worker       RENDER_CLIENT_DISPATCH(RESET, reset),
260*bbecb9d1SAndroid Build Coastguard Worker       RENDER_CLIENT_DISPATCH(CREATE_CONTEXT, create_context),
261*bbecb9d1SAndroid Build Coastguard Worker       RENDER_CLIENT_DISPATCH(DESTROY_CONTEXT, destroy_context),
262*bbecb9d1SAndroid Build Coastguard Worker #undef RENDER_CLIENT_DISPATCH
263*bbecb9d1SAndroid Build Coastguard Worker    };
264*bbecb9d1SAndroid Build Coastguard Worker 
265*bbecb9d1SAndroid Build Coastguard Worker bool
render_client_dispatch(struct render_client * client)266*bbecb9d1SAndroid Build Coastguard Worker render_client_dispatch(struct render_client *client)
267*bbecb9d1SAndroid Build Coastguard Worker {
268*bbecb9d1SAndroid Build Coastguard Worker    union render_client_op_request req;
269*bbecb9d1SAndroid Build Coastguard Worker    size_t req_size;
270*bbecb9d1SAndroid Build Coastguard Worker    if (!render_socket_receive_request(&client->socket, &req, sizeof(req), &req_size))
271*bbecb9d1SAndroid Build Coastguard Worker       return false;
272*bbecb9d1SAndroid Build Coastguard Worker 
273*bbecb9d1SAndroid Build Coastguard Worker    if (req.header.op >= RENDER_CLIENT_OP_COUNT) {
274*bbecb9d1SAndroid Build Coastguard Worker       render_log("invalid client op %d", req.header.op);
275*bbecb9d1SAndroid Build Coastguard Worker       return false;
276*bbecb9d1SAndroid Build Coastguard Worker    }
277*bbecb9d1SAndroid Build Coastguard Worker 
278*bbecb9d1SAndroid Build Coastguard Worker    const struct render_client_dispatch_entry *entry =
279*bbecb9d1SAndroid Build Coastguard Worker       &render_client_dispatch_table[req.header.op];
280*bbecb9d1SAndroid Build Coastguard Worker    if (entry->expect_size != req_size) {
281*bbecb9d1SAndroid Build Coastguard Worker       render_log("invalid request size %zu for client op %d", req_size, req.header.op);
282*bbecb9d1SAndroid Build Coastguard Worker       return false;
283*bbecb9d1SAndroid Build Coastguard Worker    }
284*bbecb9d1SAndroid Build Coastguard Worker 
285*bbecb9d1SAndroid Build Coastguard Worker    if (!entry->dispatch(client, &req))
286*bbecb9d1SAndroid Build Coastguard Worker       render_log("failed to dispatch client op %d", req.header.op);
287*bbecb9d1SAndroid Build Coastguard Worker 
288*bbecb9d1SAndroid Build Coastguard Worker    return true;
289*bbecb9d1SAndroid Build Coastguard Worker }
290*bbecb9d1SAndroid Build Coastguard Worker 
291*bbecb9d1SAndroid Build Coastguard Worker void
render_client_destroy(struct render_client * client)292*bbecb9d1SAndroid Build Coastguard Worker render_client_destroy(struct render_client *client)
293*bbecb9d1SAndroid Build Coastguard Worker {
294*bbecb9d1SAndroid Build Coastguard Worker    struct render_server *srv = client->server;
295*bbecb9d1SAndroid Build Coastguard Worker 
296*bbecb9d1SAndroid Build Coastguard Worker    if (srv->state == RENDER_SERVER_STATE_SUBPROCESS) {
297*bbecb9d1SAndroid Build Coastguard Worker       assert(list_is_empty(&client->context_records));
298*bbecb9d1SAndroid Build Coastguard Worker    } else {
299*bbecb9d1SAndroid Build Coastguard Worker       render_client_clear_records(client);
300*bbecb9d1SAndroid Build Coastguard Worker 
301*bbecb9d1SAndroid Build Coastguard Worker       /* see render_client_dispatch_init */
302*bbecb9d1SAndroid Build Coastguard Worker #ifndef ENABLE_TRACING
303*bbecb9d1SAndroid Build Coastguard Worker       render_virgl_fini();
304*bbecb9d1SAndroid Build Coastguard Worker #endif
305*bbecb9d1SAndroid Build Coastguard Worker    }
306*bbecb9d1SAndroid Build Coastguard Worker 
307*bbecb9d1SAndroid Build Coastguard Worker    render_socket_fini(&client->socket);
308*bbecb9d1SAndroid Build Coastguard Worker    free(client);
309*bbecb9d1SAndroid Build Coastguard Worker }
310*bbecb9d1SAndroid Build Coastguard Worker 
311*bbecb9d1SAndroid Build Coastguard Worker struct render_client *
render_client_create(struct render_server * srv,int client_fd)312*bbecb9d1SAndroid Build Coastguard Worker render_client_create(struct render_server *srv, int client_fd)
313*bbecb9d1SAndroid Build Coastguard Worker {
314*bbecb9d1SAndroid Build Coastguard Worker    struct render_client *client = calloc(1, sizeof(*client));
315*bbecb9d1SAndroid Build Coastguard Worker 
316*bbecb9d1SAndroid Build Coastguard Worker    if (!client)
317*bbecb9d1SAndroid Build Coastguard Worker       return NULL;
318*bbecb9d1SAndroid Build Coastguard Worker 
319*bbecb9d1SAndroid Build Coastguard Worker    client->server = srv;
320*bbecb9d1SAndroid Build Coastguard Worker    render_socket_init(&client->socket, client_fd);
321*bbecb9d1SAndroid Build Coastguard Worker 
322*bbecb9d1SAndroid Build Coastguard Worker    list_inithead(&client->context_records);
323*bbecb9d1SAndroid Build Coastguard Worker 
324*bbecb9d1SAndroid Build Coastguard Worker    return client;
325*bbecb9d1SAndroid Build Coastguard Worker }
326