1 /*
2 * Copyright 2019 Google LLC
3 * SPDX-License-Identifier: MIT
4 *
5 * based in part on anv and radv which are:
6 * Copyright © 2015 Intel Corporation
7 * Copyright © 2016 Red Hat.
8 * Copyright © 2016 Bas Nieuwenhuizen
9 */
10
11 #include "vn_queue.h"
12
13 #include "util/libsync.h"
14 #include "venus-protocol/vn_protocol_driver_event.h"
15 #include "venus-protocol/vn_protocol_driver_fence.h"
16 #include "venus-protocol/vn_protocol_driver_queue.h"
17 #include "venus-protocol/vn_protocol_driver_semaphore.h"
18 #include "venus-protocol/vn_protocol_driver_transport.h"
19
20 #include "vn_command_buffer.h"
21 #include "vn_device.h"
22 #include "vn_device_memory.h"
23 #include "vn_feedback.h"
24 #include "vn_instance.h"
25 #include "vn_physical_device.h"
26 #include "vn_query_pool.h"
27 #include "vn_renderer.h"
28 #include "vn_wsi.h"
29
30 /* queue commands */
31
32 struct vn_submit_info_pnext_fix {
33 VkDeviceGroupSubmitInfo group;
34 VkProtectedSubmitInfo protected;
35 VkTimelineSemaphoreSubmitInfo timeline;
36 };
37
38 struct vn_queue_submission {
39 VkStructureType batch_type;
40 VkQueue queue_handle;
41 uint32_t batch_count;
42 union {
43 const void *batches;
44 const VkSubmitInfo *submit_batches;
45 const VkSubmitInfo2 *submit2_batches;
46 const VkBindSparseInfo *sparse_batches;
47 };
48 VkFence fence_handle;
49
50 uint32_t cmd_count;
51 uint32_t feedback_types;
52 uint32_t pnext_count;
53 uint32_t dev_mask_count;
54 bool has_zink_sync_batch;
55 const struct vn_device_memory *wsi_mem;
56 struct vn_sync_payload_external external_payload;
57
58 /* Temporary storage allocation for submission
59 *
60 * A single alloc for storage is performed and the offsets inside storage
61 * are set as below:
62 *
63 * batches
64 * - non-empty submission: copy of original batches
65 * - empty submission: a single batch for fence feedback (ffb)
66 * cmds
67 * - for each batch:
68 * - copy of original batch cmds
69 * - a single cmd for query feedback (qfb)
70 * - one cmd for each signal semaphore that has feedback (sfb)
71 * - if last batch, a single cmd for ffb
72 */
73 struct {
74 void *storage;
75
76 union {
77 void *batches;
78 VkSubmitInfo *submit_batches;
79 VkSubmitInfo2 *submit2_batches;
80 };
81
82 union {
83 void *cmds;
84 VkCommandBuffer *cmd_handles;
85 VkCommandBufferSubmitInfo *cmd_infos;
86 };
87
88 struct vn_submit_info_pnext_fix *pnexts;
89 uint32_t *dev_masks;
90 } temp;
91 };
92
93 static inline uint32_t
vn_get_wait_semaphore_count(struct vn_queue_submission * submit,uint32_t batch_index)94 vn_get_wait_semaphore_count(struct vn_queue_submission *submit,
95 uint32_t batch_index)
96 {
97 switch (submit->batch_type) {
98 case VK_STRUCTURE_TYPE_SUBMIT_INFO:
99 return submit->submit_batches[batch_index].waitSemaphoreCount;
100 case VK_STRUCTURE_TYPE_SUBMIT_INFO_2:
101 return submit->submit2_batches[batch_index].waitSemaphoreInfoCount;
102 case VK_STRUCTURE_TYPE_BIND_SPARSE_INFO:
103 return submit->sparse_batches[batch_index].waitSemaphoreCount;
104 default:
105 unreachable("unexpected batch type");
106 }
107 }
108
109 static inline uint32_t
vn_get_signal_semaphore_count(struct vn_queue_submission * submit,uint32_t batch_index)110 vn_get_signal_semaphore_count(struct vn_queue_submission *submit,
111 uint32_t batch_index)
112 {
113 switch (submit->batch_type) {
114 case VK_STRUCTURE_TYPE_SUBMIT_INFO:
115 return submit->submit_batches[batch_index].signalSemaphoreCount;
116 case VK_STRUCTURE_TYPE_SUBMIT_INFO_2:
117 return submit->submit2_batches[batch_index].signalSemaphoreInfoCount;
118 case VK_STRUCTURE_TYPE_BIND_SPARSE_INFO:
119 return submit->sparse_batches[batch_index].signalSemaphoreCount;
120 default:
121 unreachable("unexpected batch type");
122 }
123 }
124
125 static inline VkSemaphore
vn_get_wait_semaphore(struct vn_queue_submission * submit,uint32_t batch_index,uint32_t semaphore_index)126 vn_get_wait_semaphore(struct vn_queue_submission *submit,
127 uint32_t batch_index,
128 uint32_t semaphore_index)
129 {
130 switch (submit->batch_type) {
131 case VK_STRUCTURE_TYPE_SUBMIT_INFO:
132 return submit->submit_batches[batch_index]
133 .pWaitSemaphores[semaphore_index];
134 case VK_STRUCTURE_TYPE_SUBMIT_INFO_2:
135 return submit->submit2_batches[batch_index]
136 .pWaitSemaphoreInfos[semaphore_index]
137 .semaphore;
138 case VK_STRUCTURE_TYPE_BIND_SPARSE_INFO:
139 return submit->sparse_batches[batch_index]
140 .pWaitSemaphores[semaphore_index];
141 default:
142 unreachable("unexpected batch type");
143 }
144 }
145
146 static inline VkSemaphore
vn_get_signal_semaphore(struct vn_queue_submission * submit,uint32_t batch_index,uint32_t semaphore_index)147 vn_get_signal_semaphore(struct vn_queue_submission *submit,
148 uint32_t batch_index,
149 uint32_t semaphore_index)
150 {
151 switch (submit->batch_type) {
152 case VK_STRUCTURE_TYPE_SUBMIT_INFO:
153 return submit->submit_batches[batch_index]
154 .pSignalSemaphores[semaphore_index];
155 case VK_STRUCTURE_TYPE_SUBMIT_INFO_2:
156 return submit->submit2_batches[batch_index]
157 .pSignalSemaphoreInfos[semaphore_index]
158 .semaphore;
159 case VK_STRUCTURE_TYPE_BIND_SPARSE_INFO:
160 return submit->sparse_batches[batch_index]
161 .pSignalSemaphores[semaphore_index];
162 default:
163 unreachable("unexpected batch type");
164 }
165 }
166
167 static inline size_t
vn_get_batch_size(struct vn_queue_submission * submit)168 vn_get_batch_size(struct vn_queue_submission *submit)
169 {
170 assert((submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO) ||
171 (submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO_2));
172 return submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO
173 ? sizeof(VkSubmitInfo)
174 : sizeof(VkSubmitInfo2);
175 }
176
177 static inline size_t
vn_get_cmd_size(struct vn_queue_submission * submit)178 vn_get_cmd_size(struct vn_queue_submission *submit)
179 {
180 assert((submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO) ||
181 (submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO_2));
182 return submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO
183 ? sizeof(VkCommandBuffer)
184 : sizeof(VkCommandBufferSubmitInfo);
185 }
186
187 static inline uint32_t
vn_get_cmd_count(struct vn_queue_submission * submit,uint32_t batch_index)188 vn_get_cmd_count(struct vn_queue_submission *submit, uint32_t batch_index)
189 {
190 assert((submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO) ||
191 (submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO_2));
192 return submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO
193 ? submit->submit_batches[batch_index].commandBufferCount
194 : submit->submit2_batches[batch_index].commandBufferInfoCount;
195 }
196
197 static inline const void *
vn_get_cmds(struct vn_queue_submission * submit,uint32_t batch_index)198 vn_get_cmds(struct vn_queue_submission *submit, uint32_t batch_index)
199 {
200 assert((submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO) ||
201 (submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO_2));
202 return submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO
203 ? (const void *)submit->submit_batches[batch_index]
204 .pCommandBuffers
205 : (const void *)submit->submit2_batches[batch_index]
206 .pCommandBufferInfos;
207 }
208
209 static inline struct vn_command_buffer *
vn_get_cmd(struct vn_queue_submission * submit,uint32_t batch_index,uint32_t cmd_index)210 vn_get_cmd(struct vn_queue_submission *submit,
211 uint32_t batch_index,
212 uint32_t cmd_index)
213 {
214 assert((submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO) ||
215 (submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO_2));
216 return vn_command_buffer_from_handle(
217 submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO
218 ? submit->submit_batches[batch_index].pCommandBuffers[cmd_index]
219 : submit->submit2_batches[batch_index]
220 .pCommandBufferInfos[cmd_index]
221 .commandBuffer);
222 }
223
224 static inline void
vn_set_temp_cmd(struct vn_queue_submission * submit,uint32_t cmd_index,VkCommandBuffer cmd_handle)225 vn_set_temp_cmd(struct vn_queue_submission *submit,
226 uint32_t cmd_index,
227 VkCommandBuffer cmd_handle)
228 {
229 assert((submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO) ||
230 (submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO_2));
231 if (submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO_2) {
232 submit->temp.cmd_infos[cmd_index] = (VkCommandBufferSubmitInfo){
233 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO,
234 .commandBuffer = cmd_handle,
235 };
236 } else {
237 submit->temp.cmd_handles[cmd_index] = cmd_handle;
238 }
239 }
240
241 static uint64_t
vn_get_signal_semaphore_counter(struct vn_queue_submission * submit,uint32_t batch_index,uint32_t sem_index)242 vn_get_signal_semaphore_counter(struct vn_queue_submission *submit,
243 uint32_t batch_index,
244 uint32_t sem_index)
245 {
246 switch (submit->batch_type) {
247 case VK_STRUCTURE_TYPE_SUBMIT_INFO: {
248 const struct VkTimelineSemaphoreSubmitInfo *timeline_sem_info =
249 vk_find_struct_const(submit->submit_batches[batch_index].pNext,
250 TIMELINE_SEMAPHORE_SUBMIT_INFO);
251 return timeline_sem_info->pSignalSemaphoreValues[sem_index];
252 }
253 case VK_STRUCTURE_TYPE_SUBMIT_INFO_2:
254 return submit->submit2_batches[batch_index]
255 .pSignalSemaphoreInfos[sem_index]
256 .value;
257 default:
258 unreachable("unexpected batch type");
259 }
260 }
261
262 static bool
vn_has_zink_sync_batch(struct vn_queue_submission * submit)263 vn_has_zink_sync_batch(struct vn_queue_submission *submit)
264 {
265 struct vn_queue *queue = vn_queue_from_handle(submit->queue_handle);
266 struct vn_device *dev = (void *)queue->base.base.base.device;
267 struct vn_instance *instance = dev->instance;
268 const uint32_t last_batch_index = submit->batch_count - 1;
269
270 if (!instance->engine_is_zink)
271 return false;
272
273 if (!submit->batch_count || !last_batch_index ||
274 vn_get_cmd_count(submit, last_batch_index))
275 return false;
276
277 if (vn_get_wait_semaphore_count(submit, last_batch_index))
278 return false;
279
280 const uint32_t signal_count =
281 vn_get_signal_semaphore_count(submit, last_batch_index);
282 for (uint32_t i = 0; i < signal_count; i++) {
283 struct vn_semaphore *sem = vn_semaphore_from_handle(
284 vn_get_signal_semaphore(submit, last_batch_index, i));
285 if (sem->feedback.slot) {
286 return true;
287 }
288 }
289 return false;
290 }
291
292 static bool
vn_fix_batch_cmd_count_for_zink_sync(struct vn_queue_submission * submit,uint32_t batch_index,uint32_t new_cmd_count)293 vn_fix_batch_cmd_count_for_zink_sync(struct vn_queue_submission *submit,
294 uint32_t batch_index,
295 uint32_t new_cmd_count)
296 {
297 /* If the last batch is a zink sync batch which is empty but contains
298 * feedback, append the feedback to the previous batch instead so that
299 * the last batch remains empty for perf.
300 */
301 if (batch_index == submit->batch_count - 1 &&
302 submit->has_zink_sync_batch) {
303 if (submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO_2) {
304 VkSubmitInfo2 *batch =
305 &submit->temp.submit2_batches[batch_index - 1];
306 assert(batch->pCommandBufferInfos);
307 batch->commandBufferInfoCount += new_cmd_count;
308 } else {
309 VkSubmitInfo *batch = &submit->temp.submit_batches[batch_index - 1];
310 assert(batch->pCommandBuffers);
311 batch->commandBufferCount += new_cmd_count;
312 }
313 return true;
314 }
315 return false;
316 }
317
318 static void
vn_fix_device_group_cmd_count(struct vn_queue_submission * submit,uint32_t batch_index)319 vn_fix_device_group_cmd_count(struct vn_queue_submission *submit,
320 uint32_t batch_index)
321 {
322 struct vk_queue *queue_vk = vk_queue_from_handle(submit->queue_handle);
323 struct vn_device *dev = (void *)queue_vk->base.device;
324 const VkSubmitInfo *src_batch = &submit->submit_batches[batch_index];
325 struct vn_submit_info_pnext_fix *pnext_fix = submit->temp.pnexts;
326 VkBaseOutStructure *dst =
327 (void *)&submit->temp.submit_batches[batch_index];
328 uint32_t new_cmd_count =
329 submit->temp.submit_batches[batch_index].commandBufferCount;
330
331 vk_foreach_struct_const(src, src_batch->pNext) {
332 void *pnext = NULL;
333 switch (src->sType) {
334 case VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO: {
335 uint32_t orig_cmd_count = 0;
336
337 memcpy(&pnext_fix->group, src, sizeof(pnext_fix->group));
338
339 VkDeviceGroupSubmitInfo *src_device_group =
340 (VkDeviceGroupSubmitInfo *)src;
341 if (src_device_group->commandBufferCount) {
342 orig_cmd_count = src_device_group->commandBufferCount;
343 memcpy(submit->temp.dev_masks,
344 src_device_group->pCommandBufferDeviceMasks,
345 sizeof(uint32_t) * orig_cmd_count);
346 }
347
348 /* Set the group device mask. Unlike sync2, zero means skip. */
349 for (uint32_t i = orig_cmd_count; i < new_cmd_count; i++) {
350 submit->temp.dev_masks[i] = dev->device_mask;
351 }
352
353 pnext_fix->group.commandBufferCount = new_cmd_count;
354 pnext_fix->group.pCommandBufferDeviceMasks = submit->temp.dev_masks;
355 pnext = &pnext_fix->group;
356 break;
357 }
358 case VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO:
359 memcpy(&pnext_fix->protected, src, sizeof(pnext_fix->protected));
360 pnext = &pnext_fix->protected;
361 break;
362 case VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO:
363 memcpy(&pnext_fix->timeline, src, sizeof(pnext_fix->timeline));
364 pnext = &pnext_fix->timeline;
365 break;
366 default:
367 /* The following structs are not supported by venus so are not
368 * handled here. VkAmigoProfilingSubmitInfoSEC,
369 * VkD3D12FenceSubmitInfoKHR, VkFrameBoundaryEXT,
370 * VkLatencySubmissionPresentIdNV, VkPerformanceQuerySubmitInfoKHR,
371 * VkWin32KeyedMutexAcquireReleaseInfoKHR,
372 * VkWin32KeyedMutexAcquireReleaseInfoNV
373 */
374 break;
375 }
376
377 if (pnext) {
378 dst->pNext = pnext;
379 dst = pnext;
380 }
381 }
382 submit->temp.pnexts++;
383 submit->temp.dev_masks += new_cmd_count;
384 }
385
386 static bool
387 vn_semaphore_wait_external(struct vn_device *dev, struct vn_semaphore *sem);
388
389 static VkResult
vn_queue_submission_fix_batch_semaphores(struct vn_queue_submission * submit,uint32_t batch_index)390 vn_queue_submission_fix_batch_semaphores(struct vn_queue_submission *submit,
391 uint32_t batch_index)
392 {
393 struct vk_queue *queue_vk = vk_queue_from_handle(submit->queue_handle);
394 VkDevice dev_handle = vk_device_to_handle(queue_vk->base.device);
395 struct vn_device *dev = vn_device_from_handle(dev_handle);
396
397 const uint32_t wait_count =
398 vn_get_wait_semaphore_count(submit, batch_index);
399 for (uint32_t i = 0; i < wait_count; i++) {
400 VkSemaphore sem_handle = vn_get_wait_semaphore(submit, batch_index, i);
401 struct vn_semaphore *sem = vn_semaphore_from_handle(sem_handle);
402 const struct vn_sync_payload *payload = sem->payload;
403
404 if (payload->type != VN_SYNC_TYPE_IMPORTED_SYNC_FD)
405 continue;
406
407 if (!vn_semaphore_wait_external(dev, sem))
408 return VK_ERROR_DEVICE_LOST;
409
410 assert(dev->physical_device->renderer_sync_fd.semaphore_importable);
411
412 const VkImportSemaphoreResourceInfoMESA res_info = {
413 .sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_RESOURCE_INFO_MESA,
414 .semaphore = sem_handle,
415 .resourceId = 0,
416 };
417 vn_async_vkImportSemaphoreResourceMESA(dev->primary_ring, dev_handle,
418 &res_info);
419 }
420
421 return VK_SUCCESS;
422 }
423
424 static void
vn_queue_submission_count_batch_feedback(struct vn_queue_submission * submit,uint32_t batch_index)425 vn_queue_submission_count_batch_feedback(struct vn_queue_submission *submit,
426 uint32_t batch_index)
427 {
428 const uint32_t signal_count =
429 vn_get_signal_semaphore_count(submit, batch_index);
430 uint32_t extra_cmd_count = 0;
431 uint32_t feedback_types = 0;
432
433 for (uint32_t i = 0; i < signal_count; i++) {
434 struct vn_semaphore *sem = vn_semaphore_from_handle(
435 vn_get_signal_semaphore(submit, batch_index, i));
436 if (sem->feedback.slot) {
437 feedback_types |= VN_FEEDBACK_TYPE_SEMAPHORE;
438 extra_cmd_count++;
439 }
440 }
441
442 if (submit->batch_type != VK_STRUCTURE_TYPE_BIND_SPARSE_INFO) {
443 const uint32_t cmd_count = vn_get_cmd_count(submit, batch_index);
444 for (uint32_t i = 0; i < cmd_count; i++) {
445 struct vn_command_buffer *cmd = vn_get_cmd(submit, batch_index, i);
446 if (!list_is_empty(&cmd->builder.query_records))
447 feedback_types |= VN_FEEDBACK_TYPE_QUERY;
448
449 /* If a cmd that was submitted previously and already has a feedback
450 * cmd linked, as long as
451 * VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT was not set we can
452 * assume it has completed execution and is no longer in the pending
453 * state so its safe to recycle the old feedback command.
454 */
455 if (cmd->linked_qfb_cmd) {
456 assert(!cmd->builder.is_simultaneous);
457
458 vn_query_feedback_cmd_free(cmd->linked_qfb_cmd);
459 cmd->linked_qfb_cmd = NULL;
460 }
461 }
462 if (feedback_types & VN_FEEDBACK_TYPE_QUERY)
463 extra_cmd_count++;
464
465 if (submit->feedback_types & VN_FEEDBACK_TYPE_FENCE &&
466 batch_index == submit->batch_count - 1) {
467 feedback_types |= VN_FEEDBACK_TYPE_FENCE;
468 extra_cmd_count++;
469 }
470
471 /* Space to copy the original cmds to append feedback to it.
472 * If the last batch is a zink sync batch which is an empty batch with
473 * sem feedback, feedback will be appended to the second to last batch
474 * so also need to copy the second to last batch's original cmds even
475 * if it doesn't have feedback itself.
476 */
477 if (feedback_types || (batch_index == submit->batch_count - 2 &&
478 submit->has_zink_sync_batch)) {
479 extra_cmd_count += cmd_count;
480 }
481 }
482
483 if (submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO &&
484 extra_cmd_count) {
485 const VkDeviceGroupSubmitInfo *device_group = vk_find_struct_const(
486 submit->submit_batches[batch_index].pNext, DEVICE_GROUP_SUBMIT_INFO);
487 if (device_group) {
488 submit->pnext_count++;
489 submit->dev_mask_count += extra_cmd_count;
490 }
491 }
492
493 submit->feedback_types |= feedback_types;
494 submit->cmd_count += extra_cmd_count;
495 }
496
497 static VkResult
vn_queue_submission_prepare(struct vn_queue_submission * submit)498 vn_queue_submission_prepare(struct vn_queue_submission *submit)
499 {
500 struct vn_queue *queue = vn_queue_from_handle(submit->queue_handle);
501 struct vn_fence *fence = vn_fence_from_handle(submit->fence_handle);
502
503 assert(!fence || !fence->is_external || !fence->feedback.slot);
504 if (fence && fence->feedback.slot)
505 submit->feedback_types |= VN_FEEDBACK_TYPE_FENCE;
506
507 if (submit->batch_type != VK_STRUCTURE_TYPE_BIND_SPARSE_INFO)
508 submit->has_zink_sync_batch = vn_has_zink_sync_batch(submit);
509
510 submit->external_payload.ring_idx = queue->ring_idx;
511
512 submit->wsi_mem = NULL;
513 if (submit->batch_count == 1 &&
514 submit->batch_type != VK_STRUCTURE_TYPE_BIND_SPARSE_INFO) {
515 const struct wsi_memory_signal_submit_info *info = vk_find_struct_const(
516 submit->submit_batches[0].pNext, WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA);
517 if (info) {
518 submit->wsi_mem = vn_device_memory_from_handle(info->memory);
519 assert(submit->wsi_mem->base_bo);
520 }
521 }
522
523 for (uint32_t i = 0; i < submit->batch_count; i++) {
524 VkResult result = vn_queue_submission_fix_batch_semaphores(submit, i);
525 if (result != VK_SUCCESS)
526 return result;
527
528 vn_queue_submission_count_batch_feedback(submit, i);
529 }
530
531 return VK_SUCCESS;
532 }
533
534 static VkResult
vn_queue_submission_alloc_storage(struct vn_queue_submission * submit)535 vn_queue_submission_alloc_storage(struct vn_queue_submission *submit)
536 {
537 struct vn_queue *queue = vn_queue_from_handle(submit->queue_handle);
538
539 if (!submit->feedback_types)
540 return VK_SUCCESS;
541
542 /* for original batches or a new batch to hold feedback fence cmd */
543 const size_t total_batch_size =
544 vn_get_batch_size(submit) * MAX2(submit->batch_count, 1);
545 /* for fence, timeline semaphore and query feedback cmds */
546 const size_t total_cmd_size =
547 vn_get_cmd_size(submit) * MAX2(submit->cmd_count, 1);
548 /* for fixing command buffer counts in device group info, if it exists */
549 const size_t total_pnext_size =
550 submit->pnext_count * sizeof(struct vn_submit_info_pnext_fix);
551 const size_t total_dev_mask_size =
552 submit->dev_mask_count * sizeof(uint32_t);
553 submit->temp.storage = vn_cached_storage_get(
554 &queue->storage, total_batch_size + total_cmd_size + total_pnext_size +
555 total_dev_mask_size);
556 if (!submit->temp.storage)
557 return VK_ERROR_OUT_OF_HOST_MEMORY;
558
559 submit->temp.batches = submit->temp.storage;
560 submit->temp.cmds = submit->temp.storage + total_batch_size;
561 submit->temp.pnexts =
562 submit->temp.storage + total_batch_size + total_cmd_size;
563 submit->temp.dev_masks = submit->temp.storage + total_batch_size +
564 total_cmd_size + total_pnext_size;
565
566 return VK_SUCCESS;
567 }
568
569 static VkResult
vn_queue_submission_get_resolved_query_records(struct vn_queue_submission * submit,uint32_t batch_index,struct vn_feedback_cmd_pool * fb_cmd_pool,struct list_head * resolved_records)570 vn_queue_submission_get_resolved_query_records(
571 struct vn_queue_submission *submit,
572 uint32_t batch_index,
573 struct vn_feedback_cmd_pool *fb_cmd_pool,
574 struct list_head *resolved_records)
575 {
576 struct vn_command_pool *cmd_pool =
577 vn_command_pool_from_handle(fb_cmd_pool->pool_handle);
578 struct list_head dropped_records;
579 VkResult result = VK_SUCCESS;
580
581 list_inithead(resolved_records);
582 list_inithead(&dropped_records);
583 const uint32_t cmd_count = vn_get_cmd_count(submit, batch_index);
584 for (uint32_t i = 0; i < cmd_count; i++) {
585 struct vn_command_buffer *cmd = vn_get_cmd(submit, batch_index, i);
586
587 list_for_each_entry(struct vn_cmd_query_record, record,
588 &cmd->builder.query_records, head) {
589 if (!record->copy) {
590 list_for_each_entry_safe(struct vn_cmd_query_record, prev,
591 resolved_records, head) {
592 /* If we previously added a query feedback that is now getting
593 * reset, remove it since it is now a no-op and the deferred
594 * feedback copy will cause a hang waiting for the reset query
595 * to become available.
596 */
597 if (prev->copy && prev->query_pool == record->query_pool &&
598 prev->query >= record->query &&
599 prev->query < record->query + record->query_count)
600 list_move_to(&prev->head, &dropped_records);
601 }
602 }
603
604 simple_mtx_lock(&fb_cmd_pool->mutex);
605 struct vn_cmd_query_record *curr = vn_cmd_pool_alloc_query_record(
606 cmd_pool, record->query_pool, record->query, record->query_count,
607 record->copy);
608 simple_mtx_unlock(&fb_cmd_pool->mutex);
609
610 if (!curr) {
611 list_splicetail(resolved_records, &dropped_records);
612 result = VK_ERROR_OUT_OF_HOST_MEMORY;
613 goto out_free_dropped_records;
614 }
615
616 list_addtail(&curr->head, resolved_records);
617 }
618 }
619
620 /* further resolve to batch sequential queries */
621 struct vn_cmd_query_record *curr =
622 list_first_entry(resolved_records, struct vn_cmd_query_record, head);
623 list_for_each_entry_safe(struct vn_cmd_query_record, next,
624 resolved_records, head) {
625 if (curr->query_pool == next->query_pool && curr->copy == next->copy) {
626 if (curr->query + curr->query_count == next->query) {
627 curr->query_count += next->query_count;
628 list_move_to(&next->head, &dropped_records);
629 } else if (curr->query == next->query + next->query_count) {
630 curr->query = next->query;
631 curr->query_count += next->query_count;
632 list_move_to(&next->head, &dropped_records);
633 } else {
634 curr = next;
635 }
636 } else {
637 curr = next;
638 }
639 }
640
641 out_free_dropped_records:
642 simple_mtx_lock(&fb_cmd_pool->mutex);
643 vn_cmd_pool_free_query_records(cmd_pool, &dropped_records);
644 simple_mtx_unlock(&fb_cmd_pool->mutex);
645 return result;
646 }
647
648 static VkResult
vn_queue_submission_add_query_feedback(struct vn_queue_submission * submit,uint32_t batch_index,uint32_t * new_cmd_count)649 vn_queue_submission_add_query_feedback(struct vn_queue_submission *submit,
650 uint32_t batch_index,
651 uint32_t *new_cmd_count)
652 {
653 struct vk_queue *queue_vk = vk_queue_from_handle(submit->queue_handle);
654 struct vn_device *dev = (void *)queue_vk->base.device;
655 VkResult result;
656
657 struct vn_feedback_cmd_pool *fb_cmd_pool = NULL;
658 for (uint32_t i = 0; i < dev->queue_family_count; i++) {
659 if (dev->queue_families[i] == queue_vk->queue_family_index) {
660 fb_cmd_pool = &dev->fb_cmd_pools[i];
661 break;
662 }
663 }
664 assert(fb_cmd_pool);
665
666 struct list_head resolved_records;
667 result = vn_queue_submission_get_resolved_query_records(
668 submit, batch_index, fb_cmd_pool, &resolved_records);
669 if (result != VK_SUCCESS)
670 return result;
671
672 /* currently the reset query is always recorded */
673 assert(!list_is_empty(&resolved_records));
674 struct vn_query_feedback_cmd *qfb_cmd;
675 result = vn_query_feedback_cmd_alloc(vn_device_to_handle(dev), fb_cmd_pool,
676 &resolved_records, &qfb_cmd);
677 if (result == VK_SUCCESS) {
678 /* link query feedback cmd lifecycle with a cmd in the original batch so
679 * that the feedback cmd can be reset and recycled when that cmd gets
680 * reset/freed.
681 *
682 * Avoid cmd buffers with VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT
683 * since we don't know if all its instances have completed execution.
684 * Should be rare enough to just log and leak the feedback cmd.
685 */
686 bool found_companion_cmd = false;
687 const uint32_t cmd_count = vn_get_cmd_count(submit, batch_index);
688 for (uint32_t i = 0; i < cmd_count; i++) {
689 struct vn_command_buffer *cmd = vn_get_cmd(submit, batch_index, i);
690 if (!cmd->builder.is_simultaneous) {
691 cmd->linked_qfb_cmd = qfb_cmd;
692 found_companion_cmd = true;
693 break;
694 }
695 }
696 if (!found_companion_cmd)
697 vn_log(dev->instance, "WARN: qfb cmd has leaked!");
698
699 vn_set_temp_cmd(submit, (*new_cmd_count)++, qfb_cmd->cmd_handle);
700 }
701
702 simple_mtx_lock(&fb_cmd_pool->mutex);
703 vn_cmd_pool_free_query_records(
704 vn_command_pool_from_handle(fb_cmd_pool->pool_handle),
705 &resolved_records);
706 simple_mtx_unlock(&fb_cmd_pool->mutex);
707
708 return result;
709 }
710
711 struct vn_semaphore_feedback_cmd *
712 vn_semaphore_get_feedback_cmd(struct vn_device *dev,
713 struct vn_semaphore *sem);
714
715 static VkResult
vn_queue_submission_add_semaphore_feedback(struct vn_queue_submission * submit,uint32_t batch_index,uint32_t signal_index,uint32_t * new_cmd_count)716 vn_queue_submission_add_semaphore_feedback(struct vn_queue_submission *submit,
717 uint32_t batch_index,
718 uint32_t signal_index,
719 uint32_t *new_cmd_count)
720 {
721 struct vn_semaphore *sem = vn_semaphore_from_handle(
722 vn_get_signal_semaphore(submit, batch_index, signal_index));
723 if (!sem->feedback.slot)
724 return VK_SUCCESS;
725
726 VK_FROM_HANDLE(vk_queue, queue_vk, submit->queue_handle);
727 struct vn_device *dev = (void *)queue_vk->base.device;
728 struct vn_semaphore_feedback_cmd *sfb_cmd =
729 vn_semaphore_get_feedback_cmd(dev, sem);
730 if (!sfb_cmd)
731 return VK_ERROR_OUT_OF_HOST_MEMORY;
732
733 const uint64_t counter =
734 vn_get_signal_semaphore_counter(submit, batch_index, signal_index);
735 vn_feedback_set_counter(sfb_cmd->src_slot, counter);
736
737 for (uint32_t i = 0; i < dev->queue_family_count; i++) {
738 if (dev->queue_families[i] == queue_vk->queue_family_index) {
739 vn_set_temp_cmd(submit, (*new_cmd_count)++, sfb_cmd->cmd_handles[i]);
740 return VK_SUCCESS;
741 }
742 }
743
744 unreachable("bad feedback sem");
745 }
746
747 static void
vn_queue_submission_add_fence_feedback(struct vn_queue_submission * submit,uint32_t batch_index,uint32_t * new_cmd_count)748 vn_queue_submission_add_fence_feedback(struct vn_queue_submission *submit,
749 uint32_t batch_index,
750 uint32_t *new_cmd_count)
751 {
752 VK_FROM_HANDLE(vk_queue, queue_vk, submit->queue_handle);
753 struct vn_device *dev = (void *)queue_vk->base.device;
754 struct vn_fence *fence = vn_fence_from_handle(submit->fence_handle);
755
756 VkCommandBuffer ffb_cmd_handle = VK_NULL_HANDLE;
757 for (uint32_t i = 0; i < dev->queue_family_count; i++) {
758 if (dev->queue_families[i] == queue_vk->queue_family_index) {
759 ffb_cmd_handle = fence->feedback.commands[i];
760 }
761 }
762 assert(ffb_cmd_handle != VK_NULL_HANDLE);
763
764 vn_set_temp_cmd(submit, (*new_cmd_count)++, ffb_cmd_handle);
765 }
766
767 static VkResult
vn_queue_submission_add_feedback_cmds(struct vn_queue_submission * submit,uint32_t batch_index,uint32_t feedback_types)768 vn_queue_submission_add_feedback_cmds(struct vn_queue_submission *submit,
769 uint32_t batch_index,
770 uint32_t feedback_types)
771 {
772 VkResult result;
773 uint32_t new_cmd_count = vn_get_cmd_count(submit, batch_index);
774
775 if (feedback_types & VN_FEEDBACK_TYPE_QUERY) {
776 result = vn_queue_submission_add_query_feedback(submit, batch_index,
777 &new_cmd_count);
778 if (result != VK_SUCCESS)
779 return result;
780 }
781
782 if (feedback_types & VN_FEEDBACK_TYPE_SEMAPHORE) {
783 const uint32_t signal_count =
784 vn_get_signal_semaphore_count(submit, batch_index);
785 for (uint32_t i = 0; i < signal_count; i++) {
786 result = vn_queue_submission_add_semaphore_feedback(
787 submit, batch_index, i, &new_cmd_count);
788 if (result != VK_SUCCESS)
789 return result;
790 }
791 if (vn_fix_batch_cmd_count_for_zink_sync(submit, batch_index,
792 new_cmd_count))
793 return VK_SUCCESS;
794 }
795
796 if (feedback_types & VN_FEEDBACK_TYPE_FENCE) {
797 vn_queue_submission_add_fence_feedback(submit, batch_index,
798 &new_cmd_count);
799 }
800
801 if (submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO_2) {
802 VkSubmitInfo2 *batch = &submit->temp.submit2_batches[batch_index];
803 batch->pCommandBufferInfos = submit->temp.cmd_infos;
804 batch->commandBufferInfoCount = new_cmd_count;
805 } else {
806 VkSubmitInfo *batch = &submit->temp.submit_batches[batch_index];
807 batch->pCommandBuffers = submit->temp.cmd_handles;
808 batch->commandBufferCount = new_cmd_count;
809
810 const VkDeviceGroupSubmitInfo *device_group = vk_find_struct_const(
811 submit->submit_batches[batch_index].pNext, DEVICE_GROUP_SUBMIT_INFO);
812 if (device_group)
813 vn_fix_device_group_cmd_count(submit, batch_index);
814 }
815
816 return VK_SUCCESS;
817 }
818
819 static VkResult
vn_queue_submission_setup_batch(struct vn_queue_submission * submit,uint32_t batch_index)820 vn_queue_submission_setup_batch(struct vn_queue_submission *submit,
821 uint32_t batch_index)
822 {
823 uint32_t feedback_types = 0;
824 uint32_t extra_cmd_count = 0;
825
826 const uint32_t signal_count =
827 vn_get_signal_semaphore_count(submit, batch_index);
828 for (uint32_t i = 0; i < signal_count; i++) {
829 struct vn_semaphore *sem = vn_semaphore_from_handle(
830 vn_get_signal_semaphore(submit, batch_index, i));
831 if (sem->feedback.slot) {
832 feedback_types |= VN_FEEDBACK_TYPE_SEMAPHORE;
833 extra_cmd_count++;
834 }
835 }
836
837 const uint32_t cmd_count = vn_get_cmd_count(submit, batch_index);
838 for (uint32_t i = 0; i < cmd_count; i++) {
839 struct vn_command_buffer *cmd = vn_get_cmd(submit, batch_index, i);
840 if (!list_is_empty(&cmd->builder.query_records)) {
841 feedback_types |= VN_FEEDBACK_TYPE_QUERY;
842 extra_cmd_count++;
843 break;
844 }
845 }
846
847 if (submit->feedback_types & VN_FEEDBACK_TYPE_FENCE &&
848 batch_index == submit->batch_count - 1) {
849 feedback_types |= VN_FEEDBACK_TYPE_FENCE;
850 extra_cmd_count++;
851 }
852
853 /* If the batch has qfb, sfb or ffb, copy the original commands and append
854 * feedback cmds.
855 * If this is the second to last batch and the last batch a zink sync batch
856 * which is empty but has feedback, also copy the original commands for
857 * this batch so that the last batch's feedback can be appended to it.
858 */
859 if (feedback_types || (batch_index == submit->batch_count - 2 &&
860 submit->has_zink_sync_batch)) {
861 const size_t cmd_size = vn_get_cmd_size(submit);
862 const size_t total_cmd_size = cmd_count * cmd_size;
863 /* copy only needed for non-empty batches */
864 if (total_cmd_size) {
865 memcpy(submit->temp.cmds, vn_get_cmds(submit, batch_index),
866 total_cmd_size);
867 }
868
869 VkResult result = vn_queue_submission_add_feedback_cmds(
870 submit, batch_index, feedback_types);
871 if (result != VK_SUCCESS)
872 return result;
873
874 /* advance the temp cmds for working on next batch cmds */
875 submit->temp.cmds += total_cmd_size + (extra_cmd_count * cmd_size);
876 }
877
878 return VK_SUCCESS;
879 }
880
881 static VkResult
vn_queue_submission_setup_batches(struct vn_queue_submission * submit)882 vn_queue_submission_setup_batches(struct vn_queue_submission *submit)
883 {
884 assert(submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO_2 ||
885 submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO);
886
887 if (!submit->feedback_types)
888 return VK_SUCCESS;
889
890 /* For a submission that is:
891 * - non-empty: copy batches for adding feedbacks
892 * - empty: initialize a batch for fence feedback
893 */
894 if (submit->batch_count) {
895 memcpy(submit->temp.batches, submit->batches,
896 vn_get_batch_size(submit) * submit->batch_count);
897 } else {
898 assert(submit->feedback_types & VN_FEEDBACK_TYPE_FENCE);
899 if (submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO_2) {
900 submit->temp.submit2_batches[0] = (VkSubmitInfo2){
901 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2,
902 };
903 } else {
904 submit->temp.submit_batches[0] = (VkSubmitInfo){
905 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
906 };
907 }
908 submit->batch_count = 1;
909 submit->batches = submit->temp.batches;
910 }
911
912 for (uint32_t i = 0; i < submit->batch_count; i++) {
913 VkResult result = vn_queue_submission_setup_batch(submit, i);
914 if (result != VK_SUCCESS)
915 return result;
916 }
917
918 submit->batches = submit->temp.batches;
919
920 return VK_SUCCESS;
921 }
922
923 static void
vn_queue_submission_cleanup_semaphore_feedback(struct vn_queue_submission * submit)924 vn_queue_submission_cleanup_semaphore_feedback(
925 struct vn_queue_submission *submit)
926 {
927 struct vk_queue *queue_vk = vk_queue_from_handle(submit->queue_handle);
928 VkDevice dev_handle = vk_device_to_handle(queue_vk->base.device);
929
930 for (uint32_t i = 0; i < submit->batch_count; i++) {
931 const uint32_t wait_count = vn_get_wait_semaphore_count(submit, i);
932 for (uint32_t j = 0; j < wait_count; j++) {
933 VkSemaphore sem_handle = vn_get_wait_semaphore(submit, i, j);
934 struct vn_semaphore *sem = vn_semaphore_from_handle(sem_handle);
935 if (!sem->feedback.slot)
936 continue;
937
938 /* sfb pending cmds are recycled when signaled counter is updated */
939 uint64_t counter = 0;
940 vn_GetSemaphoreCounterValue(dev_handle, sem_handle, &counter);
941 }
942
943 const uint32_t signal_count = vn_get_signal_semaphore_count(submit, i);
944 for (uint32_t j = 0; j < signal_count; j++) {
945 VkSemaphore sem_handle = vn_get_signal_semaphore(submit, i, j);
946 struct vn_semaphore *sem = vn_semaphore_from_handle(sem_handle);
947 if (!sem->feedback.slot)
948 continue;
949
950 /* sfb pending cmds are recycled when signaled counter is updated */
951 uint64_t counter = 0;
952 vn_GetSemaphoreCounterValue(dev_handle, sem_handle, &counter);
953 }
954 }
955 }
956
957 static void
vn_queue_submission_cleanup(struct vn_queue_submission * submit)958 vn_queue_submission_cleanup(struct vn_queue_submission *submit)
959 {
960 /* TODO clean up pending src feedbacks on failure? */
961 if (submit->feedback_types & VN_FEEDBACK_TYPE_SEMAPHORE)
962 vn_queue_submission_cleanup_semaphore_feedback(submit);
963 }
964
965 static VkResult
vn_queue_submission_prepare_submit(struct vn_queue_submission * submit)966 vn_queue_submission_prepare_submit(struct vn_queue_submission *submit)
967 {
968 VkResult result = vn_queue_submission_prepare(submit);
969 if (result != VK_SUCCESS)
970 return result;
971
972 result = vn_queue_submission_alloc_storage(submit);
973 if (result != VK_SUCCESS)
974 return result;
975
976 result = vn_queue_submission_setup_batches(submit);
977 if (result != VK_SUCCESS) {
978 vn_queue_submission_cleanup(submit);
979 return result;
980 }
981
982 return VK_SUCCESS;
983 }
984
985 static void
vn_queue_wsi_present(struct vn_queue_submission * submit)986 vn_queue_wsi_present(struct vn_queue_submission *submit)
987 {
988 struct vk_queue *queue_vk = vk_queue_from_handle(submit->queue_handle);
989 struct vn_device *dev = (void *)queue_vk->base.device;
990
991 if (!submit->wsi_mem)
992 return;
993
994 if (dev->renderer->info.has_implicit_fencing) {
995 struct vn_renderer_submit_batch batch = {
996 .ring_idx = submit->external_payload.ring_idx,
997 };
998
999 uint32_t local_data[8];
1000 struct vn_cs_encoder local_enc =
1001 VN_CS_ENCODER_INITIALIZER_LOCAL(local_data, sizeof(local_data));
1002 if (submit->external_payload.ring_seqno_valid) {
1003 const uint64_t ring_id = vn_ring_get_id(dev->primary_ring);
1004 vn_encode_vkWaitRingSeqnoMESA(&local_enc, 0, ring_id,
1005 submit->external_payload.ring_seqno);
1006 batch.cs_data = local_data;
1007 batch.cs_size = vn_cs_encoder_get_len(&local_enc);
1008 }
1009
1010 const struct vn_renderer_submit renderer_submit = {
1011 .bos = &submit->wsi_mem->base_bo,
1012 .bo_count = 1,
1013 .batches = &batch,
1014 .batch_count = 1,
1015 };
1016 vn_renderer_submit(dev->renderer, &renderer_submit);
1017 } else {
1018 if (VN_DEBUG(WSI)) {
1019 static uint32_t num_rate_limit_warning = 0;
1020
1021 if (num_rate_limit_warning++ < 10)
1022 vn_log(dev->instance,
1023 "forcing vkQueueWaitIdle before presenting");
1024 }
1025
1026 vn_QueueWaitIdle(submit->queue_handle);
1027 }
1028 }
1029
1030 static VkResult
vn_queue_submit(struct vn_queue_submission * submit)1031 vn_queue_submit(struct vn_queue_submission *submit)
1032 {
1033 struct vn_queue *queue = vn_queue_from_handle(submit->queue_handle);
1034 struct vn_device *dev = (void *)queue->base.base.base.device;
1035 struct vn_instance *instance = dev->instance;
1036 VkResult result;
1037
1038 /* To ensure external components waiting on the correct fence payload,
1039 * below sync primitives must be installed after the submission:
1040 * - explicit fencing: sync file export
1041 * - implicit fencing: dma-fence attached to the wsi bo
1042 *
1043 * We enforce above via an asynchronous vkQueueSubmit(2) via ring followed
1044 * by an asynchronous renderer submission to wait for the ring submission:
1045 * - struct wsi_memory_signal_submit_info
1046 * - fence is an external fence
1047 * - has an external signal semaphore
1048 */
1049 result = vn_queue_submission_prepare_submit(submit);
1050 if (result != VK_SUCCESS)
1051 return vn_error(instance, result);
1052
1053 /* skip no-op submit */
1054 if (!submit->batch_count && submit->fence_handle == VK_NULL_HANDLE)
1055 return VK_SUCCESS;
1056
1057 if (VN_PERF(NO_ASYNC_QUEUE_SUBMIT)) {
1058 if (submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO_2) {
1059 result = vn_call_vkQueueSubmit2(
1060 dev->primary_ring, submit->queue_handle, submit->batch_count,
1061 submit->submit2_batches, submit->fence_handle);
1062 } else {
1063 result = vn_call_vkQueueSubmit(
1064 dev->primary_ring, submit->queue_handle, submit->batch_count,
1065 submit->submit_batches, submit->fence_handle);
1066 }
1067
1068 if (result != VK_SUCCESS) {
1069 vn_queue_submission_cleanup(submit);
1070 return vn_error(instance, result);
1071 }
1072 } else {
1073 struct vn_ring_submit_command ring_submit;
1074 if (submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO_2) {
1075 vn_submit_vkQueueSubmit2(
1076 dev->primary_ring, 0, submit->queue_handle, submit->batch_count,
1077 submit->submit2_batches, submit->fence_handle, &ring_submit);
1078 } else {
1079 vn_submit_vkQueueSubmit(dev->primary_ring, 0, submit->queue_handle,
1080 submit->batch_count, submit->submit_batches,
1081 submit->fence_handle, &ring_submit);
1082 }
1083 if (!ring_submit.ring_seqno_valid) {
1084 vn_queue_submission_cleanup(submit);
1085 return vn_error(instance, VK_ERROR_DEVICE_LOST);
1086 }
1087 submit->external_payload.ring_seqno_valid = true;
1088 submit->external_payload.ring_seqno = ring_submit.ring_seqno;
1089 }
1090
1091 /* If external fence, track the submission's ring_idx to facilitate
1092 * sync_file export.
1093 *
1094 * Imported syncs don't need a proxy renderer sync on subsequent export,
1095 * because an fd is already available.
1096 */
1097 struct vn_fence *fence = vn_fence_from_handle(submit->fence_handle);
1098 if (fence && fence->is_external) {
1099 assert(fence->payload->type == VN_SYNC_TYPE_DEVICE_ONLY);
1100 fence->external_payload = submit->external_payload;
1101 }
1102
1103 for (uint32_t i = 0; i < submit->batch_count; i++) {
1104 const uint32_t signal_count = vn_get_signal_semaphore_count(submit, i);
1105 for (uint32_t j = 0; j < signal_count; j++) {
1106 struct vn_semaphore *sem =
1107 vn_semaphore_from_handle(vn_get_signal_semaphore(submit, i, j));
1108 if (sem->is_external) {
1109 assert(sem->payload->type == VN_SYNC_TYPE_DEVICE_ONLY);
1110 sem->external_payload = submit->external_payload;
1111 }
1112 }
1113 }
1114
1115 vn_queue_wsi_present(submit);
1116
1117 vn_queue_submission_cleanup(submit);
1118
1119 return VK_SUCCESS;
1120 }
1121
1122 VkResult
vn_QueueSubmit(VkQueue queue,uint32_t submitCount,const VkSubmitInfo * pSubmits,VkFence fence)1123 vn_QueueSubmit(VkQueue queue,
1124 uint32_t submitCount,
1125 const VkSubmitInfo *pSubmits,
1126 VkFence fence)
1127 {
1128 VN_TRACE_FUNC();
1129
1130 struct vn_queue_submission submit = {
1131 .batch_type = VK_STRUCTURE_TYPE_SUBMIT_INFO,
1132 .queue_handle = queue,
1133 .batch_count = submitCount,
1134 .submit_batches = pSubmits,
1135 .fence_handle = fence,
1136 };
1137
1138 return vn_queue_submit(&submit);
1139 }
1140
1141 VkResult
vn_QueueSubmit2(VkQueue queue,uint32_t submitCount,const VkSubmitInfo2 * pSubmits,VkFence fence)1142 vn_QueueSubmit2(VkQueue queue,
1143 uint32_t submitCount,
1144 const VkSubmitInfo2 *pSubmits,
1145 VkFence fence)
1146 {
1147 VN_TRACE_FUNC();
1148
1149 struct vn_queue_submission submit = {
1150 .batch_type = VK_STRUCTURE_TYPE_SUBMIT_INFO_2,
1151 .queue_handle = queue,
1152 .batch_count = submitCount,
1153 .submit2_batches = pSubmits,
1154 .fence_handle = fence,
1155 };
1156
1157 return vn_queue_submit(&submit);
1158 }
1159
1160 static VkResult
vn_queue_bind_sparse_submit(struct vn_queue_submission * submit)1161 vn_queue_bind_sparse_submit(struct vn_queue_submission *submit)
1162 {
1163 struct vn_queue *queue = vn_queue_from_handle(submit->queue_handle);
1164 struct vn_device *dev = (void *)queue->base.base.base.device;
1165 struct vn_instance *instance = dev->instance;
1166 VkResult result;
1167
1168 if (VN_PERF(NO_ASYNC_QUEUE_SUBMIT)) {
1169 result = vn_call_vkQueueBindSparse(
1170 dev->primary_ring, submit->queue_handle, submit->batch_count,
1171 submit->sparse_batches, submit->fence_handle);
1172 if (result != VK_SUCCESS)
1173 return vn_error(instance, result);
1174 } else {
1175 struct vn_ring_submit_command ring_submit;
1176 vn_submit_vkQueueBindSparse(dev->primary_ring, 0, submit->queue_handle,
1177 submit->batch_count, submit->sparse_batches,
1178 submit->fence_handle, &ring_submit);
1179
1180 if (!ring_submit.ring_seqno_valid)
1181 return vn_error(instance, VK_ERROR_DEVICE_LOST);
1182 }
1183
1184 return VK_SUCCESS;
1185 }
1186
1187 static VkResult
vn_queue_bind_sparse_submit_batch(struct vn_queue_submission * submit,uint32_t batch_index)1188 vn_queue_bind_sparse_submit_batch(struct vn_queue_submission *submit,
1189 uint32_t batch_index)
1190 {
1191 struct vn_queue *queue = vn_queue_from_handle(submit->queue_handle);
1192 VkDevice dev_handle = vk_device_to_handle(queue->base.base.base.device);
1193 const VkBindSparseInfo *sparse_info = &submit->sparse_batches[batch_index];
1194 const VkSemaphore *signal_sem = sparse_info->pSignalSemaphores;
1195 uint32_t signal_sem_count = sparse_info->signalSemaphoreCount;
1196 VkResult result;
1197
1198 struct vn_queue_submission sparse_batch = {
1199 .batch_type = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,
1200 .queue_handle = submit->queue_handle,
1201 .batch_count = 1,
1202 .fence_handle = VK_NULL_HANDLE,
1203 };
1204
1205 /* lazily create sparse semaphore */
1206 if (queue->sparse_semaphore == VK_NULL_HANDLE) {
1207 queue->sparse_semaphore_counter = 1;
1208 const VkSemaphoreTypeCreateInfo sem_type_create_info = {
1209 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
1210 .pNext = NULL,
1211 /* This must be timeline type to adhere to mesa's requirement
1212 * not to mix binary semaphores with wait-before-signal.
1213 */
1214 .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
1215 .initialValue = 1,
1216 };
1217 const VkSemaphoreCreateInfo create_info = {
1218 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
1219 .pNext = &sem_type_create_info,
1220 .flags = 0,
1221 };
1222
1223 result = vn_CreateSemaphore(dev_handle, &create_info, NULL,
1224 &queue->sparse_semaphore);
1225 if (result != VK_SUCCESS)
1226 return result;
1227 }
1228
1229 /* Setup VkTimelineSemaphoreSubmitInfo's for our queue sparse semaphore
1230 * so that the vkQueueSubmit waits on the vkQueueBindSparse signal.
1231 */
1232 queue->sparse_semaphore_counter++;
1233 struct VkTimelineSemaphoreSubmitInfo wait_timeline_sem_info = { 0 };
1234 wait_timeline_sem_info.sType =
1235 VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO;
1236 wait_timeline_sem_info.signalSemaphoreValueCount = 1;
1237 wait_timeline_sem_info.pSignalSemaphoreValues =
1238 &queue->sparse_semaphore_counter;
1239
1240 struct VkTimelineSemaphoreSubmitInfo signal_timeline_sem_info = { 0 };
1241 signal_timeline_sem_info.sType =
1242 VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO;
1243 signal_timeline_sem_info.waitSemaphoreValueCount = 1;
1244 signal_timeline_sem_info.pWaitSemaphoreValues =
1245 &queue->sparse_semaphore_counter;
1246
1247 /* Split up the original wait and signal semaphores into its respective
1248 * vkTimelineSemaphoreSubmitInfo
1249 */
1250 const struct VkTimelineSemaphoreSubmitInfo *timeline_sem_info =
1251 vk_find_struct_const(sparse_info->pNext,
1252 TIMELINE_SEMAPHORE_SUBMIT_INFO);
1253 if (timeline_sem_info) {
1254 if (timeline_sem_info->waitSemaphoreValueCount) {
1255 wait_timeline_sem_info.waitSemaphoreValueCount =
1256 timeline_sem_info->waitSemaphoreValueCount;
1257 wait_timeline_sem_info.pWaitSemaphoreValues =
1258 timeline_sem_info->pWaitSemaphoreValues;
1259 }
1260
1261 if (timeline_sem_info->signalSemaphoreValueCount) {
1262 signal_timeline_sem_info.signalSemaphoreValueCount =
1263 timeline_sem_info->signalSemaphoreValueCount;
1264 signal_timeline_sem_info.pSignalSemaphoreValues =
1265 timeline_sem_info->pSignalSemaphoreValues;
1266 }
1267 }
1268
1269 /* Attach the original VkDeviceGroupBindSparseInfo if it exists */
1270 struct VkDeviceGroupBindSparseInfo batch_device_group_info;
1271 const struct VkDeviceGroupBindSparseInfo *device_group_info =
1272 vk_find_struct_const(sparse_info->pNext, DEVICE_GROUP_BIND_SPARSE_INFO);
1273 if (device_group_info) {
1274 memcpy(&batch_device_group_info, device_group_info,
1275 sizeof(*device_group_info));
1276 batch_device_group_info.pNext = NULL;
1277
1278 wait_timeline_sem_info.pNext = &batch_device_group_info;
1279 }
1280
1281 /* Copy the original batch VkBindSparseInfo modified to signal
1282 * our sparse semaphore.
1283 */
1284 VkBindSparseInfo batch_sparse_info;
1285 memcpy(&batch_sparse_info, sparse_info, sizeof(*sparse_info));
1286
1287 batch_sparse_info.pNext = &wait_timeline_sem_info;
1288 batch_sparse_info.signalSemaphoreCount = 1;
1289 batch_sparse_info.pSignalSemaphores = &queue->sparse_semaphore;
1290
1291 /* Set up the SubmitInfo to wait on our sparse semaphore before sending
1292 * feedback and signaling the original semaphores/fence
1293 *
1294 * Even if this VkBindSparse batch does not have feedback semaphores,
1295 * we still glue all the batches together to ensure the feedback
1296 * fence occurs after.
1297 */
1298 VkPipelineStageFlags stage_masks = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
1299 VkSubmitInfo batch_submit_info = {
1300 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
1301 .pNext = &signal_timeline_sem_info,
1302 .waitSemaphoreCount = 1,
1303 .pWaitSemaphores = &queue->sparse_semaphore,
1304 .pWaitDstStageMask = &stage_masks,
1305 .signalSemaphoreCount = signal_sem_count,
1306 .pSignalSemaphores = signal_sem,
1307 };
1308
1309 /* Set the possible fence if on the last batch */
1310 VkFence fence_handle = VK_NULL_HANDLE;
1311 if ((submit->feedback_types & VN_FEEDBACK_TYPE_FENCE) &&
1312 batch_index == (submit->batch_count - 1)) {
1313 fence_handle = submit->fence_handle;
1314 }
1315
1316 sparse_batch.sparse_batches = &batch_sparse_info;
1317 result = vn_queue_bind_sparse_submit(&sparse_batch);
1318 if (result != VK_SUCCESS)
1319 return result;
1320
1321 result = vn_QueueSubmit(submit->queue_handle, 1, &batch_submit_info,
1322 fence_handle);
1323 if (result != VK_SUCCESS)
1324 return result;
1325
1326 return VK_SUCCESS;
1327 }
1328
1329 VkResult
vn_QueueBindSparse(VkQueue queue,uint32_t bindInfoCount,const VkBindSparseInfo * pBindInfo,VkFence fence)1330 vn_QueueBindSparse(VkQueue queue,
1331 uint32_t bindInfoCount,
1332 const VkBindSparseInfo *pBindInfo,
1333 VkFence fence)
1334 {
1335 VN_TRACE_FUNC();
1336 VkResult result;
1337
1338 struct vn_queue_submission submit = {
1339 .batch_type = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,
1340 .queue_handle = queue,
1341 .batch_count = bindInfoCount,
1342 .sparse_batches = pBindInfo,
1343 .fence_handle = fence,
1344 };
1345
1346 result = vn_queue_submission_prepare(&submit);
1347 if (result != VK_SUCCESS)
1348 return result;
1349
1350 if (!submit.batch_count) {
1351 /* skip no-op submit */
1352 if (submit.fence_handle == VK_NULL_HANDLE)
1353 return VK_SUCCESS;
1354
1355 /* if empty batch, just send a vkQueueSubmit with the fence */
1356 result =
1357 vn_QueueSubmit(submit.queue_handle, 0, NULL, submit.fence_handle);
1358 if (result != VK_SUCCESS)
1359 return result;
1360 }
1361
1362 /* if feedback isn't used in the batch, can directly submit */
1363 if (!submit.feedback_types)
1364 return vn_queue_bind_sparse_submit(&submit);
1365
1366 for (uint32_t i = 0; i < submit.batch_count; i++) {
1367 result = vn_queue_bind_sparse_submit_batch(&submit, i);
1368 if (result != VK_SUCCESS)
1369 return result;
1370 }
1371
1372 return VK_SUCCESS;
1373 }
1374
1375 VkResult
vn_QueueWaitIdle(VkQueue _queue)1376 vn_QueueWaitIdle(VkQueue _queue)
1377 {
1378 VN_TRACE_FUNC();
1379 struct vn_queue *queue = vn_queue_from_handle(_queue);
1380 VkDevice dev_handle = vk_device_to_handle(queue->base.base.base.device);
1381 struct vn_device *dev = vn_device_from_handle(dev_handle);
1382 VkResult result;
1383
1384 /* lazily create queue wait fence for queue idle waiting */
1385 if (queue->wait_fence == VK_NULL_HANDLE) {
1386 const VkFenceCreateInfo create_info = {
1387 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
1388 .flags = 0,
1389 };
1390 result =
1391 vn_CreateFence(dev_handle, &create_info, NULL, &queue->wait_fence);
1392 if (result != VK_SUCCESS)
1393 return result;
1394 }
1395
1396 result = vn_QueueSubmit(_queue, 0, NULL, queue->wait_fence);
1397 if (result != VK_SUCCESS)
1398 return result;
1399
1400 result =
1401 vn_WaitForFences(dev_handle, 1, &queue->wait_fence, true, UINT64_MAX);
1402 vn_ResetFences(dev_handle, 1, &queue->wait_fence);
1403
1404 return vn_result(dev->instance, result);
1405 }
1406
1407 /* fence commands */
1408
1409 static void
vn_sync_payload_release(UNUSED struct vn_device * dev,struct vn_sync_payload * payload)1410 vn_sync_payload_release(UNUSED struct vn_device *dev,
1411 struct vn_sync_payload *payload)
1412 {
1413 if (payload->type == VN_SYNC_TYPE_IMPORTED_SYNC_FD && payload->fd >= 0)
1414 close(payload->fd);
1415
1416 payload->type = VN_SYNC_TYPE_INVALID;
1417 }
1418
1419 static VkResult
vn_fence_init_payloads(struct vn_device * dev,struct vn_fence * fence,bool signaled,const VkAllocationCallbacks * alloc)1420 vn_fence_init_payloads(struct vn_device *dev,
1421 struct vn_fence *fence,
1422 bool signaled,
1423 const VkAllocationCallbacks *alloc)
1424 {
1425 fence->permanent.type = VN_SYNC_TYPE_DEVICE_ONLY;
1426 fence->temporary.type = VN_SYNC_TYPE_INVALID;
1427 fence->payload = &fence->permanent;
1428
1429 return VK_SUCCESS;
1430 }
1431
1432 void
vn_fence_signal_wsi(struct vn_device * dev,struct vn_fence * fence)1433 vn_fence_signal_wsi(struct vn_device *dev, struct vn_fence *fence)
1434 {
1435 struct vn_sync_payload *temp = &fence->temporary;
1436
1437 vn_sync_payload_release(dev, temp);
1438 temp->type = VN_SYNC_TYPE_IMPORTED_SYNC_FD;
1439 temp->fd = -1;
1440 fence->payload = temp;
1441 }
1442
1443 static VkResult
vn_fence_feedback_init(struct vn_device * dev,struct vn_fence * fence,bool signaled,const VkAllocationCallbacks * alloc)1444 vn_fence_feedback_init(struct vn_device *dev,
1445 struct vn_fence *fence,
1446 bool signaled,
1447 const VkAllocationCallbacks *alloc)
1448 {
1449 VkDevice dev_handle = vn_device_to_handle(dev);
1450 struct vn_feedback_slot *slot;
1451 VkCommandBuffer *cmd_handles;
1452 VkResult result;
1453
1454 if (fence->is_external)
1455 return VK_SUCCESS;
1456
1457 if (VN_PERF(NO_FENCE_FEEDBACK))
1458 return VK_SUCCESS;
1459
1460 slot = vn_feedback_pool_alloc(&dev->feedback_pool, VN_FEEDBACK_TYPE_FENCE);
1461 if (!slot)
1462 return VK_ERROR_OUT_OF_HOST_MEMORY;
1463
1464 vn_feedback_set_status(slot, signaled ? VK_SUCCESS : VK_NOT_READY);
1465
1466 cmd_handles =
1467 vk_zalloc(alloc, sizeof(*cmd_handles) * dev->queue_family_count,
1468 VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1469 if (!cmd_handles) {
1470 vn_feedback_pool_free(&dev->feedback_pool, slot);
1471 return VK_ERROR_OUT_OF_HOST_MEMORY;
1472 }
1473
1474 for (uint32_t i = 0; i < dev->queue_family_count; i++) {
1475 result = vn_feedback_cmd_alloc(dev_handle, &dev->fb_cmd_pools[i], slot,
1476 NULL, &cmd_handles[i]);
1477 if (result != VK_SUCCESS) {
1478 for (uint32_t j = 0; j < i; j++) {
1479 vn_feedback_cmd_free(dev_handle, &dev->fb_cmd_pools[j],
1480 cmd_handles[j]);
1481 }
1482 break;
1483 }
1484 }
1485
1486 if (result != VK_SUCCESS) {
1487 vk_free(alloc, cmd_handles);
1488 vn_feedback_pool_free(&dev->feedback_pool, slot);
1489 return result;
1490 }
1491
1492 fence->feedback.slot = slot;
1493 fence->feedback.commands = cmd_handles;
1494
1495 return VK_SUCCESS;
1496 }
1497
1498 static void
vn_fence_feedback_fini(struct vn_device * dev,struct vn_fence * fence,const VkAllocationCallbacks * alloc)1499 vn_fence_feedback_fini(struct vn_device *dev,
1500 struct vn_fence *fence,
1501 const VkAllocationCallbacks *alloc)
1502 {
1503 VkDevice dev_handle = vn_device_to_handle(dev);
1504
1505 if (!fence->feedback.slot)
1506 return;
1507
1508 for (uint32_t i = 0; i < dev->queue_family_count; i++) {
1509 vn_feedback_cmd_free(dev_handle, &dev->fb_cmd_pools[i],
1510 fence->feedback.commands[i]);
1511 }
1512
1513 vn_feedback_pool_free(&dev->feedback_pool, fence->feedback.slot);
1514
1515 vk_free(alloc, fence->feedback.commands);
1516 }
1517
1518 VkResult
vn_CreateFence(VkDevice device,const VkFenceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkFence * pFence)1519 vn_CreateFence(VkDevice device,
1520 const VkFenceCreateInfo *pCreateInfo,
1521 const VkAllocationCallbacks *pAllocator,
1522 VkFence *pFence)
1523 {
1524 VN_TRACE_FUNC();
1525 struct vn_device *dev = vn_device_from_handle(device);
1526 const VkAllocationCallbacks *alloc =
1527 pAllocator ? pAllocator : &dev->base.base.alloc;
1528 const bool signaled = pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT;
1529 VkResult result;
1530
1531 struct vn_fence *fence = vk_zalloc(alloc, sizeof(*fence), VN_DEFAULT_ALIGN,
1532 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1533 if (!fence)
1534 return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
1535
1536 vn_object_base_init(&fence->base, VK_OBJECT_TYPE_FENCE, &dev->base);
1537
1538 const struct VkExportFenceCreateInfo *export_info =
1539 vk_find_struct_const(pCreateInfo->pNext, EXPORT_FENCE_CREATE_INFO);
1540 fence->is_external = export_info && export_info->handleTypes;
1541
1542 result = vn_fence_init_payloads(dev, fence, signaled, alloc);
1543 if (result != VK_SUCCESS)
1544 goto out_object_base_fini;
1545
1546 result = vn_fence_feedback_init(dev, fence, signaled, alloc);
1547 if (result != VK_SUCCESS)
1548 goto out_payloads_fini;
1549
1550 *pFence = vn_fence_to_handle(fence);
1551 vn_async_vkCreateFence(dev->primary_ring, device, pCreateInfo, NULL,
1552 pFence);
1553
1554 return VK_SUCCESS;
1555
1556 out_payloads_fini:
1557 vn_sync_payload_release(dev, &fence->permanent);
1558 vn_sync_payload_release(dev, &fence->temporary);
1559
1560 out_object_base_fini:
1561 vn_object_base_fini(&fence->base);
1562 vk_free(alloc, fence);
1563 return vn_error(dev->instance, result);
1564 }
1565
1566 void
vn_DestroyFence(VkDevice device,VkFence _fence,const VkAllocationCallbacks * pAllocator)1567 vn_DestroyFence(VkDevice device,
1568 VkFence _fence,
1569 const VkAllocationCallbacks *pAllocator)
1570 {
1571 VN_TRACE_FUNC();
1572 struct vn_device *dev = vn_device_from_handle(device);
1573 struct vn_fence *fence = vn_fence_from_handle(_fence);
1574 const VkAllocationCallbacks *alloc =
1575 pAllocator ? pAllocator : &dev->base.base.alloc;
1576
1577 if (!fence)
1578 return;
1579
1580 vn_async_vkDestroyFence(dev->primary_ring, device, _fence, NULL);
1581
1582 vn_fence_feedback_fini(dev, fence, alloc);
1583
1584 vn_sync_payload_release(dev, &fence->permanent);
1585 vn_sync_payload_release(dev, &fence->temporary);
1586
1587 vn_object_base_fini(&fence->base);
1588 vk_free(alloc, fence);
1589 }
1590
1591 VkResult
vn_ResetFences(VkDevice device,uint32_t fenceCount,const VkFence * pFences)1592 vn_ResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences)
1593 {
1594 VN_TRACE_FUNC();
1595 struct vn_device *dev = vn_device_from_handle(device);
1596
1597 vn_async_vkResetFences(dev->primary_ring, device, fenceCount, pFences);
1598
1599 for (uint32_t i = 0; i < fenceCount; i++) {
1600 struct vn_fence *fence = vn_fence_from_handle(pFences[i]);
1601 struct vn_sync_payload *perm = &fence->permanent;
1602
1603 vn_sync_payload_release(dev, &fence->temporary);
1604
1605 assert(perm->type == VN_SYNC_TYPE_DEVICE_ONLY);
1606 fence->payload = perm;
1607
1608 if (fence->feedback.slot)
1609 vn_feedback_reset_status(fence->feedback.slot);
1610 }
1611
1612 return VK_SUCCESS;
1613 }
1614
1615 VkResult
vn_GetFenceStatus(VkDevice device,VkFence _fence)1616 vn_GetFenceStatus(VkDevice device, VkFence _fence)
1617 {
1618 struct vn_device *dev = vn_device_from_handle(device);
1619 struct vn_fence *fence = vn_fence_from_handle(_fence);
1620 struct vn_sync_payload *payload = fence->payload;
1621
1622 VkResult result;
1623 switch (payload->type) {
1624 case VN_SYNC_TYPE_DEVICE_ONLY:
1625 if (fence->feedback.slot) {
1626 result = vn_feedback_get_status(fence->feedback.slot);
1627 if (result == VK_SUCCESS) {
1628 /* When fence feedback slot gets signaled, the real fence
1629 * signal operation follows after but the signaling isr can be
1630 * deferred or preempted. To avoid racing, we let the
1631 * renderer wait for the fence. This also helps resolve
1632 * synchronization validation errors, because the layer no
1633 * longer sees any fence status checks and falsely believes the
1634 * caller does not sync.
1635 */
1636 vn_async_vkWaitForFences(dev->primary_ring, device, 1, &_fence,
1637 VK_TRUE, UINT64_MAX);
1638 }
1639 } else {
1640 result = vn_call_vkGetFenceStatus(dev->primary_ring, device, _fence);
1641 }
1642 break;
1643 case VN_SYNC_TYPE_IMPORTED_SYNC_FD:
1644 if (payload->fd < 0 || sync_wait(payload->fd, 0) == 0)
1645 result = VK_SUCCESS;
1646 else
1647 result = errno == ETIME ? VK_NOT_READY : VK_ERROR_DEVICE_LOST;
1648 break;
1649 default:
1650 unreachable("unexpected fence payload type");
1651 break;
1652 }
1653
1654 return vn_result(dev->instance, result);
1655 }
1656
1657 static VkResult
vn_find_first_signaled_fence(VkDevice device,const VkFence * fences,uint32_t count)1658 vn_find_first_signaled_fence(VkDevice device,
1659 const VkFence *fences,
1660 uint32_t count)
1661 {
1662 for (uint32_t i = 0; i < count; i++) {
1663 VkResult result = vn_GetFenceStatus(device, fences[i]);
1664 if (result == VK_SUCCESS || result < 0)
1665 return result;
1666 }
1667 return VK_NOT_READY;
1668 }
1669
1670 static VkResult
vn_remove_signaled_fences(VkDevice device,VkFence * fences,uint32_t * count)1671 vn_remove_signaled_fences(VkDevice device, VkFence *fences, uint32_t *count)
1672 {
1673 uint32_t cur = 0;
1674 for (uint32_t i = 0; i < *count; i++) {
1675 VkResult result = vn_GetFenceStatus(device, fences[i]);
1676 if (result != VK_SUCCESS) {
1677 if (result < 0)
1678 return result;
1679 fences[cur++] = fences[i];
1680 }
1681 }
1682
1683 *count = cur;
1684 return cur ? VK_NOT_READY : VK_SUCCESS;
1685 }
1686
1687 static VkResult
vn_update_sync_result(struct vn_device * dev,VkResult result,int64_t abs_timeout,struct vn_relax_state * relax_state)1688 vn_update_sync_result(struct vn_device *dev,
1689 VkResult result,
1690 int64_t abs_timeout,
1691 struct vn_relax_state *relax_state)
1692 {
1693 switch (result) {
1694 case VK_NOT_READY:
1695 if (abs_timeout != OS_TIMEOUT_INFINITE &&
1696 os_time_get_nano() >= abs_timeout)
1697 result = VK_TIMEOUT;
1698 else
1699 vn_relax(relax_state);
1700 break;
1701 default:
1702 assert(result == VK_SUCCESS || result < 0);
1703 break;
1704 }
1705
1706 return result;
1707 }
1708
1709 VkResult
vn_WaitForFences(VkDevice device,uint32_t fenceCount,const VkFence * pFences,VkBool32 waitAll,uint64_t timeout)1710 vn_WaitForFences(VkDevice device,
1711 uint32_t fenceCount,
1712 const VkFence *pFences,
1713 VkBool32 waitAll,
1714 uint64_t timeout)
1715 {
1716 VN_TRACE_FUNC();
1717 struct vn_device *dev = vn_device_from_handle(device);
1718
1719 const int64_t abs_timeout = os_time_get_absolute_timeout(timeout);
1720 VkResult result = VK_NOT_READY;
1721 if (fenceCount > 1 && waitAll) {
1722 STACK_ARRAY(VkFence, fences, fenceCount);
1723 typed_memcpy(fences, pFences, fenceCount);
1724
1725 struct vn_relax_state relax_state =
1726 vn_relax_init(dev->instance, VN_RELAX_REASON_FENCE);
1727 while (result == VK_NOT_READY) {
1728 result = vn_remove_signaled_fences(device, fences, &fenceCount);
1729 result =
1730 vn_update_sync_result(dev, result, abs_timeout, &relax_state);
1731 }
1732 vn_relax_fini(&relax_state);
1733
1734 STACK_ARRAY_FINISH(fences);
1735 } else {
1736 struct vn_relax_state relax_state =
1737 vn_relax_init(dev->instance, VN_RELAX_REASON_FENCE);
1738 while (result == VK_NOT_READY) {
1739 result = vn_find_first_signaled_fence(device, pFences, fenceCount);
1740 result =
1741 vn_update_sync_result(dev, result, abs_timeout, &relax_state);
1742 }
1743 vn_relax_fini(&relax_state);
1744 }
1745
1746 return vn_result(dev->instance, result);
1747 }
1748
1749 static VkResult
vn_create_sync_file(struct vn_device * dev,struct vn_sync_payload_external * external_payload,int * out_fd)1750 vn_create_sync_file(struct vn_device *dev,
1751 struct vn_sync_payload_external *external_payload,
1752 int *out_fd)
1753 {
1754 struct vn_renderer_sync *sync;
1755 VkResult result = vn_renderer_sync_create(dev->renderer, 0,
1756 VN_RENDERER_SYNC_BINARY, &sync);
1757 if (result != VK_SUCCESS)
1758 return vn_error(dev->instance, result);
1759
1760 struct vn_renderer_submit_batch batch = {
1761 .syncs = &sync,
1762 .sync_values = &(const uint64_t){ 1 },
1763 .sync_count = 1,
1764 .ring_idx = external_payload->ring_idx,
1765 };
1766
1767 uint32_t local_data[8];
1768 struct vn_cs_encoder local_enc =
1769 VN_CS_ENCODER_INITIALIZER_LOCAL(local_data, sizeof(local_data));
1770 if (external_payload->ring_seqno_valid) {
1771 const uint64_t ring_id = vn_ring_get_id(dev->primary_ring);
1772 vn_encode_vkWaitRingSeqnoMESA(&local_enc, 0, ring_id,
1773 external_payload->ring_seqno);
1774 batch.cs_data = local_data;
1775 batch.cs_size = vn_cs_encoder_get_len(&local_enc);
1776 }
1777
1778 const struct vn_renderer_submit submit = {
1779 .batches = &batch,
1780 .batch_count = 1,
1781 };
1782 result = vn_renderer_submit(dev->renderer, &submit);
1783 if (result != VK_SUCCESS) {
1784 vn_renderer_sync_destroy(dev->renderer, sync);
1785 return vn_error(dev->instance, result);
1786 }
1787
1788 *out_fd = vn_renderer_sync_export_syncobj(dev->renderer, sync, true);
1789 vn_renderer_sync_destroy(dev->renderer, sync);
1790
1791 return *out_fd >= 0 ? VK_SUCCESS : VK_ERROR_TOO_MANY_OBJECTS;
1792 }
1793
1794 static inline bool
vn_sync_valid_fd(int fd)1795 vn_sync_valid_fd(int fd)
1796 {
1797 /* the special value -1 for fd is treated like a valid sync file descriptor
1798 * referring to an object that has already signaled
1799 */
1800 return (fd >= 0 && sync_valid_fd(fd)) || fd == -1;
1801 }
1802
1803 VkResult
vn_ImportFenceFdKHR(VkDevice device,const VkImportFenceFdInfoKHR * pImportFenceFdInfo)1804 vn_ImportFenceFdKHR(VkDevice device,
1805 const VkImportFenceFdInfoKHR *pImportFenceFdInfo)
1806 {
1807 VN_TRACE_FUNC();
1808 struct vn_device *dev = vn_device_from_handle(device);
1809 struct vn_fence *fence = vn_fence_from_handle(pImportFenceFdInfo->fence);
1810 ASSERTED const bool sync_file = pImportFenceFdInfo->handleType ==
1811 VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
1812 const int fd = pImportFenceFdInfo->fd;
1813
1814 assert(sync_file);
1815
1816 if (!vn_sync_valid_fd(fd))
1817 return vn_error(dev->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE);
1818
1819 struct vn_sync_payload *temp = &fence->temporary;
1820 vn_sync_payload_release(dev, temp);
1821 temp->type = VN_SYNC_TYPE_IMPORTED_SYNC_FD;
1822 temp->fd = fd;
1823 fence->payload = temp;
1824
1825 return VK_SUCCESS;
1826 }
1827
1828 VkResult
vn_GetFenceFdKHR(VkDevice device,const VkFenceGetFdInfoKHR * pGetFdInfo,int * pFd)1829 vn_GetFenceFdKHR(VkDevice device,
1830 const VkFenceGetFdInfoKHR *pGetFdInfo,
1831 int *pFd)
1832 {
1833 VN_TRACE_FUNC();
1834 struct vn_device *dev = vn_device_from_handle(device);
1835 struct vn_fence *fence = vn_fence_from_handle(pGetFdInfo->fence);
1836 const bool sync_file =
1837 pGetFdInfo->handleType == VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
1838 struct vn_sync_payload *payload = fence->payload;
1839 VkResult result;
1840
1841 assert(sync_file);
1842 assert(dev->physical_device->renderer_sync_fd.fence_exportable);
1843
1844 int fd = -1;
1845 if (payload->type == VN_SYNC_TYPE_DEVICE_ONLY) {
1846 result = vn_create_sync_file(dev, &fence->external_payload, &fd);
1847 if (result != VK_SUCCESS)
1848 return vn_error(dev->instance, result);
1849
1850 vn_async_vkResetFenceResourceMESA(dev->primary_ring, device,
1851 pGetFdInfo->fence);
1852
1853 vn_sync_payload_release(dev, &fence->temporary);
1854 fence->payload = &fence->permanent;
1855
1856 #ifdef VN_USE_WSI_PLATFORM
1857 if (!dev->renderer->info.has_implicit_fencing)
1858 sync_wait(fd, -1);
1859 #endif
1860 } else {
1861 assert(payload->type == VN_SYNC_TYPE_IMPORTED_SYNC_FD);
1862
1863 /* transfer ownership of imported sync fd to save a dup */
1864 fd = payload->fd;
1865 payload->fd = -1;
1866
1867 /* reset host fence in case in signaled state before import */
1868 result = vn_ResetFences(device, 1, &pGetFdInfo->fence);
1869 if (result != VK_SUCCESS) {
1870 /* transfer sync fd ownership back on error */
1871 payload->fd = fd;
1872 return result;
1873 }
1874 }
1875
1876 *pFd = fd;
1877 return VK_SUCCESS;
1878 }
1879
1880 /* semaphore commands */
1881
1882 static VkResult
vn_semaphore_init_payloads(struct vn_device * dev,struct vn_semaphore * sem,uint64_t initial_val,const VkAllocationCallbacks * alloc)1883 vn_semaphore_init_payloads(struct vn_device *dev,
1884 struct vn_semaphore *sem,
1885 uint64_t initial_val,
1886 const VkAllocationCallbacks *alloc)
1887 {
1888 sem->permanent.type = VN_SYNC_TYPE_DEVICE_ONLY;
1889 sem->temporary.type = VN_SYNC_TYPE_INVALID;
1890 sem->payload = &sem->permanent;
1891
1892 return VK_SUCCESS;
1893 }
1894
1895 static bool
vn_semaphore_wait_external(struct vn_device * dev,struct vn_semaphore * sem)1896 vn_semaphore_wait_external(struct vn_device *dev, struct vn_semaphore *sem)
1897 {
1898 struct vn_sync_payload *temp = &sem->temporary;
1899
1900 assert(temp->type == VN_SYNC_TYPE_IMPORTED_SYNC_FD);
1901
1902 if (temp->fd >= 0) {
1903 if (sync_wait(temp->fd, -1))
1904 return false;
1905 }
1906
1907 vn_sync_payload_release(dev, &sem->temporary);
1908 sem->payload = &sem->permanent;
1909
1910 return true;
1911 }
1912
1913 void
vn_semaphore_signal_wsi(struct vn_device * dev,struct vn_semaphore * sem)1914 vn_semaphore_signal_wsi(struct vn_device *dev, struct vn_semaphore *sem)
1915 {
1916 struct vn_sync_payload *temp = &sem->temporary;
1917
1918 vn_sync_payload_release(dev, temp);
1919 temp->type = VN_SYNC_TYPE_IMPORTED_SYNC_FD;
1920 temp->fd = -1;
1921 sem->payload = temp;
1922 }
1923
1924 struct vn_semaphore_feedback_cmd *
vn_semaphore_get_feedback_cmd(struct vn_device * dev,struct vn_semaphore * sem)1925 vn_semaphore_get_feedback_cmd(struct vn_device *dev, struct vn_semaphore *sem)
1926 {
1927 struct vn_semaphore_feedback_cmd *sfb_cmd = NULL;
1928
1929 simple_mtx_lock(&sem->feedback.cmd_mtx);
1930 if (!list_is_empty(&sem->feedback.free_cmds)) {
1931 sfb_cmd = list_first_entry(&sem->feedback.free_cmds,
1932 struct vn_semaphore_feedback_cmd, head);
1933 list_move_to(&sfb_cmd->head, &sem->feedback.pending_cmds);
1934 sem->feedback.free_cmd_count--;
1935 }
1936 simple_mtx_unlock(&sem->feedback.cmd_mtx);
1937
1938 if (!sfb_cmd) {
1939 sfb_cmd = vn_semaphore_feedback_cmd_alloc(dev, sem->feedback.slot);
1940
1941 simple_mtx_lock(&sem->feedback.cmd_mtx);
1942 list_add(&sfb_cmd->head, &sem->feedback.pending_cmds);
1943 simple_mtx_unlock(&sem->feedback.cmd_mtx);
1944 }
1945
1946 return sfb_cmd;
1947 }
1948
1949 static VkResult
vn_semaphore_feedback_init(struct vn_device * dev,struct vn_semaphore * sem,uint64_t initial_value,const VkAllocationCallbacks * alloc)1950 vn_semaphore_feedback_init(struct vn_device *dev,
1951 struct vn_semaphore *sem,
1952 uint64_t initial_value,
1953 const VkAllocationCallbacks *alloc)
1954 {
1955 struct vn_feedback_slot *slot;
1956
1957 assert(sem->type == VK_SEMAPHORE_TYPE_TIMELINE);
1958
1959 if (sem->is_external)
1960 return VK_SUCCESS;
1961
1962 if (VN_PERF(NO_SEMAPHORE_FEEDBACK))
1963 return VK_SUCCESS;
1964
1965 slot =
1966 vn_feedback_pool_alloc(&dev->feedback_pool, VN_FEEDBACK_TYPE_SEMAPHORE);
1967 if (!slot)
1968 return VK_ERROR_OUT_OF_HOST_MEMORY;
1969
1970 list_inithead(&sem->feedback.pending_cmds);
1971 list_inithead(&sem->feedback.free_cmds);
1972
1973 vn_feedback_set_counter(slot, initial_value);
1974
1975 simple_mtx_init(&sem->feedback.cmd_mtx, mtx_plain);
1976 simple_mtx_init(&sem->feedback.async_wait_mtx, mtx_plain);
1977
1978 sem->feedback.signaled_counter = initial_value;
1979 sem->feedback.slot = slot;
1980
1981 return VK_SUCCESS;
1982 }
1983
1984 static void
vn_semaphore_feedback_fini(struct vn_device * dev,struct vn_semaphore * sem)1985 vn_semaphore_feedback_fini(struct vn_device *dev, struct vn_semaphore *sem)
1986 {
1987 if (!sem->feedback.slot)
1988 return;
1989
1990 list_for_each_entry_safe(struct vn_semaphore_feedback_cmd, sfb_cmd,
1991 &sem->feedback.free_cmds, head)
1992 vn_semaphore_feedback_cmd_free(dev, sfb_cmd);
1993
1994 list_for_each_entry_safe(struct vn_semaphore_feedback_cmd, sfb_cmd,
1995 &sem->feedback.pending_cmds, head)
1996 vn_semaphore_feedback_cmd_free(dev, sfb_cmd);
1997
1998 simple_mtx_destroy(&sem->feedback.cmd_mtx);
1999 simple_mtx_destroy(&sem->feedback.async_wait_mtx);
2000
2001 vn_feedback_pool_free(&dev->feedback_pool, sem->feedback.slot);
2002 }
2003
2004 VkResult
vn_CreateSemaphore(VkDevice device,const VkSemaphoreCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSemaphore * pSemaphore)2005 vn_CreateSemaphore(VkDevice device,
2006 const VkSemaphoreCreateInfo *pCreateInfo,
2007 const VkAllocationCallbacks *pAllocator,
2008 VkSemaphore *pSemaphore)
2009 {
2010 VN_TRACE_FUNC();
2011 struct vn_device *dev = vn_device_from_handle(device);
2012 const VkAllocationCallbacks *alloc =
2013 pAllocator ? pAllocator : &dev->base.base.alloc;
2014
2015 struct vn_semaphore *sem = vk_zalloc(alloc, sizeof(*sem), VN_DEFAULT_ALIGN,
2016 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2017 if (!sem)
2018 return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
2019
2020 vn_object_base_init(&sem->base, VK_OBJECT_TYPE_SEMAPHORE, &dev->base);
2021
2022 const VkSemaphoreTypeCreateInfo *type_info =
2023 vk_find_struct_const(pCreateInfo->pNext, SEMAPHORE_TYPE_CREATE_INFO);
2024 uint64_t initial_val = 0;
2025 if (type_info && type_info->semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE) {
2026 sem->type = VK_SEMAPHORE_TYPE_TIMELINE;
2027 initial_val = type_info->initialValue;
2028 } else {
2029 sem->type = VK_SEMAPHORE_TYPE_BINARY;
2030 }
2031
2032 const struct VkExportSemaphoreCreateInfo *export_info =
2033 vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO);
2034 sem->is_external = export_info && export_info->handleTypes;
2035
2036 VkResult result = vn_semaphore_init_payloads(dev, sem, initial_val, alloc);
2037 if (result != VK_SUCCESS)
2038 goto out_object_base_fini;
2039
2040 if (sem->type == VK_SEMAPHORE_TYPE_TIMELINE) {
2041 result = vn_semaphore_feedback_init(dev, sem, initial_val, alloc);
2042 if (result != VK_SUCCESS)
2043 goto out_payloads_fini;
2044 }
2045
2046 VkSemaphore sem_handle = vn_semaphore_to_handle(sem);
2047 vn_async_vkCreateSemaphore(dev->primary_ring, device, pCreateInfo, NULL,
2048 &sem_handle);
2049
2050 *pSemaphore = sem_handle;
2051
2052 return VK_SUCCESS;
2053
2054 out_payloads_fini:
2055 vn_sync_payload_release(dev, &sem->permanent);
2056 vn_sync_payload_release(dev, &sem->temporary);
2057
2058 out_object_base_fini:
2059 vn_object_base_fini(&sem->base);
2060 vk_free(alloc, sem);
2061 return vn_error(dev->instance, result);
2062 }
2063
2064 void
vn_DestroySemaphore(VkDevice device,VkSemaphore semaphore,const VkAllocationCallbacks * pAllocator)2065 vn_DestroySemaphore(VkDevice device,
2066 VkSemaphore semaphore,
2067 const VkAllocationCallbacks *pAllocator)
2068 {
2069 VN_TRACE_FUNC();
2070 struct vn_device *dev = vn_device_from_handle(device);
2071 struct vn_semaphore *sem = vn_semaphore_from_handle(semaphore);
2072 const VkAllocationCallbacks *alloc =
2073 pAllocator ? pAllocator : &dev->base.base.alloc;
2074
2075 if (!sem)
2076 return;
2077
2078 vn_async_vkDestroySemaphore(dev->primary_ring, device, semaphore, NULL);
2079
2080 if (sem->type == VK_SEMAPHORE_TYPE_TIMELINE)
2081 vn_semaphore_feedback_fini(dev, sem);
2082
2083 vn_sync_payload_release(dev, &sem->permanent);
2084 vn_sync_payload_release(dev, &sem->temporary);
2085
2086 vn_object_base_fini(&sem->base);
2087 vk_free(alloc, sem);
2088 }
2089
2090 VkResult
vn_GetSemaphoreCounterValue(VkDevice device,VkSemaphore semaphore,uint64_t * pValue)2091 vn_GetSemaphoreCounterValue(VkDevice device,
2092 VkSemaphore semaphore,
2093 uint64_t *pValue)
2094 {
2095 struct vn_device *dev = vn_device_from_handle(device);
2096 struct vn_semaphore *sem = vn_semaphore_from_handle(semaphore);
2097 ASSERTED struct vn_sync_payload *payload = sem->payload;
2098
2099 assert(payload->type == VN_SYNC_TYPE_DEVICE_ONLY);
2100
2101 if (sem->feedback.slot) {
2102 simple_mtx_lock(&sem->feedback.async_wait_mtx);
2103 const uint64_t counter = vn_feedback_get_counter(sem->feedback.slot);
2104 if (sem->feedback.signaled_counter < counter) {
2105 /* When the timeline semaphore feedback slot gets signaled, the real
2106 * semaphore signal operation follows after but the signaling isr can
2107 * be deferred or preempted. To avoid racing, we let the renderer
2108 * wait for the semaphore by sending an asynchronous wait call for
2109 * the feedback value.
2110 * We also cache the counter value to only send the async call once
2111 * per counter value to prevent spamming redundant async wait calls.
2112 * The cached counter value requires a lock to ensure multiple
2113 * threads querying for the same value are guaranteed to encode after
2114 * the async wait call.
2115 *
2116 * This also helps resolve synchronization validation errors, because
2117 * the layer no longer sees any semaphore status checks and falsely
2118 * believes the caller does not sync.
2119 */
2120 VkSemaphoreWaitInfo wait_info = {
2121 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
2122 .pNext = NULL,
2123 .flags = 0,
2124 .semaphoreCount = 1,
2125 .pSemaphores = &semaphore,
2126 .pValues = &counter,
2127 };
2128
2129 vn_async_vkWaitSemaphores(dev->primary_ring, device, &wait_info,
2130 UINT64_MAX);
2131
2132 /* search pending cmds for already signaled values */
2133 simple_mtx_lock(&sem->feedback.cmd_mtx);
2134 list_for_each_entry_safe(struct vn_semaphore_feedback_cmd, sfb_cmd,
2135 &sem->feedback.pending_cmds, head) {
2136 if (counter >= vn_feedback_get_counter(sfb_cmd->src_slot)) {
2137 /* avoid over-caching more than normal runtime usage */
2138 if (sem->feedback.free_cmd_count > 5) {
2139 list_del(&sfb_cmd->head);
2140 vn_semaphore_feedback_cmd_free(dev, sfb_cmd);
2141 } else {
2142 list_move_to(&sfb_cmd->head, &sem->feedback.free_cmds);
2143 sem->feedback.free_cmd_count++;
2144 }
2145 }
2146 }
2147 simple_mtx_unlock(&sem->feedback.cmd_mtx);
2148
2149 sem->feedback.signaled_counter = counter;
2150 }
2151 simple_mtx_unlock(&sem->feedback.async_wait_mtx);
2152
2153 *pValue = counter;
2154 return VK_SUCCESS;
2155 } else {
2156 return vn_call_vkGetSemaphoreCounterValue(dev->primary_ring, device,
2157 semaphore, pValue);
2158 }
2159 }
2160
2161 VkResult
vn_SignalSemaphore(VkDevice device,const VkSemaphoreSignalInfo * pSignalInfo)2162 vn_SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo *pSignalInfo)
2163 {
2164 VN_TRACE_FUNC();
2165 struct vn_device *dev = vn_device_from_handle(device);
2166 struct vn_semaphore *sem =
2167 vn_semaphore_from_handle(pSignalInfo->semaphore);
2168
2169 vn_async_vkSignalSemaphore(dev->primary_ring, device, pSignalInfo);
2170
2171 if (sem->feedback.slot) {
2172 simple_mtx_lock(&sem->feedback.async_wait_mtx);
2173
2174 vn_feedback_set_counter(sem->feedback.slot, pSignalInfo->value);
2175 /* Update async counters. Since we're signaling, we're aligned with
2176 * the renderer.
2177 */
2178 sem->feedback.signaled_counter = pSignalInfo->value;
2179
2180 simple_mtx_unlock(&sem->feedback.async_wait_mtx);
2181 }
2182
2183 return VK_SUCCESS;
2184 }
2185
2186 static VkResult
vn_find_first_signaled_semaphore(VkDevice device,const VkSemaphore * semaphores,const uint64_t * values,uint32_t count)2187 vn_find_first_signaled_semaphore(VkDevice device,
2188 const VkSemaphore *semaphores,
2189 const uint64_t *values,
2190 uint32_t count)
2191 {
2192 for (uint32_t i = 0; i < count; i++) {
2193 uint64_t val = 0;
2194 VkResult result =
2195 vn_GetSemaphoreCounterValue(device, semaphores[i], &val);
2196 if (result != VK_SUCCESS || val >= values[i])
2197 return result;
2198 }
2199 return VK_NOT_READY;
2200 }
2201
2202 static VkResult
vn_remove_signaled_semaphores(VkDevice device,VkSemaphore * semaphores,uint64_t * values,uint32_t * count)2203 vn_remove_signaled_semaphores(VkDevice device,
2204 VkSemaphore *semaphores,
2205 uint64_t *values,
2206 uint32_t *count)
2207 {
2208 uint32_t cur = 0;
2209 for (uint32_t i = 0; i < *count; i++) {
2210 uint64_t val = 0;
2211 VkResult result =
2212 vn_GetSemaphoreCounterValue(device, semaphores[i], &val);
2213 if (result != VK_SUCCESS)
2214 return result;
2215 if (val < values[i])
2216 semaphores[cur++] = semaphores[i];
2217 }
2218
2219 *count = cur;
2220 return cur ? VK_NOT_READY : VK_SUCCESS;
2221 }
2222
2223 VkResult
vn_WaitSemaphores(VkDevice device,const VkSemaphoreWaitInfo * pWaitInfo,uint64_t timeout)2224 vn_WaitSemaphores(VkDevice device,
2225 const VkSemaphoreWaitInfo *pWaitInfo,
2226 uint64_t timeout)
2227 {
2228 VN_TRACE_FUNC();
2229 struct vn_device *dev = vn_device_from_handle(device);
2230
2231 const int64_t abs_timeout = os_time_get_absolute_timeout(timeout);
2232 VkResult result = VK_NOT_READY;
2233 if (pWaitInfo->semaphoreCount > 1 &&
2234 !(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT)) {
2235 uint32_t semaphore_count = pWaitInfo->semaphoreCount;
2236 STACK_ARRAY(VkSemaphore, semaphores, semaphore_count);
2237 STACK_ARRAY(uint64_t, values, semaphore_count);
2238 typed_memcpy(semaphores, pWaitInfo->pSemaphores, semaphore_count);
2239 typed_memcpy(values, pWaitInfo->pValues, semaphore_count);
2240
2241 struct vn_relax_state relax_state =
2242 vn_relax_init(dev->instance, VN_RELAX_REASON_SEMAPHORE);
2243 while (result == VK_NOT_READY) {
2244 result = vn_remove_signaled_semaphores(device, semaphores, values,
2245 &semaphore_count);
2246 result =
2247 vn_update_sync_result(dev, result, abs_timeout, &relax_state);
2248 }
2249 vn_relax_fini(&relax_state);
2250
2251 STACK_ARRAY_FINISH(semaphores);
2252 STACK_ARRAY_FINISH(values);
2253 } else {
2254 struct vn_relax_state relax_state =
2255 vn_relax_init(dev->instance, VN_RELAX_REASON_SEMAPHORE);
2256 while (result == VK_NOT_READY) {
2257 result = vn_find_first_signaled_semaphore(
2258 device, pWaitInfo->pSemaphores, pWaitInfo->pValues,
2259 pWaitInfo->semaphoreCount);
2260 result =
2261 vn_update_sync_result(dev, result, abs_timeout, &relax_state);
2262 }
2263 vn_relax_fini(&relax_state);
2264 }
2265
2266 return vn_result(dev->instance, result);
2267 }
2268
2269 VkResult
vn_ImportSemaphoreFdKHR(VkDevice device,const VkImportSemaphoreFdInfoKHR * pImportSemaphoreFdInfo)2270 vn_ImportSemaphoreFdKHR(
2271 VkDevice device, const VkImportSemaphoreFdInfoKHR *pImportSemaphoreFdInfo)
2272 {
2273 VN_TRACE_FUNC();
2274 struct vn_device *dev = vn_device_from_handle(device);
2275 struct vn_semaphore *sem =
2276 vn_semaphore_from_handle(pImportSemaphoreFdInfo->semaphore);
2277 ASSERTED const bool sync_file =
2278 pImportSemaphoreFdInfo->handleType ==
2279 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
2280 const int fd = pImportSemaphoreFdInfo->fd;
2281
2282 assert(sync_file);
2283
2284 if (!vn_sync_valid_fd(fd))
2285 return vn_error(dev->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE);
2286
2287 struct vn_sync_payload *temp = &sem->temporary;
2288 vn_sync_payload_release(dev, temp);
2289 temp->type = VN_SYNC_TYPE_IMPORTED_SYNC_FD;
2290 temp->fd = fd;
2291 sem->payload = temp;
2292
2293 return VK_SUCCESS;
2294 }
2295
2296 VkResult
vn_GetSemaphoreFdKHR(VkDevice device,const VkSemaphoreGetFdInfoKHR * pGetFdInfo,int * pFd)2297 vn_GetSemaphoreFdKHR(VkDevice device,
2298 const VkSemaphoreGetFdInfoKHR *pGetFdInfo,
2299 int *pFd)
2300 {
2301 VN_TRACE_FUNC();
2302 struct vn_device *dev = vn_device_from_handle(device);
2303 struct vn_semaphore *sem = vn_semaphore_from_handle(pGetFdInfo->semaphore);
2304 const bool sync_file =
2305 pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
2306 struct vn_sync_payload *payload = sem->payload;
2307
2308 assert(sync_file);
2309 assert(dev->physical_device->renderer_sync_fd.semaphore_exportable);
2310 assert(dev->physical_device->renderer_sync_fd.semaphore_importable);
2311
2312 int fd = -1;
2313 if (payload->type == VN_SYNC_TYPE_DEVICE_ONLY) {
2314 VkResult result = vn_create_sync_file(dev, &sem->external_payload, &fd);
2315 if (result != VK_SUCCESS)
2316 return vn_error(dev->instance, result);
2317
2318 #ifdef VN_USE_WSI_PLATFORM
2319 if (!dev->renderer->info.has_implicit_fencing)
2320 sync_wait(fd, -1);
2321 #endif
2322 } else {
2323 assert(payload->type == VN_SYNC_TYPE_IMPORTED_SYNC_FD);
2324
2325 /* transfer ownership of imported sync fd to save a dup */
2326 fd = payload->fd;
2327 payload->fd = -1;
2328 }
2329
2330 /* When payload->type is VN_SYNC_TYPE_IMPORTED_SYNC_FD, the current
2331 * payload is from a prior temporary sync_fd import. The permanent
2332 * payload of the sempahore might be in signaled state. So we do an
2333 * import here to ensure later wait operation is legit. With resourceId
2334 * 0, renderer does a signaled sync_fd -1 payload import on the host
2335 * semaphore.
2336 */
2337 if (payload->type == VN_SYNC_TYPE_IMPORTED_SYNC_FD) {
2338 const VkImportSemaphoreResourceInfoMESA res_info = {
2339 .sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_RESOURCE_INFO_MESA,
2340 .semaphore = pGetFdInfo->semaphore,
2341 .resourceId = 0,
2342 };
2343 vn_async_vkImportSemaphoreResourceMESA(dev->primary_ring, device,
2344 &res_info);
2345 }
2346
2347 /* perform wait operation on the host semaphore */
2348 vn_async_vkWaitSemaphoreResourceMESA(dev->primary_ring, device,
2349 pGetFdInfo->semaphore);
2350
2351 vn_sync_payload_release(dev, &sem->temporary);
2352 sem->payload = &sem->permanent;
2353
2354 *pFd = fd;
2355 return VK_SUCCESS;
2356 }
2357
2358 /* event commands */
2359
2360 static VkResult
vn_event_feedback_init(struct vn_device * dev,struct vn_event * ev)2361 vn_event_feedback_init(struct vn_device *dev, struct vn_event *ev)
2362 {
2363 struct vn_feedback_slot *slot;
2364
2365 if (VN_PERF(NO_EVENT_FEEDBACK))
2366 return VK_SUCCESS;
2367
2368 slot = vn_feedback_pool_alloc(&dev->feedback_pool, VN_FEEDBACK_TYPE_EVENT);
2369 if (!slot)
2370 return VK_ERROR_OUT_OF_HOST_MEMORY;
2371
2372 /* newly created event object is in the unsignaled state */
2373 vn_feedback_set_status(slot, VK_EVENT_RESET);
2374
2375 ev->feedback_slot = slot;
2376
2377 return VK_SUCCESS;
2378 }
2379
2380 static inline void
vn_event_feedback_fini(struct vn_device * dev,struct vn_event * ev)2381 vn_event_feedback_fini(struct vn_device *dev, struct vn_event *ev)
2382 {
2383 if (ev->feedback_slot)
2384 vn_feedback_pool_free(&dev->feedback_pool, ev->feedback_slot);
2385 }
2386
2387 VkResult
vn_CreateEvent(VkDevice device,const VkEventCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkEvent * pEvent)2388 vn_CreateEvent(VkDevice device,
2389 const VkEventCreateInfo *pCreateInfo,
2390 const VkAllocationCallbacks *pAllocator,
2391 VkEvent *pEvent)
2392 {
2393 VN_TRACE_FUNC();
2394 struct vn_device *dev = vn_device_from_handle(device);
2395 const VkAllocationCallbacks *alloc =
2396 pAllocator ? pAllocator : &dev->base.base.alloc;
2397
2398 struct vn_event *ev = vk_zalloc(alloc, sizeof(*ev), VN_DEFAULT_ALIGN,
2399 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2400 if (!ev)
2401 return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
2402
2403 vn_object_base_init(&ev->base, VK_OBJECT_TYPE_EVENT, &dev->base);
2404
2405 /* feedback is only needed to speed up host operations */
2406 if (!(pCreateInfo->flags & VK_EVENT_CREATE_DEVICE_ONLY_BIT)) {
2407 VkResult result = vn_event_feedback_init(dev, ev);
2408 if (result != VK_SUCCESS)
2409 return vn_error(dev->instance, result);
2410 }
2411
2412 VkEvent ev_handle = vn_event_to_handle(ev);
2413 vn_async_vkCreateEvent(dev->primary_ring, device, pCreateInfo, NULL,
2414 &ev_handle);
2415
2416 *pEvent = ev_handle;
2417
2418 return VK_SUCCESS;
2419 }
2420
2421 void
vn_DestroyEvent(VkDevice device,VkEvent event,const VkAllocationCallbacks * pAllocator)2422 vn_DestroyEvent(VkDevice device,
2423 VkEvent event,
2424 const VkAllocationCallbacks *pAllocator)
2425 {
2426 VN_TRACE_FUNC();
2427 struct vn_device *dev = vn_device_from_handle(device);
2428 struct vn_event *ev = vn_event_from_handle(event);
2429 const VkAllocationCallbacks *alloc =
2430 pAllocator ? pAllocator : &dev->base.base.alloc;
2431
2432 if (!ev)
2433 return;
2434
2435 vn_async_vkDestroyEvent(dev->primary_ring, device, event, NULL);
2436
2437 vn_event_feedback_fini(dev, ev);
2438
2439 vn_object_base_fini(&ev->base);
2440 vk_free(alloc, ev);
2441 }
2442
2443 VkResult
vn_GetEventStatus(VkDevice device,VkEvent event)2444 vn_GetEventStatus(VkDevice device, VkEvent event)
2445 {
2446 VN_TRACE_FUNC();
2447 struct vn_device *dev = vn_device_from_handle(device);
2448 struct vn_event *ev = vn_event_from_handle(event);
2449 VkResult result;
2450
2451 if (ev->feedback_slot)
2452 result = vn_feedback_get_status(ev->feedback_slot);
2453 else
2454 result = vn_call_vkGetEventStatus(dev->primary_ring, device, event);
2455
2456 return vn_result(dev->instance, result);
2457 }
2458
2459 VkResult
vn_SetEvent(VkDevice device,VkEvent event)2460 vn_SetEvent(VkDevice device, VkEvent event)
2461 {
2462 VN_TRACE_FUNC();
2463 struct vn_device *dev = vn_device_from_handle(device);
2464 struct vn_event *ev = vn_event_from_handle(event);
2465
2466 if (ev->feedback_slot) {
2467 vn_feedback_set_status(ev->feedback_slot, VK_EVENT_SET);
2468 vn_async_vkSetEvent(dev->primary_ring, device, event);
2469 } else {
2470 VkResult result = vn_call_vkSetEvent(dev->primary_ring, device, event);
2471 if (result != VK_SUCCESS)
2472 return vn_error(dev->instance, result);
2473 }
2474
2475 return VK_SUCCESS;
2476 }
2477
2478 VkResult
vn_ResetEvent(VkDevice device,VkEvent event)2479 vn_ResetEvent(VkDevice device, VkEvent event)
2480 {
2481 VN_TRACE_FUNC();
2482 struct vn_device *dev = vn_device_from_handle(device);
2483 struct vn_event *ev = vn_event_from_handle(event);
2484
2485 if (ev->feedback_slot) {
2486 vn_feedback_reset_status(ev->feedback_slot);
2487 vn_async_vkResetEvent(dev->primary_ring, device, event);
2488 } else {
2489 VkResult result =
2490 vn_call_vkResetEvent(dev->primary_ring, device, event);
2491 if (result != VK_SUCCESS)
2492 return vn_error(dev->instance, result);
2493 }
2494
2495 return VK_SUCCESS;
2496 }
2497