• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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