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