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