xref: /aosp_15_r20/external/virglrenderer/src/venus/vkr_transport.c (revision bbecb9d118dfdb95f99bd754f8fa9be01f189df3)
1 /*
2  * Copyright 2020 Google LLC
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #include "vkr_transport.h"
7 
8 #include "venus-protocol/vn_protocol_renderer_dispatches.h"
9 #include "venus-protocol/vn_protocol_renderer_transport.h"
10 #include "vrend_iov.h"
11 
12 #include "vkr_context.h"
13 #include "vkr_ring.h"
14 
15 static void
vkr_dispatch_vkSetReplyCommandStreamMESA(struct vn_dispatch_context * dispatch,struct vn_command_vkSetReplyCommandStreamMESA * args)16 vkr_dispatch_vkSetReplyCommandStreamMESA(
17    struct vn_dispatch_context *dispatch,
18    struct vn_command_vkSetReplyCommandStreamMESA *args)
19 {
20    struct vkr_context *ctx = dispatch->data;
21    struct vkr_resource_attachment *att;
22 
23    att = vkr_context_get_resource(ctx, args->pStream->resourceId);
24    if (!att) {
25       vkr_log("failed to set reply stream: invalid res_id %u", args->pStream->resourceId);
26       vkr_cs_decoder_set_fatal(&ctx->decoder);
27       return;
28    }
29 
30    vkr_cs_encoder_set_stream(&ctx->encoder, att, args->pStream->offset,
31                              args->pStream->size);
32 }
33 
34 static void
vkr_dispatch_vkSeekReplyCommandStreamMESA(struct vn_dispatch_context * dispatch,struct vn_command_vkSeekReplyCommandStreamMESA * args)35 vkr_dispatch_vkSeekReplyCommandStreamMESA(
36    struct vn_dispatch_context *dispatch,
37    struct vn_command_vkSeekReplyCommandStreamMESA *args)
38 {
39    struct vkr_context *ctx = dispatch->data;
40    vkr_cs_encoder_seek_stream(&ctx->encoder, args->position);
41 }
42 
43 static void *
copy_command_stream(struct vkr_context * ctx,const VkCommandStreamDescriptionMESA * stream)44 copy_command_stream(struct vkr_context *ctx, const VkCommandStreamDescriptionMESA *stream)
45 {
46    struct vkr_resource_attachment *att;
47 
48    att = vkr_context_get_resource(ctx, stream->resourceId);
49    if (!att) {
50       vkr_log("failed to copy command stream: invalid res_id %u", stream->resourceId);
51       return NULL;
52    }
53 
54    /* seek to offset */
55    size_t iov_offset = stream->offset;
56    const struct iovec *iov = NULL;
57    for (int i = 0; i < att->iov_count; i++) {
58       if (iov_offset < att->iov[i].iov_len) {
59          iov = &att->iov[i];
60          break;
61       }
62       iov_offset -= att->iov[i].iov_len;
63    }
64    if (!iov) {
65       vkr_log("failed to copy command stream: invalid offset %zu", stream->offset);
66       return NULL;
67    }
68 
69    /* XXX until the decoder supports scatter-gather and is robust enough,
70     * always make a copy in case the caller modifies the commands while we
71     * parse
72     */
73    uint8_t *data = malloc(stream->size);
74    if (!data) {
75       vkr_log("failed to copy command stream: malloc(%zu) failed", stream->size);
76       return NULL;
77    }
78 
79    uint32_t copied = 0;
80    while (true) {
81       const size_t s = MIN2(stream->size - copied, iov->iov_len - iov_offset);
82       memcpy(data + copied, (const uint8_t *)iov->iov_base + iov_offset, s);
83 
84       copied += s;
85       if (copied == stream->size) {
86          break;
87       } else if (iov == &att->iov[att->iov_count - 1]) {
88          vkr_log("failed to copy command stream: invalid size %zu", stream->size);
89          free(data);
90          return NULL;
91       }
92 
93       iov++;
94       iov_offset = 0;
95    }
96 
97    return data;
98 }
99 
100 static void
vkr_dispatch_vkExecuteCommandStreamsMESA(struct vn_dispatch_context * dispatch,struct vn_command_vkExecuteCommandStreamsMESA * args)101 vkr_dispatch_vkExecuteCommandStreamsMESA(
102    struct vn_dispatch_context *dispatch,
103    struct vn_command_vkExecuteCommandStreamsMESA *args)
104 {
105    struct vkr_context *ctx = dispatch->data;
106 
107    if (unlikely(!args->streamCount)) {
108       vkr_log("failed to execute command streams: no stream specified");
109       vkr_cs_decoder_set_fatal(&ctx->decoder);
110       return;
111    }
112 
113    /* note that nested vkExecuteCommandStreamsMESA is not allowed */
114    if (unlikely(!vkr_cs_decoder_push_state(&ctx->decoder))) {
115       vkr_log("failed to execute command streams: nested execution");
116       vkr_cs_decoder_set_fatal(&ctx->decoder);
117       return;
118    }
119 
120    for (uint32_t i = 0; i < args->streamCount; i++) {
121       const VkCommandStreamDescriptionMESA *stream = &args->pStreams[i];
122 
123       if (args->pReplyPositions)
124          vkr_cs_encoder_seek_stream(&ctx->encoder, args->pReplyPositions[i]);
125 
126       if (!stream->size)
127          continue;
128 
129       void *data = copy_command_stream(ctx, stream);
130       if (!data) {
131          vkr_cs_decoder_set_fatal(&ctx->decoder);
132          break;
133       }
134 
135       vkr_cs_decoder_set_stream(&ctx->decoder, data, stream->size);
136       while (vkr_cs_decoder_has_command(&ctx->decoder)) {
137          vn_dispatch_command(&ctx->dispatch);
138          if (vkr_cs_decoder_get_fatal(&ctx->decoder))
139             break;
140       }
141 
142       free(data);
143 
144       if (vkr_cs_decoder_get_fatal(&ctx->decoder))
145          break;
146    }
147 
148    vkr_cs_decoder_pop_state(&ctx->decoder);
149 }
150 
151 static struct vkr_ring *
lookup_ring(struct vkr_context * ctx,uint64_t ring_id)152 lookup_ring(struct vkr_context *ctx, uint64_t ring_id)
153 {
154    struct vkr_ring *ring;
155    LIST_FOR_EACH_ENTRY (ring, &ctx->rings, head) {
156       if (ring->id == ring_id)
157          return ring;
158    }
159    return NULL;
160 }
161 
162 static bool
vkr_ring_layout_init(struct vkr_ring_layout * layout,const struct vkr_resource_attachment * att,const VkRingCreateInfoMESA * info)163 vkr_ring_layout_init(struct vkr_ring_layout *layout,
164                      const struct vkr_resource_attachment *att,
165                      const VkRingCreateInfoMESA *info)
166 {
167    /* clang-format off */
168    *layout = (struct vkr_ring_layout){
169       .attachment = att,
170       .head   = VKR_REGION_INIT(info->offset + info->headOffset, sizeof(uint32_t)),
171       .tail   = VKR_REGION_INIT(info->offset + info->tailOffset, sizeof(uint32_t)),
172       .status = VKR_REGION_INIT(info->offset + info->statusOffset, sizeof(uint32_t)),
173       .buffer = VKR_REGION_INIT(info->offset + info->bufferOffset, info->bufferSize),
174       .extra  = VKR_REGION_INIT(info->offset + info->extraOffset, info->extraSize),
175    };
176 
177    const struct vkr_region res_region = VKR_REGION_INIT(info->offset, info->size);
178    const struct vkr_region *regions[] = {
179       &layout->head,
180       &layout->tail,
181       &layout->status,
182       &layout->buffer,
183       &layout->extra,
184    };
185    /* clang-format on */
186 
187    const struct vkr_region res_size =
188       VKR_REGION_INIT(0, vrend_get_iovec_size(att->iov, att->iov_count));
189    if (!vkr_region_is_valid(&res_region) || !vkr_region_is_within(&res_region, &res_size))
190       return false;
191 
192    for (size_t i = 0; i < ARRAY_SIZE(regions); i++) {
193       const struct vkr_region *region = regions[i];
194 
195       if (!vkr_region_is_valid(region) || !vkr_region_is_within(region, &res_region)) {
196          vkr_log("ring buffer control variable (begin=%lu, end=%lu) placed"
197                  " out-of-bounds in shared memory layout",
198                  region->begin, region->end);
199          return false;
200       }
201 
202       if (!vkr_region_is_aligned(region, 4)) {
203          vkr_log("ring buffer control variable (begin=%lu, end=%lu) must be"
204                  " 32-bit aligned in shared memory layout",
205                  region->begin, region->end);
206          return false;
207       }
208    }
209 
210    /* assumes region->size == 0 is valid */
211    for (size_t i = 0; i < ARRAY_SIZE(regions); i++) {
212       const struct vkr_region *region = regions[i];
213 
214       for (size_t j = i + 1; j < ARRAY_SIZE(regions); j++) {
215          const struct vkr_region *other = regions[j];
216 
217          if (!vkr_region_is_disjoint(region, other)) {
218             vkr_log("ring buffer control variable (begin=%lu, end=%lu)"
219                     " overlaps with control variable (begin=%lu, end=%lu)",
220                     other->begin, other->end, region->begin, region->end);
221             return false;
222          }
223       }
224    }
225 
226    const size_t buf_size = vkr_region_size(&layout->buffer);
227    if (buf_size > VKR_RING_BUFFER_MAX_SIZE || !util_is_power_of_two_nonzero(buf_size)) {
228       vkr_log("ring buffer size (%z) must be a power of two and not exceed %lu", buf_size,
229               VKR_RING_BUFFER_MAX_SIZE);
230       return false;
231    }
232 
233    return true;
234 }
235 
236 static void
vkr_dispatch_vkCreateRingMESA(struct vn_dispatch_context * dispatch,struct vn_command_vkCreateRingMESA * args)237 vkr_dispatch_vkCreateRingMESA(struct vn_dispatch_context *dispatch,
238                               struct vn_command_vkCreateRingMESA *args)
239 {
240    struct vkr_context *ctx = dispatch->data;
241    const VkRingCreateInfoMESA *info = args->pCreateInfo;
242    const struct vkr_resource_attachment *att;
243    struct vkr_ring *ring;
244 
245    att = vkr_context_get_resource(ctx, info->resourceId);
246    if (!att) {
247       vkr_cs_decoder_set_fatal(&ctx->decoder);
248       return;
249    }
250 
251    struct vkr_ring_layout layout;
252    if (!vkr_ring_layout_init(&layout, att, info)) {
253       vkr_log("vkCreateRingMESA supplied with invalid buffer layout parameters");
254       vkr_cs_decoder_set_fatal(&ctx->decoder);
255       return;
256    }
257 
258    ring = vkr_ring_create(&layout, &ctx->base, info->idleTimeout);
259    if (!ring) {
260       vkr_cs_decoder_set_fatal(&ctx->decoder);
261       return;
262    }
263 
264    ring->id = args->ring;
265    list_addtail(&ring->head, &ctx->rings);
266 
267    vkr_ring_start(ring);
268 }
269 
270 static void
vkr_dispatch_vkDestroyRingMESA(struct vn_dispatch_context * dispatch,struct vn_command_vkDestroyRingMESA * args)271 vkr_dispatch_vkDestroyRingMESA(struct vn_dispatch_context *dispatch,
272                                struct vn_command_vkDestroyRingMESA *args)
273 {
274    struct vkr_context *ctx = dispatch->data;
275    struct vkr_ring *ring = lookup_ring(ctx, args->ring);
276    if (!ring || !vkr_ring_stop(ring)) {
277       vkr_cs_decoder_set_fatal(&ctx->decoder);
278       return;
279    }
280 
281    vkr_ring_destroy(ring);
282 }
283 
284 static void
vkr_dispatch_vkNotifyRingMESA(struct vn_dispatch_context * dispatch,struct vn_command_vkNotifyRingMESA * args)285 vkr_dispatch_vkNotifyRingMESA(struct vn_dispatch_context *dispatch,
286                               struct vn_command_vkNotifyRingMESA *args)
287 {
288    struct vkr_context *ctx = dispatch->data;
289    struct vkr_ring *ring = lookup_ring(ctx, args->ring);
290    if (!ring) {
291       vkr_cs_decoder_set_fatal(&ctx->decoder);
292       return;
293    }
294 
295    vkr_ring_notify(ring);
296 }
297 
298 static void
vkr_dispatch_vkWriteRingExtraMESA(struct vn_dispatch_context * dispatch,struct vn_command_vkWriteRingExtraMESA * args)299 vkr_dispatch_vkWriteRingExtraMESA(struct vn_dispatch_context *dispatch,
300                                   struct vn_command_vkWriteRingExtraMESA *args)
301 {
302    struct vkr_context *ctx = dispatch->data;
303    struct vkr_ring *ring = lookup_ring(ctx, args->ring);
304    if (!ring) {
305       vkr_cs_decoder_set_fatal(&ctx->decoder);
306       return;
307    }
308 
309    if (!vkr_ring_write_extra(ring, args->offset, args->value))
310       vkr_cs_decoder_set_fatal(&ctx->decoder);
311 }
312 
313 static void
vkr_dispatch_vkGetVenusExperimentalFeatureData100000MESA(UNUSED struct vn_dispatch_context * dispatch,struct vn_command_vkGetVenusExperimentalFeatureData100000MESA * args)314 vkr_dispatch_vkGetVenusExperimentalFeatureData100000MESA(
315    UNUSED struct vn_dispatch_context *dispatch,
316    struct vn_command_vkGetVenusExperimentalFeatureData100000MESA *args)
317 {
318    const VkVenusExperimentalFeatures100000MESA features = {
319       .memoryResourceAllocationSize = VK_TRUE,
320       .globalFencing = VK_FALSE,
321       .largeRing = VK_TRUE,
322       .syncFdFencing = VK_TRUE,
323    };
324 
325    vn_replace_vkGetVenusExperimentalFeatureData100000MESA_args_handle(args);
326 
327    if (!args->pData) {
328       *args->pDataSize = sizeof(features);
329       return;
330    }
331 
332    *args->pDataSize = MIN2(*args->pDataSize, sizeof(features));
333    memcpy(args->pData, &features, *args->pDataSize);
334 }
335 
336 void
vkr_context_init_transport_dispatch(struct vkr_context * ctx)337 vkr_context_init_transport_dispatch(struct vkr_context *ctx)
338 {
339    struct vn_dispatch_context *dispatch = &ctx->dispatch;
340 
341    dispatch->dispatch_vkSetReplyCommandStreamMESA =
342       vkr_dispatch_vkSetReplyCommandStreamMESA;
343    dispatch->dispatch_vkSeekReplyCommandStreamMESA =
344       vkr_dispatch_vkSeekReplyCommandStreamMESA;
345    dispatch->dispatch_vkExecuteCommandStreamsMESA =
346       vkr_dispatch_vkExecuteCommandStreamsMESA;
347    dispatch->dispatch_vkCreateRingMESA = vkr_dispatch_vkCreateRingMESA;
348    dispatch->dispatch_vkDestroyRingMESA = vkr_dispatch_vkDestroyRingMESA;
349    dispatch->dispatch_vkNotifyRingMESA = vkr_dispatch_vkNotifyRingMESA;
350    dispatch->dispatch_vkWriteRingExtraMESA = vkr_dispatch_vkWriteRingExtraMESA;
351 
352    dispatch->dispatch_vkGetVenusExperimentalFeatureData100000MESA =
353       vkr_dispatch_vkGetVenusExperimentalFeatureData100000MESA;
354 }
355