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