1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright 2019 Google LLC
3bf215546Sopenharmony_ci * SPDX-License-Identifier: MIT
4bf215546Sopenharmony_ci *
5bf215546Sopenharmony_ci * based in part on anv and radv which are:
6bf215546Sopenharmony_ci * Copyright © 2015 Intel Corporation
7bf215546Sopenharmony_ci * Copyright © 2016 Red Hat.
8bf215546Sopenharmony_ci * Copyright © 2016 Bas Nieuwenhuizen
9bf215546Sopenharmony_ci */
10bf215546Sopenharmony_ci
11bf215546Sopenharmony_ci#include "vn_queue.h"
12bf215546Sopenharmony_ci
13bf215546Sopenharmony_ci#include "util/libsync.h"
14bf215546Sopenharmony_ci#include "venus-protocol/vn_protocol_driver_event.h"
15bf215546Sopenharmony_ci#include "venus-protocol/vn_protocol_driver_fence.h"
16bf215546Sopenharmony_ci#include "venus-protocol/vn_protocol_driver_queue.h"
17bf215546Sopenharmony_ci#include "venus-protocol/vn_protocol_driver_semaphore.h"
18bf215546Sopenharmony_ci
19bf215546Sopenharmony_ci#include "vn_device.h"
20bf215546Sopenharmony_ci#include "vn_device_memory.h"
21bf215546Sopenharmony_ci#include "vn_renderer.h"
22bf215546Sopenharmony_ci#include "vn_wsi.h"
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci/* queue commands */
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_civoid
27bf215546Sopenharmony_civn_GetDeviceQueue2(VkDevice device,
28bf215546Sopenharmony_ci                   const VkDeviceQueueInfo2 *pQueueInfo,
29bf215546Sopenharmony_ci                   VkQueue *pQueue)
30bf215546Sopenharmony_ci{
31bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci   for (uint32_t i = 0; i < dev->queue_count; i++) {
34bf215546Sopenharmony_ci      struct vn_queue *queue = &dev->queues[i];
35bf215546Sopenharmony_ci      if (queue->family == pQueueInfo->queueFamilyIndex &&
36bf215546Sopenharmony_ci          queue->index == pQueueInfo->queueIndex &&
37bf215546Sopenharmony_ci          queue->flags == pQueueInfo->flags) {
38bf215546Sopenharmony_ci         *pQueue = vn_queue_to_handle(queue);
39bf215546Sopenharmony_ci         return;
40bf215546Sopenharmony_ci      }
41bf215546Sopenharmony_ci   }
42bf215546Sopenharmony_ci   unreachable("bad queue family/index");
43bf215546Sopenharmony_ci}
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_cistatic void
46bf215546Sopenharmony_civn_semaphore_reset_wsi(struct vn_device *dev, struct vn_semaphore *sem);
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_cistruct vn_queue_submission {
49bf215546Sopenharmony_ci   VkStructureType batch_type;
50bf215546Sopenharmony_ci   VkQueue queue;
51bf215546Sopenharmony_ci   uint32_t batch_count;
52bf215546Sopenharmony_ci   union {
53bf215546Sopenharmony_ci      const void *batches;
54bf215546Sopenharmony_ci      const VkSubmitInfo *submit_batches;
55bf215546Sopenharmony_ci      const VkBindSparseInfo *bind_sparse_batches;
56bf215546Sopenharmony_ci   };
57bf215546Sopenharmony_ci   VkFence fence;
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   uint32_t wait_semaphore_count;
60bf215546Sopenharmony_ci   uint32_t wait_wsi_count;
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci   struct {
63bf215546Sopenharmony_ci      void *storage;
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_ci      union {
66bf215546Sopenharmony_ci         void *batches;
67bf215546Sopenharmony_ci         VkSubmitInfo *submit_batches;
68bf215546Sopenharmony_ci         VkBindSparseInfo *bind_sparse_batches;
69bf215546Sopenharmony_ci      };
70bf215546Sopenharmony_ci      VkSemaphore *semaphores;
71bf215546Sopenharmony_ci   } temp;
72bf215546Sopenharmony_ci};
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_cistatic void
75bf215546Sopenharmony_civn_queue_submission_count_batch_semaphores(struct vn_queue_submission *submit,
76bf215546Sopenharmony_ci                                           uint32_t batch_index)
77bf215546Sopenharmony_ci{
78bf215546Sopenharmony_ci   union {
79bf215546Sopenharmony_ci      const VkSubmitInfo *submit_batch;
80bf215546Sopenharmony_ci      const VkBindSparseInfo *bind_sparse_batch;
81bf215546Sopenharmony_ci   } u;
82bf215546Sopenharmony_ci   const VkSemaphore *wait_sems;
83bf215546Sopenharmony_ci   uint32_t wait_count;
84bf215546Sopenharmony_ci   switch (submit->batch_type) {
85bf215546Sopenharmony_ci   case VK_STRUCTURE_TYPE_SUBMIT_INFO:
86bf215546Sopenharmony_ci      u.submit_batch = &submit->submit_batches[batch_index];
87bf215546Sopenharmony_ci      wait_sems = u.submit_batch->pWaitSemaphores;
88bf215546Sopenharmony_ci      wait_count = u.submit_batch->waitSemaphoreCount;
89bf215546Sopenharmony_ci      break;
90bf215546Sopenharmony_ci   case VK_STRUCTURE_TYPE_BIND_SPARSE_INFO:
91bf215546Sopenharmony_ci      u.bind_sparse_batch = &submit->bind_sparse_batches[batch_index];
92bf215546Sopenharmony_ci      wait_sems = u.bind_sparse_batch->pWaitSemaphores;
93bf215546Sopenharmony_ci      wait_count = u.bind_sparse_batch->waitSemaphoreCount;
94bf215546Sopenharmony_ci      break;
95bf215546Sopenharmony_ci   default:
96bf215546Sopenharmony_ci      unreachable("unexpected batch type");
97bf215546Sopenharmony_ci      break;
98bf215546Sopenharmony_ci   }
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ci   submit->wait_semaphore_count += wait_count;
101bf215546Sopenharmony_ci   for (uint32_t i = 0; i < wait_count; i++) {
102bf215546Sopenharmony_ci      struct vn_semaphore *sem = vn_semaphore_from_handle(wait_sems[i]);
103bf215546Sopenharmony_ci      const struct vn_sync_payload *payload = sem->payload;
104bf215546Sopenharmony_ci
105bf215546Sopenharmony_ci      if (payload->type == VN_SYNC_TYPE_WSI_SIGNALED)
106bf215546Sopenharmony_ci         submit->wait_wsi_count++;
107bf215546Sopenharmony_ci   }
108bf215546Sopenharmony_ci}
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_cistatic void
111bf215546Sopenharmony_civn_queue_submission_count_semaphores(struct vn_queue_submission *submit)
112bf215546Sopenharmony_ci{
113bf215546Sopenharmony_ci   submit->wait_semaphore_count = 0;
114bf215546Sopenharmony_ci   submit->wait_wsi_count = 0;
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_ci   for (uint32_t i = 0; i < submit->batch_count; i++)
117bf215546Sopenharmony_ci      vn_queue_submission_count_batch_semaphores(submit, i);
118bf215546Sopenharmony_ci}
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_cistatic VkResult
121bf215546Sopenharmony_civn_queue_submission_alloc_storage(struct vn_queue_submission *submit)
122bf215546Sopenharmony_ci{
123bf215546Sopenharmony_ci   struct vn_queue *queue = vn_queue_from_handle(submit->queue);
124bf215546Sopenharmony_ci   const VkAllocationCallbacks *alloc = &queue->device->base.base.alloc;
125bf215546Sopenharmony_ci   size_t alloc_size = 0;
126bf215546Sopenharmony_ci   size_t semaphores_offset = 0;
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ci   /* we want to filter out VN_SYNC_TYPE_WSI_SIGNALED wait semaphores */
129bf215546Sopenharmony_ci   if (submit->wait_wsi_count) {
130bf215546Sopenharmony_ci      switch (submit->batch_type) {
131bf215546Sopenharmony_ci      case VK_STRUCTURE_TYPE_SUBMIT_INFO:
132bf215546Sopenharmony_ci         alloc_size += sizeof(VkSubmitInfo) * submit->batch_count;
133bf215546Sopenharmony_ci         break;
134bf215546Sopenharmony_ci      case VK_STRUCTURE_TYPE_BIND_SPARSE_INFO:
135bf215546Sopenharmony_ci         alloc_size += sizeof(VkBindSparseInfo) * submit->batch_count;
136bf215546Sopenharmony_ci         break;
137bf215546Sopenharmony_ci      default:
138bf215546Sopenharmony_ci         unreachable("unexpected batch type");
139bf215546Sopenharmony_ci         break;
140bf215546Sopenharmony_ci      }
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci      semaphores_offset = alloc_size;
143bf215546Sopenharmony_ci      alloc_size += sizeof(*submit->temp.semaphores) *
144bf215546Sopenharmony_ci                    (submit->wait_semaphore_count - submit->wait_wsi_count);
145bf215546Sopenharmony_ci   }
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci   if (!alloc_size) {
148bf215546Sopenharmony_ci      submit->temp.storage = NULL;
149bf215546Sopenharmony_ci      return VK_SUCCESS;
150bf215546Sopenharmony_ci   }
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci   submit->temp.storage = vk_alloc(alloc, alloc_size, VN_DEFAULT_ALIGN,
153bf215546Sopenharmony_ci                                   VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
154bf215546Sopenharmony_ci   if (!submit->temp.storage)
155bf215546Sopenharmony_ci      return VK_ERROR_OUT_OF_HOST_MEMORY;
156bf215546Sopenharmony_ci
157bf215546Sopenharmony_ci   submit->temp.batches = submit->temp.storage;
158bf215546Sopenharmony_ci   submit->temp.semaphores = submit->temp.storage + semaphores_offset;
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci   return VK_SUCCESS;
161bf215546Sopenharmony_ci}
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_cistatic uint32_t
164bf215546Sopenharmony_civn_queue_submission_filter_batch_wsi_semaphores(
165bf215546Sopenharmony_ci   struct vn_queue_submission *submit,
166bf215546Sopenharmony_ci   uint32_t batch_index,
167bf215546Sopenharmony_ci   uint32_t sem_base)
168bf215546Sopenharmony_ci{
169bf215546Sopenharmony_ci   struct vn_queue *queue = vn_queue_from_handle(submit->queue);
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci   union {
172bf215546Sopenharmony_ci      VkSubmitInfo *submit_batch;
173bf215546Sopenharmony_ci      VkBindSparseInfo *bind_sparse_batch;
174bf215546Sopenharmony_ci   } u;
175bf215546Sopenharmony_ci   const VkSemaphore *src_sems;
176bf215546Sopenharmony_ci   uint32_t src_count;
177bf215546Sopenharmony_ci   switch (submit->batch_type) {
178bf215546Sopenharmony_ci   case VK_STRUCTURE_TYPE_SUBMIT_INFO:
179bf215546Sopenharmony_ci      u.submit_batch = &submit->temp.submit_batches[batch_index];
180bf215546Sopenharmony_ci      src_sems = u.submit_batch->pWaitSemaphores;
181bf215546Sopenharmony_ci      src_count = u.submit_batch->waitSemaphoreCount;
182bf215546Sopenharmony_ci      break;
183bf215546Sopenharmony_ci   case VK_STRUCTURE_TYPE_BIND_SPARSE_INFO:
184bf215546Sopenharmony_ci      u.bind_sparse_batch = &submit->temp.bind_sparse_batches[batch_index];
185bf215546Sopenharmony_ci      src_sems = u.bind_sparse_batch->pWaitSemaphores;
186bf215546Sopenharmony_ci      src_count = u.bind_sparse_batch->waitSemaphoreCount;
187bf215546Sopenharmony_ci      break;
188bf215546Sopenharmony_ci   default:
189bf215546Sopenharmony_ci      unreachable("unexpected batch type");
190bf215546Sopenharmony_ci      break;
191bf215546Sopenharmony_ci   }
192bf215546Sopenharmony_ci
193bf215546Sopenharmony_ci   VkSemaphore *dst_sems = &submit->temp.semaphores[sem_base];
194bf215546Sopenharmony_ci   uint32_t dst_count = 0;
195bf215546Sopenharmony_ci
196bf215546Sopenharmony_ci   /* filter out VN_SYNC_TYPE_WSI_SIGNALED wait semaphores */
197bf215546Sopenharmony_ci   for (uint32_t i = 0; i < src_count; i++) {
198bf215546Sopenharmony_ci      struct vn_semaphore *sem = vn_semaphore_from_handle(src_sems[i]);
199bf215546Sopenharmony_ci      const struct vn_sync_payload *payload = sem->payload;
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci      if (payload->type == VN_SYNC_TYPE_WSI_SIGNALED)
202bf215546Sopenharmony_ci         vn_semaphore_reset_wsi(queue->device, sem);
203bf215546Sopenharmony_ci      else
204bf215546Sopenharmony_ci         dst_sems[dst_count++] = src_sems[i];
205bf215546Sopenharmony_ci   }
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_ci   switch (submit->batch_type) {
208bf215546Sopenharmony_ci   case VK_STRUCTURE_TYPE_SUBMIT_INFO:
209bf215546Sopenharmony_ci      u.submit_batch->pWaitSemaphores = dst_sems;
210bf215546Sopenharmony_ci      u.submit_batch->waitSemaphoreCount = dst_count;
211bf215546Sopenharmony_ci      break;
212bf215546Sopenharmony_ci   case VK_STRUCTURE_TYPE_BIND_SPARSE_INFO:
213bf215546Sopenharmony_ci      u.bind_sparse_batch->pWaitSemaphores = dst_sems;
214bf215546Sopenharmony_ci      u.bind_sparse_batch->waitSemaphoreCount = dst_count;
215bf215546Sopenharmony_ci      break;
216bf215546Sopenharmony_ci   default:
217bf215546Sopenharmony_ci      break;
218bf215546Sopenharmony_ci   }
219bf215546Sopenharmony_ci
220bf215546Sopenharmony_ci   return dst_count;
221bf215546Sopenharmony_ci}
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_cistatic void
224bf215546Sopenharmony_civn_queue_submission_setup_batches(struct vn_queue_submission *submit)
225bf215546Sopenharmony_ci{
226bf215546Sopenharmony_ci   if (!submit->temp.storage)
227bf215546Sopenharmony_ci      return;
228bf215546Sopenharmony_ci
229bf215546Sopenharmony_ci   /* make a copy because we need to filter out WSI semaphores */
230bf215546Sopenharmony_ci   if (submit->wait_wsi_count) {
231bf215546Sopenharmony_ci      switch (submit->batch_type) {
232bf215546Sopenharmony_ci      case VK_STRUCTURE_TYPE_SUBMIT_INFO:
233bf215546Sopenharmony_ci         memcpy(submit->temp.submit_batches, submit->submit_batches,
234bf215546Sopenharmony_ci                sizeof(submit->submit_batches[0]) * submit->batch_count);
235bf215546Sopenharmony_ci         submit->submit_batches = submit->temp.submit_batches;
236bf215546Sopenharmony_ci         break;
237bf215546Sopenharmony_ci      case VK_STRUCTURE_TYPE_BIND_SPARSE_INFO:
238bf215546Sopenharmony_ci         memcpy(submit->temp.bind_sparse_batches, submit->bind_sparse_batches,
239bf215546Sopenharmony_ci                sizeof(submit->bind_sparse_batches[0]) * submit->batch_count);
240bf215546Sopenharmony_ci         submit->bind_sparse_batches = submit->temp.bind_sparse_batches;
241bf215546Sopenharmony_ci         break;
242bf215546Sopenharmony_ci      default:
243bf215546Sopenharmony_ci         unreachable("unexpected batch type");
244bf215546Sopenharmony_ci         break;
245bf215546Sopenharmony_ci      }
246bf215546Sopenharmony_ci   }
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci   uint32_t wait_sem_base = 0;
249bf215546Sopenharmony_ci   for (uint32_t i = 0; i < submit->batch_count; i++) {
250bf215546Sopenharmony_ci      if (submit->wait_wsi_count) {
251bf215546Sopenharmony_ci         wait_sem_base += vn_queue_submission_filter_batch_wsi_semaphores(
252bf215546Sopenharmony_ci            submit, i, wait_sem_base);
253bf215546Sopenharmony_ci      }
254bf215546Sopenharmony_ci   }
255bf215546Sopenharmony_ci}
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_cistatic VkResult
258bf215546Sopenharmony_civn_queue_submission_prepare_submit(struct vn_queue_submission *submit,
259bf215546Sopenharmony_ci                                   VkQueue queue,
260bf215546Sopenharmony_ci                                   uint32_t batch_count,
261bf215546Sopenharmony_ci                                   const VkSubmitInfo *submit_batches,
262bf215546Sopenharmony_ci                                   VkFence fence)
263bf215546Sopenharmony_ci{
264bf215546Sopenharmony_ci   submit->batch_type = VK_STRUCTURE_TYPE_SUBMIT_INFO;
265bf215546Sopenharmony_ci   submit->queue = queue;
266bf215546Sopenharmony_ci   submit->batch_count = batch_count;
267bf215546Sopenharmony_ci   submit->submit_batches = submit_batches;
268bf215546Sopenharmony_ci   submit->fence = fence;
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci   vn_queue_submission_count_semaphores(submit);
271bf215546Sopenharmony_ci
272bf215546Sopenharmony_ci   VkResult result = vn_queue_submission_alloc_storage(submit);
273bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
274bf215546Sopenharmony_ci      return result;
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci   vn_queue_submission_setup_batches(submit);
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci   return VK_SUCCESS;
279bf215546Sopenharmony_ci}
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_cistatic VkResult
282bf215546Sopenharmony_civn_queue_submission_prepare_bind_sparse(
283bf215546Sopenharmony_ci   struct vn_queue_submission *submit,
284bf215546Sopenharmony_ci   VkQueue queue,
285bf215546Sopenharmony_ci   uint32_t batch_count,
286bf215546Sopenharmony_ci   const VkBindSparseInfo *bind_sparse_batches,
287bf215546Sopenharmony_ci   VkFence fence)
288bf215546Sopenharmony_ci{
289bf215546Sopenharmony_ci   submit->batch_type = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO;
290bf215546Sopenharmony_ci   submit->queue = queue;
291bf215546Sopenharmony_ci   submit->batch_count = batch_count;
292bf215546Sopenharmony_ci   submit->bind_sparse_batches = bind_sparse_batches;
293bf215546Sopenharmony_ci   submit->fence = fence;
294bf215546Sopenharmony_ci
295bf215546Sopenharmony_ci   vn_queue_submission_count_semaphores(submit);
296bf215546Sopenharmony_ci
297bf215546Sopenharmony_ci   VkResult result = vn_queue_submission_alloc_storage(submit);
298bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
299bf215546Sopenharmony_ci      return result;
300bf215546Sopenharmony_ci
301bf215546Sopenharmony_ci   vn_queue_submission_setup_batches(submit);
302bf215546Sopenharmony_ci
303bf215546Sopenharmony_ci   return VK_SUCCESS;
304bf215546Sopenharmony_ci}
305bf215546Sopenharmony_ci
306bf215546Sopenharmony_cistatic void
307bf215546Sopenharmony_civn_queue_submission_cleanup(struct vn_queue_submission *submit)
308bf215546Sopenharmony_ci{
309bf215546Sopenharmony_ci   struct vn_queue *queue = vn_queue_from_handle(submit->queue);
310bf215546Sopenharmony_ci   const VkAllocationCallbacks *alloc = &queue->device->base.base.alloc;
311bf215546Sopenharmony_ci
312bf215546Sopenharmony_ci   vk_free(alloc, submit->temp.storage);
313bf215546Sopenharmony_ci}
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_cistatic inline uint32_t
316bf215546Sopenharmony_civn_queue_family_array_index(struct vn_queue *queue)
317bf215546Sopenharmony_ci{
318bf215546Sopenharmony_ci   for (uint32_t i = 0; i < queue->device->queue_family_count; i++) {
319bf215546Sopenharmony_ci      if (queue->device->queue_families[i] == queue->family)
320bf215546Sopenharmony_ci         return i;
321bf215546Sopenharmony_ci   }
322bf215546Sopenharmony_ci   unreachable("invalid queue");
323bf215546Sopenharmony_ci}
324bf215546Sopenharmony_ci
325bf215546Sopenharmony_cistatic VkResult
326bf215546Sopenharmony_civn_queue_submit(struct vn_instance *instance,
327bf215546Sopenharmony_ci                VkQueue queue_handle,
328bf215546Sopenharmony_ci                uint32_t batch_count,
329bf215546Sopenharmony_ci                const VkSubmitInfo *batches,
330bf215546Sopenharmony_ci                VkFence fence_handle,
331bf215546Sopenharmony_ci                bool sync_submit)
332bf215546Sopenharmony_ci{
333bf215546Sopenharmony_ci   /* skip no-op submit */
334bf215546Sopenharmony_ci   if (!batch_count && fence_handle == VK_NULL_HANDLE)
335bf215546Sopenharmony_ci      return VK_SUCCESS;
336bf215546Sopenharmony_ci
337bf215546Sopenharmony_ci   if (sync_submit) {
338bf215546Sopenharmony_ci      return vn_call_vkQueueSubmit(instance, queue_handle, batch_count,
339bf215546Sopenharmony_ci                                   batches, fence_handle);
340bf215546Sopenharmony_ci   }
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_ci   vn_async_vkQueueSubmit(instance, queue_handle, batch_count, batches,
343bf215546Sopenharmony_ci                          fence_handle);
344bf215546Sopenharmony_ci   return VK_SUCCESS;
345bf215546Sopenharmony_ci}
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ciVkResult
348bf215546Sopenharmony_civn_QueueSubmit(VkQueue _queue,
349bf215546Sopenharmony_ci               uint32_t submitCount,
350bf215546Sopenharmony_ci               const VkSubmitInfo *pSubmits,
351bf215546Sopenharmony_ci               VkFence _fence)
352bf215546Sopenharmony_ci{
353bf215546Sopenharmony_ci   VN_TRACE_FUNC();
354bf215546Sopenharmony_ci   struct vn_queue *queue = vn_queue_from_handle(_queue);
355bf215546Sopenharmony_ci   struct vn_device *dev = queue->device;
356bf215546Sopenharmony_ci   struct vn_fence *fence = vn_fence_from_handle(_fence);
357bf215546Sopenharmony_ci   const bool external_fence = fence && fence->is_external;
358bf215546Sopenharmony_ci   const bool feedback_fence = fence && fence->feedback.slot;
359bf215546Sopenharmony_ci   struct vn_queue_submission submit;
360bf215546Sopenharmony_ci   const struct vn_device_memory *wsi_mem = NULL;
361bf215546Sopenharmony_ci   bool sync_submit;
362bf215546Sopenharmony_ci   VkResult result;
363bf215546Sopenharmony_ci
364bf215546Sopenharmony_ci   result = vn_queue_submission_prepare_submit(&submit, _queue, submitCount,
365bf215546Sopenharmony_ci                                               pSubmits, _fence);
366bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
367bf215546Sopenharmony_ci      return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
368bf215546Sopenharmony_ci
369bf215546Sopenharmony_ci   if (submit.batch_count == 1) {
370bf215546Sopenharmony_ci      const struct wsi_memory_signal_submit_info *info = vk_find_struct_const(
371bf215546Sopenharmony_ci         submit.submit_batches[0].pNext, WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA);
372bf215546Sopenharmony_ci      if (info) {
373bf215546Sopenharmony_ci         wsi_mem = vn_device_memory_from_handle(info->memory);
374bf215546Sopenharmony_ci         assert(!wsi_mem->base_memory && wsi_mem->base_bo);
375bf215546Sopenharmony_ci      }
376bf215546Sopenharmony_ci   }
377bf215546Sopenharmony_ci
378bf215546Sopenharmony_ci   /* force synchronous submission if any of the below applies:
379bf215546Sopenharmony_ci    * - struct wsi_memory_signal_submit_info
380bf215546Sopenharmony_ci    * - fence is an external fence
381bf215546Sopenharmony_ci    * - NO_ASYNC_QUEUE_SUBMIT perf option enabled
382bf215546Sopenharmony_ci    */
383bf215546Sopenharmony_ci   sync_submit = wsi_mem || external_fence || VN_PERF(NO_ASYNC_QUEUE_SUBMIT);
384bf215546Sopenharmony_ci
385bf215546Sopenharmony_ci   /* if the original submission involves a feedback fence:
386bf215546Sopenharmony_ci    * - defer the feedback fence to another submit to avoid deep copy
387bf215546Sopenharmony_ci    * - defer the potential sync_submit to the feedback fence submission
388bf215546Sopenharmony_ci    */
389bf215546Sopenharmony_ci   result = vn_queue_submit(dev->instance, submit.queue, submit.batch_count,
390bf215546Sopenharmony_ci                            submit.submit_batches,
391bf215546Sopenharmony_ci                            feedback_fence ? VK_NULL_HANDLE : submit.fence,
392bf215546Sopenharmony_ci                            !feedback_fence && sync_submit);
393bf215546Sopenharmony_ci   if (result != VK_SUCCESS) {
394bf215546Sopenharmony_ci      vn_queue_submission_cleanup(&submit);
395bf215546Sopenharmony_ci      return vn_error(dev->instance, result);
396bf215546Sopenharmony_ci   }
397bf215546Sopenharmony_ci
398bf215546Sopenharmony_ci   /* TODO intercept original submit batches to append the fence feedback cmd
399bf215546Sopenharmony_ci    * with a per-queue cached submission builder to avoid transient allocs.
400bf215546Sopenharmony_ci    *
401bf215546Sopenharmony_ci    * vn_queue_submission bits must be fixed for VkTimelineSemaphoreSubmitInfo
402bf215546Sopenharmony_ci    * before adding timeline semaphore feedback.
403bf215546Sopenharmony_ci    */
404bf215546Sopenharmony_ci   if (feedback_fence) {
405bf215546Sopenharmony_ci      const uint32_t feedback_cmd_index = vn_queue_family_array_index(queue);
406bf215546Sopenharmony_ci      const VkSubmitInfo info = {
407bf215546Sopenharmony_ci         .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
408bf215546Sopenharmony_ci         .pNext = NULL,
409bf215546Sopenharmony_ci         .waitSemaphoreCount = 0,
410bf215546Sopenharmony_ci         .pWaitSemaphores = NULL,
411bf215546Sopenharmony_ci         .pWaitDstStageMask = NULL,
412bf215546Sopenharmony_ci         .commandBufferCount = 1,
413bf215546Sopenharmony_ci         .pCommandBuffers = &fence->feedback.commands[feedback_cmd_index],
414bf215546Sopenharmony_ci      };
415bf215546Sopenharmony_ci      result = vn_queue_submit(dev->instance, submit.queue, 1, &info,
416bf215546Sopenharmony_ci                               submit.fence, sync_submit);
417bf215546Sopenharmony_ci      if (result != VK_SUCCESS) {
418bf215546Sopenharmony_ci         vn_queue_submission_cleanup(&submit);
419bf215546Sopenharmony_ci         return vn_error(dev->instance, result);
420bf215546Sopenharmony_ci      }
421bf215546Sopenharmony_ci   }
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci   if (wsi_mem) {
424bf215546Sopenharmony_ci      /* XXX this is always false and kills the performance */
425bf215546Sopenharmony_ci      if (dev->instance->renderer->info.has_implicit_fencing) {
426bf215546Sopenharmony_ci         vn_renderer_submit(dev->renderer, &(const struct vn_renderer_submit){
427bf215546Sopenharmony_ci                                              .bos = &wsi_mem->base_bo,
428bf215546Sopenharmony_ci                                              .bo_count = 1,
429bf215546Sopenharmony_ci                                           });
430bf215546Sopenharmony_ci      } else {
431bf215546Sopenharmony_ci         if (VN_DEBUG(WSI)) {
432bf215546Sopenharmony_ci            static uint32_t ratelimit;
433bf215546Sopenharmony_ci            if (ratelimit < 10) {
434bf215546Sopenharmony_ci               vn_log(dev->instance,
435bf215546Sopenharmony_ci                      "forcing vkQueueWaitIdle before presenting");
436bf215546Sopenharmony_ci               ratelimit++;
437bf215546Sopenharmony_ci            }
438bf215546Sopenharmony_ci         }
439bf215546Sopenharmony_ci
440bf215546Sopenharmony_ci         vn_QueueWaitIdle(submit.queue);
441bf215546Sopenharmony_ci      }
442bf215546Sopenharmony_ci   }
443bf215546Sopenharmony_ci
444bf215546Sopenharmony_ci   vn_queue_submission_cleanup(&submit);
445bf215546Sopenharmony_ci
446bf215546Sopenharmony_ci   return VK_SUCCESS;
447bf215546Sopenharmony_ci}
448bf215546Sopenharmony_ci
449bf215546Sopenharmony_ciVkResult
450bf215546Sopenharmony_civn_QueueBindSparse(VkQueue _queue,
451bf215546Sopenharmony_ci                   uint32_t bindInfoCount,
452bf215546Sopenharmony_ci                   const VkBindSparseInfo *pBindInfo,
453bf215546Sopenharmony_ci                   VkFence fence)
454bf215546Sopenharmony_ci{
455bf215546Sopenharmony_ci   VN_TRACE_FUNC();
456bf215546Sopenharmony_ci   struct vn_queue *queue = vn_queue_from_handle(_queue);
457bf215546Sopenharmony_ci   struct vn_device *dev = queue->device;
458bf215546Sopenharmony_ci
459bf215546Sopenharmony_ci   /* TODO allow sparse resource along with sync feedback */
460bf215546Sopenharmony_ci   assert(VN_PERF(NO_FENCE_FEEDBACK));
461bf215546Sopenharmony_ci
462bf215546Sopenharmony_ci   struct vn_queue_submission submit;
463bf215546Sopenharmony_ci   VkResult result = vn_queue_submission_prepare_bind_sparse(
464bf215546Sopenharmony_ci      &submit, _queue, bindInfoCount, pBindInfo, fence);
465bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
466bf215546Sopenharmony_ci      return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
467bf215546Sopenharmony_ci
468bf215546Sopenharmony_ci   result = vn_call_vkQueueBindSparse(
469bf215546Sopenharmony_ci      dev->instance, submit.queue, submit.batch_count,
470bf215546Sopenharmony_ci      submit.bind_sparse_batches, submit.fence);
471bf215546Sopenharmony_ci   if (result != VK_SUCCESS) {
472bf215546Sopenharmony_ci      vn_queue_submission_cleanup(&submit);
473bf215546Sopenharmony_ci      return vn_error(dev->instance, result);
474bf215546Sopenharmony_ci   }
475bf215546Sopenharmony_ci
476bf215546Sopenharmony_ci   vn_queue_submission_cleanup(&submit);
477bf215546Sopenharmony_ci
478bf215546Sopenharmony_ci   return VK_SUCCESS;
479bf215546Sopenharmony_ci}
480bf215546Sopenharmony_ci
481bf215546Sopenharmony_ciVkResult
482bf215546Sopenharmony_civn_QueueWaitIdle(VkQueue _queue)
483bf215546Sopenharmony_ci{
484bf215546Sopenharmony_ci   VN_TRACE_FUNC();
485bf215546Sopenharmony_ci   struct vn_queue *queue = vn_queue_from_handle(_queue);
486bf215546Sopenharmony_ci   VkDevice device = vn_device_to_handle(queue->device);
487bf215546Sopenharmony_ci
488bf215546Sopenharmony_ci   VkResult result = vn_QueueSubmit(_queue, 0, NULL, queue->wait_fence);
489bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
490bf215546Sopenharmony_ci      return result;
491bf215546Sopenharmony_ci
492bf215546Sopenharmony_ci   result = vn_WaitForFences(device, 1, &queue->wait_fence, true, UINT64_MAX);
493bf215546Sopenharmony_ci   vn_ResetFences(device, 1, &queue->wait_fence);
494bf215546Sopenharmony_ci
495bf215546Sopenharmony_ci   return vn_result(queue->device->instance, result);
496bf215546Sopenharmony_ci}
497bf215546Sopenharmony_ci
498bf215546Sopenharmony_ci/* fence commands */
499bf215546Sopenharmony_ci
500bf215546Sopenharmony_cistatic void
501bf215546Sopenharmony_civn_sync_payload_release(struct vn_device *dev,
502bf215546Sopenharmony_ci                        struct vn_sync_payload *payload)
503bf215546Sopenharmony_ci{
504bf215546Sopenharmony_ci   payload->type = VN_SYNC_TYPE_INVALID;
505bf215546Sopenharmony_ci}
506bf215546Sopenharmony_ci
507bf215546Sopenharmony_cistatic VkResult
508bf215546Sopenharmony_civn_fence_init_payloads(struct vn_device *dev,
509bf215546Sopenharmony_ci                       struct vn_fence *fence,
510bf215546Sopenharmony_ci                       bool signaled,
511bf215546Sopenharmony_ci                       const VkAllocationCallbacks *alloc)
512bf215546Sopenharmony_ci{
513bf215546Sopenharmony_ci   fence->permanent.type = VN_SYNC_TYPE_DEVICE_ONLY;
514bf215546Sopenharmony_ci   fence->temporary.type = VN_SYNC_TYPE_INVALID;
515bf215546Sopenharmony_ci   fence->payload = &fence->permanent;
516bf215546Sopenharmony_ci
517bf215546Sopenharmony_ci   return VK_SUCCESS;
518bf215546Sopenharmony_ci}
519bf215546Sopenharmony_ci
520bf215546Sopenharmony_civoid
521bf215546Sopenharmony_civn_fence_signal_wsi(struct vn_device *dev, struct vn_fence *fence)
522bf215546Sopenharmony_ci{
523bf215546Sopenharmony_ci   struct vn_sync_payload *temp = &fence->temporary;
524bf215546Sopenharmony_ci
525bf215546Sopenharmony_ci   vn_sync_payload_release(dev, temp);
526bf215546Sopenharmony_ci   temp->type = VN_SYNC_TYPE_WSI_SIGNALED;
527bf215546Sopenharmony_ci   fence->payload = temp;
528bf215546Sopenharmony_ci}
529bf215546Sopenharmony_ci
530bf215546Sopenharmony_cistatic VkResult
531bf215546Sopenharmony_civn_fence_feedback_init(struct vn_device *dev,
532bf215546Sopenharmony_ci                       struct vn_fence *fence,
533bf215546Sopenharmony_ci                       bool signaled,
534bf215546Sopenharmony_ci                       const VkAllocationCallbacks *alloc)
535bf215546Sopenharmony_ci{
536bf215546Sopenharmony_ci   VkDevice dev_handle = vn_device_to_handle(dev);
537bf215546Sopenharmony_ci   struct vn_feedback_slot *slot;
538bf215546Sopenharmony_ci   VkCommandBuffer *cmd_handles;
539bf215546Sopenharmony_ci   VkResult result;
540bf215546Sopenharmony_ci
541bf215546Sopenharmony_ci   if (fence->is_external)
542bf215546Sopenharmony_ci      return VK_SUCCESS;
543bf215546Sopenharmony_ci
544bf215546Sopenharmony_ci   /* Fence feedback implementation relies on vkWaitForFences to cover the gap
545bf215546Sopenharmony_ci    * between feedback slot signaling and the actual fence signal operation.
546bf215546Sopenharmony_ci    */
547bf215546Sopenharmony_ci   if (unlikely(!dev->instance->renderer->info.allow_vk_wait_syncs))
548bf215546Sopenharmony_ci      return VK_SUCCESS;
549bf215546Sopenharmony_ci
550bf215546Sopenharmony_ci   if (VN_PERF(NO_FENCE_FEEDBACK))
551bf215546Sopenharmony_ci      return VK_SUCCESS;
552bf215546Sopenharmony_ci
553bf215546Sopenharmony_ci   slot = vn_feedback_pool_alloc(&dev->feedback_pool, VN_FEEDBACK_TYPE_FENCE);
554bf215546Sopenharmony_ci   if (!slot)
555bf215546Sopenharmony_ci      return VK_ERROR_OUT_OF_HOST_MEMORY;
556bf215546Sopenharmony_ci
557bf215546Sopenharmony_ci   vn_feedback_set_status(slot, signaled ? VK_SUCCESS : VK_NOT_READY);
558bf215546Sopenharmony_ci
559bf215546Sopenharmony_ci   cmd_handles =
560bf215546Sopenharmony_ci      vk_zalloc(alloc, sizeof(*cmd_handles) * dev->queue_family_count,
561bf215546Sopenharmony_ci                VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
562bf215546Sopenharmony_ci   if (!cmd_handles) {
563bf215546Sopenharmony_ci      vn_feedback_pool_free(&dev->feedback_pool, slot);
564bf215546Sopenharmony_ci      return VK_ERROR_OUT_OF_HOST_MEMORY;
565bf215546Sopenharmony_ci   }
566bf215546Sopenharmony_ci
567bf215546Sopenharmony_ci   for (uint32_t i = 0; i < dev->queue_family_count; i++) {
568bf215546Sopenharmony_ci      result = vn_feedback_fence_cmd_alloc(dev_handle, &dev->cmd_pools[i],
569bf215546Sopenharmony_ci                                           slot, &cmd_handles[i]);
570bf215546Sopenharmony_ci      if (result != VK_SUCCESS) {
571bf215546Sopenharmony_ci         for (uint32_t j = 0; j < i; j++) {
572bf215546Sopenharmony_ci            vn_feedback_fence_cmd_free(dev_handle, &dev->cmd_pools[j],
573bf215546Sopenharmony_ci                                       cmd_handles[j]);
574bf215546Sopenharmony_ci         }
575bf215546Sopenharmony_ci         break;
576bf215546Sopenharmony_ci      }
577bf215546Sopenharmony_ci   }
578bf215546Sopenharmony_ci
579bf215546Sopenharmony_ci   if (result != VK_SUCCESS) {
580bf215546Sopenharmony_ci      vk_free(alloc, cmd_handles);
581bf215546Sopenharmony_ci      vn_feedback_pool_free(&dev->feedback_pool, slot);
582bf215546Sopenharmony_ci      return result;
583bf215546Sopenharmony_ci   }
584bf215546Sopenharmony_ci
585bf215546Sopenharmony_ci   fence->feedback.slot = slot;
586bf215546Sopenharmony_ci   fence->feedback.commands = cmd_handles;
587bf215546Sopenharmony_ci
588bf215546Sopenharmony_ci   return VK_SUCCESS;
589bf215546Sopenharmony_ci}
590bf215546Sopenharmony_ci
591bf215546Sopenharmony_cistatic void
592bf215546Sopenharmony_civn_fence_feedback_fini(struct vn_device *dev,
593bf215546Sopenharmony_ci                       struct vn_fence *fence,
594bf215546Sopenharmony_ci                       const VkAllocationCallbacks *alloc)
595bf215546Sopenharmony_ci{
596bf215546Sopenharmony_ci   VkDevice dev_handle = vn_device_to_handle(dev);
597bf215546Sopenharmony_ci
598bf215546Sopenharmony_ci   if (!fence->feedback.slot)
599bf215546Sopenharmony_ci      return;
600bf215546Sopenharmony_ci
601bf215546Sopenharmony_ci   for (uint32_t i = 0; i < dev->queue_family_count; i++) {
602bf215546Sopenharmony_ci      vn_feedback_fence_cmd_free(dev_handle, &dev->cmd_pools[i],
603bf215546Sopenharmony_ci                                 fence->feedback.commands[i]);
604bf215546Sopenharmony_ci   }
605bf215546Sopenharmony_ci
606bf215546Sopenharmony_ci   vn_feedback_pool_free(&dev->feedback_pool, fence->feedback.slot);
607bf215546Sopenharmony_ci
608bf215546Sopenharmony_ci   vk_free(alloc, fence->feedback.commands);
609bf215546Sopenharmony_ci}
610bf215546Sopenharmony_ci
611bf215546Sopenharmony_ciVkResult
612bf215546Sopenharmony_civn_CreateFence(VkDevice device,
613bf215546Sopenharmony_ci               const VkFenceCreateInfo *pCreateInfo,
614bf215546Sopenharmony_ci               const VkAllocationCallbacks *pAllocator,
615bf215546Sopenharmony_ci               VkFence *pFence)
616bf215546Sopenharmony_ci{
617bf215546Sopenharmony_ci   VN_TRACE_FUNC();
618bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
619bf215546Sopenharmony_ci   const VkAllocationCallbacks *alloc =
620bf215546Sopenharmony_ci      pAllocator ? pAllocator : &dev->base.base.alloc;
621bf215546Sopenharmony_ci   const bool signaled = pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT;
622bf215546Sopenharmony_ci   VkResult result;
623bf215546Sopenharmony_ci
624bf215546Sopenharmony_ci   struct vn_fence *fence = vk_zalloc(alloc, sizeof(*fence), VN_DEFAULT_ALIGN,
625bf215546Sopenharmony_ci                                      VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
626bf215546Sopenharmony_ci   if (!fence)
627bf215546Sopenharmony_ci      return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
628bf215546Sopenharmony_ci
629bf215546Sopenharmony_ci   vn_object_base_init(&fence->base, VK_OBJECT_TYPE_FENCE, &dev->base);
630bf215546Sopenharmony_ci
631bf215546Sopenharmony_ci   const struct VkExportFenceCreateInfo *export_info =
632bf215546Sopenharmony_ci      vk_find_struct_const(pCreateInfo->pNext, EXPORT_FENCE_CREATE_INFO);
633bf215546Sopenharmony_ci   VkFenceCreateInfo local_create_info;
634bf215546Sopenharmony_ci   if (export_info) {
635bf215546Sopenharmony_ci      local_create_info = *pCreateInfo;
636bf215546Sopenharmony_ci      local_create_info.pNext = NULL;
637bf215546Sopenharmony_ci      pCreateInfo = &local_create_info;
638bf215546Sopenharmony_ci
639bf215546Sopenharmony_ci      fence->is_external = !!export_info->handleTypes;
640bf215546Sopenharmony_ci   }
641bf215546Sopenharmony_ci
642bf215546Sopenharmony_ci   result = vn_fence_init_payloads(dev, fence, signaled, alloc);
643bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
644bf215546Sopenharmony_ci      goto out_object_base_fini;
645bf215546Sopenharmony_ci
646bf215546Sopenharmony_ci   result = vn_fence_feedback_init(dev, fence, signaled, alloc);
647bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
648bf215546Sopenharmony_ci      goto out_payloads_fini;
649bf215546Sopenharmony_ci
650bf215546Sopenharmony_ci   *pFence = vn_fence_to_handle(fence);
651bf215546Sopenharmony_ci   vn_async_vkCreateFence(dev->instance, device, pCreateInfo, NULL, pFence);
652bf215546Sopenharmony_ci
653bf215546Sopenharmony_ci   return VK_SUCCESS;
654bf215546Sopenharmony_ci
655bf215546Sopenharmony_ciout_payloads_fini:
656bf215546Sopenharmony_ci   vn_sync_payload_release(dev, &fence->permanent);
657bf215546Sopenharmony_ci   vn_sync_payload_release(dev, &fence->temporary);
658bf215546Sopenharmony_ci
659bf215546Sopenharmony_ciout_object_base_fini:
660bf215546Sopenharmony_ci   vn_object_base_fini(&fence->base);
661bf215546Sopenharmony_ci   vk_free(alloc, fence);
662bf215546Sopenharmony_ci   return vn_error(dev->instance, result);
663bf215546Sopenharmony_ci}
664bf215546Sopenharmony_ci
665bf215546Sopenharmony_civoid
666bf215546Sopenharmony_civn_DestroyFence(VkDevice device,
667bf215546Sopenharmony_ci                VkFence _fence,
668bf215546Sopenharmony_ci                const VkAllocationCallbacks *pAllocator)
669bf215546Sopenharmony_ci{
670bf215546Sopenharmony_ci   VN_TRACE_FUNC();
671bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
672bf215546Sopenharmony_ci   struct vn_fence *fence = vn_fence_from_handle(_fence);
673bf215546Sopenharmony_ci   const VkAllocationCallbacks *alloc =
674bf215546Sopenharmony_ci      pAllocator ? pAllocator : &dev->base.base.alloc;
675bf215546Sopenharmony_ci
676bf215546Sopenharmony_ci   if (!fence)
677bf215546Sopenharmony_ci      return;
678bf215546Sopenharmony_ci
679bf215546Sopenharmony_ci   vn_async_vkDestroyFence(dev->instance, device, _fence, NULL);
680bf215546Sopenharmony_ci
681bf215546Sopenharmony_ci   vn_fence_feedback_fini(dev, fence, alloc);
682bf215546Sopenharmony_ci
683bf215546Sopenharmony_ci   vn_sync_payload_release(dev, &fence->permanent);
684bf215546Sopenharmony_ci   vn_sync_payload_release(dev, &fence->temporary);
685bf215546Sopenharmony_ci
686bf215546Sopenharmony_ci   vn_object_base_fini(&fence->base);
687bf215546Sopenharmony_ci   vk_free(alloc, fence);
688bf215546Sopenharmony_ci}
689bf215546Sopenharmony_ci
690bf215546Sopenharmony_ciVkResult
691bf215546Sopenharmony_civn_ResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences)
692bf215546Sopenharmony_ci{
693bf215546Sopenharmony_ci   VN_TRACE_FUNC();
694bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
695bf215546Sopenharmony_ci
696bf215546Sopenharmony_ci   /* TODO if the fence is shared-by-ref, this needs to be synchronous */
697bf215546Sopenharmony_ci   if (false)
698bf215546Sopenharmony_ci      vn_call_vkResetFences(dev->instance, device, fenceCount, pFences);
699bf215546Sopenharmony_ci   else
700bf215546Sopenharmony_ci      vn_async_vkResetFences(dev->instance, device, fenceCount, pFences);
701bf215546Sopenharmony_ci
702bf215546Sopenharmony_ci   for (uint32_t i = 0; i < fenceCount; i++) {
703bf215546Sopenharmony_ci      struct vn_fence *fence = vn_fence_from_handle(pFences[i]);
704bf215546Sopenharmony_ci      struct vn_sync_payload *perm = &fence->permanent;
705bf215546Sopenharmony_ci
706bf215546Sopenharmony_ci      vn_sync_payload_release(dev, &fence->temporary);
707bf215546Sopenharmony_ci
708bf215546Sopenharmony_ci      assert(perm->type == VN_SYNC_TYPE_DEVICE_ONLY);
709bf215546Sopenharmony_ci      fence->payload = perm;
710bf215546Sopenharmony_ci
711bf215546Sopenharmony_ci      if (fence->feedback.slot)
712bf215546Sopenharmony_ci         vn_feedback_reset_status(fence->feedback.slot);
713bf215546Sopenharmony_ci   }
714bf215546Sopenharmony_ci
715bf215546Sopenharmony_ci   return VK_SUCCESS;
716bf215546Sopenharmony_ci}
717bf215546Sopenharmony_ci
718bf215546Sopenharmony_ciVkResult
719bf215546Sopenharmony_civn_GetFenceStatus(VkDevice device, VkFence _fence)
720bf215546Sopenharmony_ci{
721bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
722bf215546Sopenharmony_ci   struct vn_fence *fence = vn_fence_from_handle(_fence);
723bf215546Sopenharmony_ci   struct vn_sync_payload *payload = fence->payload;
724bf215546Sopenharmony_ci
725bf215546Sopenharmony_ci   VkResult result;
726bf215546Sopenharmony_ci   switch (payload->type) {
727bf215546Sopenharmony_ci   case VN_SYNC_TYPE_DEVICE_ONLY:
728bf215546Sopenharmony_ci      if (fence->feedback.slot) {
729bf215546Sopenharmony_ci         result = vn_feedback_get_status(fence->feedback.slot);
730bf215546Sopenharmony_ci         if (result == VK_SUCCESS) {
731bf215546Sopenharmony_ci            /* When fence feedback slot gets signaled, the real fence
732bf215546Sopenharmony_ci             * signal operation follows after but the signaling isr can be
733bf215546Sopenharmony_ci             * deferred or preempted. To avoid theoretical racing, we let
734bf215546Sopenharmony_ci             * the renderer wait for the fence. This also helps resolve
735bf215546Sopenharmony_ci             * synchronization validation errors, because the layer no
736bf215546Sopenharmony_ci             * longer sees any fence status checks and falsely believes the
737bf215546Sopenharmony_ci             * caller does not sync.
738bf215546Sopenharmony_ci             */
739bf215546Sopenharmony_ci            vn_async_vkWaitForFences(dev->instance, device, 1, &_fence,
740bf215546Sopenharmony_ci                                     VK_TRUE, UINT64_MAX);
741bf215546Sopenharmony_ci         }
742bf215546Sopenharmony_ci      } else {
743bf215546Sopenharmony_ci         result = vn_call_vkGetFenceStatus(dev->instance, device, _fence);
744bf215546Sopenharmony_ci      }
745bf215546Sopenharmony_ci      break;
746bf215546Sopenharmony_ci   case VN_SYNC_TYPE_WSI_SIGNALED:
747bf215546Sopenharmony_ci      result = VK_SUCCESS;
748bf215546Sopenharmony_ci      break;
749bf215546Sopenharmony_ci   default:
750bf215546Sopenharmony_ci      unreachable("unexpected fence payload type");
751bf215546Sopenharmony_ci      break;
752bf215546Sopenharmony_ci   }
753bf215546Sopenharmony_ci
754bf215546Sopenharmony_ci   return vn_result(dev->instance, result);
755bf215546Sopenharmony_ci}
756bf215546Sopenharmony_ci
757bf215546Sopenharmony_cistatic VkResult
758bf215546Sopenharmony_civn_find_first_signaled_fence(VkDevice device,
759bf215546Sopenharmony_ci                             const VkFence *fences,
760bf215546Sopenharmony_ci                             uint32_t count)
761bf215546Sopenharmony_ci{
762bf215546Sopenharmony_ci   for (uint32_t i = 0; i < count; i++) {
763bf215546Sopenharmony_ci      VkResult result = vn_GetFenceStatus(device, fences[i]);
764bf215546Sopenharmony_ci      if (result == VK_SUCCESS || result < 0)
765bf215546Sopenharmony_ci         return result;
766bf215546Sopenharmony_ci   }
767bf215546Sopenharmony_ci   return VK_NOT_READY;
768bf215546Sopenharmony_ci}
769bf215546Sopenharmony_ci
770bf215546Sopenharmony_cistatic VkResult
771bf215546Sopenharmony_civn_remove_signaled_fences(VkDevice device, VkFence *fences, uint32_t *count)
772bf215546Sopenharmony_ci{
773bf215546Sopenharmony_ci   uint32_t cur = 0;
774bf215546Sopenharmony_ci   for (uint32_t i = 0; i < *count; i++) {
775bf215546Sopenharmony_ci      VkResult result = vn_GetFenceStatus(device, fences[i]);
776bf215546Sopenharmony_ci      if (result != VK_SUCCESS) {
777bf215546Sopenharmony_ci         if (result < 0)
778bf215546Sopenharmony_ci            return result;
779bf215546Sopenharmony_ci         fences[cur++] = fences[i];
780bf215546Sopenharmony_ci      }
781bf215546Sopenharmony_ci   }
782bf215546Sopenharmony_ci
783bf215546Sopenharmony_ci   *count = cur;
784bf215546Sopenharmony_ci   return cur ? VK_NOT_READY : VK_SUCCESS;
785bf215546Sopenharmony_ci}
786bf215546Sopenharmony_ci
787bf215546Sopenharmony_cistatic VkResult
788bf215546Sopenharmony_civn_update_sync_result(VkResult result, int64_t abs_timeout, uint32_t *iter)
789bf215546Sopenharmony_ci{
790bf215546Sopenharmony_ci   switch (result) {
791bf215546Sopenharmony_ci   case VK_NOT_READY:
792bf215546Sopenharmony_ci      if (abs_timeout != OS_TIMEOUT_INFINITE &&
793bf215546Sopenharmony_ci          os_time_get_nano() >= abs_timeout)
794bf215546Sopenharmony_ci         result = VK_TIMEOUT;
795bf215546Sopenharmony_ci      else
796bf215546Sopenharmony_ci         vn_relax(iter, "client");
797bf215546Sopenharmony_ci      break;
798bf215546Sopenharmony_ci   default:
799bf215546Sopenharmony_ci      assert(result == VK_SUCCESS || result < 0);
800bf215546Sopenharmony_ci      break;
801bf215546Sopenharmony_ci   }
802bf215546Sopenharmony_ci
803bf215546Sopenharmony_ci   return result;
804bf215546Sopenharmony_ci}
805bf215546Sopenharmony_ci
806bf215546Sopenharmony_ciVkResult
807bf215546Sopenharmony_civn_WaitForFences(VkDevice device,
808bf215546Sopenharmony_ci                 uint32_t fenceCount,
809bf215546Sopenharmony_ci                 const VkFence *pFences,
810bf215546Sopenharmony_ci                 VkBool32 waitAll,
811bf215546Sopenharmony_ci                 uint64_t timeout)
812bf215546Sopenharmony_ci{
813bf215546Sopenharmony_ci   VN_TRACE_FUNC();
814bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
815bf215546Sopenharmony_ci   const VkAllocationCallbacks *alloc = &dev->base.base.alloc;
816bf215546Sopenharmony_ci
817bf215546Sopenharmony_ci   const int64_t abs_timeout = os_time_get_absolute_timeout(timeout);
818bf215546Sopenharmony_ci   VkResult result = VK_NOT_READY;
819bf215546Sopenharmony_ci   uint32_t iter = 0;
820bf215546Sopenharmony_ci   if (fenceCount > 1 && waitAll) {
821bf215546Sopenharmony_ci      VkFence local_fences[8];
822bf215546Sopenharmony_ci      VkFence *fences = local_fences;
823bf215546Sopenharmony_ci      if (fenceCount > ARRAY_SIZE(local_fences)) {
824bf215546Sopenharmony_ci         fences =
825bf215546Sopenharmony_ci            vk_alloc(alloc, sizeof(*fences) * fenceCount, VN_DEFAULT_ALIGN,
826bf215546Sopenharmony_ci                     VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
827bf215546Sopenharmony_ci         if (!fences)
828bf215546Sopenharmony_ci            return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
829bf215546Sopenharmony_ci      }
830bf215546Sopenharmony_ci      memcpy(fences, pFences, sizeof(*fences) * fenceCount);
831bf215546Sopenharmony_ci
832bf215546Sopenharmony_ci      while (result == VK_NOT_READY) {
833bf215546Sopenharmony_ci         result = vn_remove_signaled_fences(device, fences, &fenceCount);
834bf215546Sopenharmony_ci         result = vn_update_sync_result(result, abs_timeout, &iter);
835bf215546Sopenharmony_ci      }
836bf215546Sopenharmony_ci
837bf215546Sopenharmony_ci      if (fences != local_fences)
838bf215546Sopenharmony_ci         vk_free(alloc, fences);
839bf215546Sopenharmony_ci   } else {
840bf215546Sopenharmony_ci      while (result == VK_NOT_READY) {
841bf215546Sopenharmony_ci         result = vn_find_first_signaled_fence(device, pFences, fenceCount);
842bf215546Sopenharmony_ci         result = vn_update_sync_result(result, abs_timeout, &iter);
843bf215546Sopenharmony_ci      }
844bf215546Sopenharmony_ci   }
845bf215546Sopenharmony_ci
846bf215546Sopenharmony_ci   return vn_result(dev->instance, result);
847bf215546Sopenharmony_ci}
848bf215546Sopenharmony_ci
849bf215546Sopenharmony_cistatic VkResult
850bf215546Sopenharmony_civn_create_sync_file(struct vn_device *dev, int *out_fd)
851bf215546Sopenharmony_ci{
852bf215546Sopenharmony_ci   struct vn_renderer_sync *sync;
853bf215546Sopenharmony_ci   VkResult result = vn_renderer_sync_create(dev->renderer, 0,
854bf215546Sopenharmony_ci                                             VN_RENDERER_SYNC_BINARY, &sync);
855bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
856bf215546Sopenharmony_ci      return vn_error(dev->instance, result);
857bf215546Sopenharmony_ci
858bf215546Sopenharmony_ci   const struct vn_renderer_submit submit = {
859bf215546Sopenharmony_ci      .batches =
860bf215546Sopenharmony_ci         &(const struct vn_renderer_submit_batch){
861bf215546Sopenharmony_ci            .syncs = &sync,
862bf215546Sopenharmony_ci            .sync_values = &(const uint64_t){ 1 },
863bf215546Sopenharmony_ci            .sync_count = 1,
864bf215546Sopenharmony_ci         },
865bf215546Sopenharmony_ci      .batch_count = 1,
866bf215546Sopenharmony_ci   };
867bf215546Sopenharmony_ci   result = vn_renderer_submit(dev->renderer, &submit);
868bf215546Sopenharmony_ci   if (result != VK_SUCCESS) {
869bf215546Sopenharmony_ci      vn_renderer_sync_destroy(dev->renderer, sync);
870bf215546Sopenharmony_ci      return vn_error(dev->instance, result);
871bf215546Sopenharmony_ci   }
872bf215546Sopenharmony_ci
873bf215546Sopenharmony_ci   *out_fd = vn_renderer_sync_export_syncobj(dev->renderer, sync, true);
874bf215546Sopenharmony_ci   vn_renderer_sync_destroy(dev->renderer, sync);
875bf215546Sopenharmony_ci
876bf215546Sopenharmony_ci   return *out_fd >= 0 ? VK_SUCCESS : VK_ERROR_TOO_MANY_OBJECTS;
877bf215546Sopenharmony_ci}
878bf215546Sopenharmony_ci
879bf215546Sopenharmony_ciVkResult
880bf215546Sopenharmony_civn_ImportFenceFdKHR(VkDevice device,
881bf215546Sopenharmony_ci                    const VkImportFenceFdInfoKHR *pImportFenceFdInfo)
882bf215546Sopenharmony_ci{
883bf215546Sopenharmony_ci   VN_TRACE_FUNC();
884bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
885bf215546Sopenharmony_ci   struct vn_fence *fence = vn_fence_from_handle(pImportFenceFdInfo->fence);
886bf215546Sopenharmony_ci   ASSERTED const bool sync_file = pImportFenceFdInfo->handleType ==
887bf215546Sopenharmony_ci                                   VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
888bf215546Sopenharmony_ci   const int fd = pImportFenceFdInfo->fd;
889bf215546Sopenharmony_ci
890bf215546Sopenharmony_ci   /* TODO update fence->is_external after we support opaque fd import */
891bf215546Sopenharmony_ci   assert(dev->instance->experimental.globalFencing);
892bf215546Sopenharmony_ci   assert(sync_file);
893bf215546Sopenharmony_ci   if (fd >= 0) {
894bf215546Sopenharmony_ci      if (sync_wait(fd, -1))
895bf215546Sopenharmony_ci         return vn_error(dev->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE);
896bf215546Sopenharmony_ci
897bf215546Sopenharmony_ci      close(fd);
898bf215546Sopenharmony_ci   }
899bf215546Sopenharmony_ci
900bf215546Sopenharmony_ci   /* abuse VN_SYNC_TYPE_WSI_SIGNALED */
901bf215546Sopenharmony_ci   vn_fence_signal_wsi(dev, fence);
902bf215546Sopenharmony_ci
903bf215546Sopenharmony_ci   return VK_SUCCESS;
904bf215546Sopenharmony_ci}
905bf215546Sopenharmony_ci
906bf215546Sopenharmony_ciVkResult
907bf215546Sopenharmony_civn_GetFenceFdKHR(VkDevice device,
908bf215546Sopenharmony_ci                 const VkFenceGetFdInfoKHR *pGetFdInfo,
909bf215546Sopenharmony_ci                 int *pFd)
910bf215546Sopenharmony_ci{
911bf215546Sopenharmony_ci   VN_TRACE_FUNC();
912bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
913bf215546Sopenharmony_ci   struct vn_fence *fence = vn_fence_from_handle(pGetFdInfo->fence);
914bf215546Sopenharmony_ci   const bool sync_file =
915bf215546Sopenharmony_ci      pGetFdInfo->handleType == VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
916bf215546Sopenharmony_ci   struct vn_sync_payload *payload = fence->payload;
917bf215546Sopenharmony_ci
918bf215546Sopenharmony_ci   assert(dev->instance->experimental.globalFencing);
919bf215546Sopenharmony_ci   assert(sync_file);
920bf215546Sopenharmony_ci   int fd = -1;
921bf215546Sopenharmony_ci   if (payload->type == VN_SYNC_TYPE_DEVICE_ONLY) {
922bf215546Sopenharmony_ci      VkResult result = vn_create_sync_file(dev, &fd);
923bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
924bf215546Sopenharmony_ci         return vn_error(dev->instance, result);
925bf215546Sopenharmony_ci   }
926bf215546Sopenharmony_ci
927bf215546Sopenharmony_ci   if (sync_file) {
928bf215546Sopenharmony_ci      vn_sync_payload_release(dev, &fence->temporary);
929bf215546Sopenharmony_ci      fence->payload = &fence->permanent;
930bf215546Sopenharmony_ci
931bf215546Sopenharmony_ci      /* XXX implies reset operation on the host fence */
932bf215546Sopenharmony_ci   }
933bf215546Sopenharmony_ci
934bf215546Sopenharmony_ci   *pFd = fd;
935bf215546Sopenharmony_ci   return VK_SUCCESS;
936bf215546Sopenharmony_ci}
937bf215546Sopenharmony_ci
938bf215546Sopenharmony_ci/* semaphore commands */
939bf215546Sopenharmony_ci
940bf215546Sopenharmony_cistatic VkResult
941bf215546Sopenharmony_civn_semaphore_init_payloads(struct vn_device *dev,
942bf215546Sopenharmony_ci                           struct vn_semaphore *sem,
943bf215546Sopenharmony_ci                           uint64_t initial_val,
944bf215546Sopenharmony_ci                           const VkAllocationCallbacks *alloc)
945bf215546Sopenharmony_ci{
946bf215546Sopenharmony_ci   sem->permanent.type = VN_SYNC_TYPE_DEVICE_ONLY;
947bf215546Sopenharmony_ci   sem->temporary.type = VN_SYNC_TYPE_INVALID;
948bf215546Sopenharmony_ci   sem->payload = &sem->permanent;
949bf215546Sopenharmony_ci
950bf215546Sopenharmony_ci   return VK_SUCCESS;
951bf215546Sopenharmony_ci}
952bf215546Sopenharmony_ci
953bf215546Sopenharmony_cistatic void
954bf215546Sopenharmony_civn_semaphore_reset_wsi(struct vn_device *dev, struct vn_semaphore *sem)
955bf215546Sopenharmony_ci{
956bf215546Sopenharmony_ci   struct vn_sync_payload *perm = &sem->permanent;
957bf215546Sopenharmony_ci
958bf215546Sopenharmony_ci   vn_sync_payload_release(dev, &sem->temporary);
959bf215546Sopenharmony_ci
960bf215546Sopenharmony_ci   sem->payload = perm;
961bf215546Sopenharmony_ci}
962bf215546Sopenharmony_ci
963bf215546Sopenharmony_civoid
964bf215546Sopenharmony_civn_semaphore_signal_wsi(struct vn_device *dev, struct vn_semaphore *sem)
965bf215546Sopenharmony_ci{
966bf215546Sopenharmony_ci   struct vn_sync_payload *temp = &sem->temporary;
967bf215546Sopenharmony_ci
968bf215546Sopenharmony_ci   vn_sync_payload_release(dev, temp);
969bf215546Sopenharmony_ci   temp->type = VN_SYNC_TYPE_WSI_SIGNALED;
970bf215546Sopenharmony_ci   sem->payload = temp;
971bf215546Sopenharmony_ci}
972bf215546Sopenharmony_ci
973bf215546Sopenharmony_ciVkResult
974bf215546Sopenharmony_civn_CreateSemaphore(VkDevice device,
975bf215546Sopenharmony_ci                   const VkSemaphoreCreateInfo *pCreateInfo,
976bf215546Sopenharmony_ci                   const VkAllocationCallbacks *pAllocator,
977bf215546Sopenharmony_ci                   VkSemaphore *pSemaphore)
978bf215546Sopenharmony_ci{
979bf215546Sopenharmony_ci   VN_TRACE_FUNC();
980bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
981bf215546Sopenharmony_ci   const VkAllocationCallbacks *alloc =
982bf215546Sopenharmony_ci      pAllocator ? pAllocator : &dev->base.base.alloc;
983bf215546Sopenharmony_ci
984bf215546Sopenharmony_ci   struct vn_semaphore *sem = vk_zalloc(alloc, sizeof(*sem), VN_DEFAULT_ALIGN,
985bf215546Sopenharmony_ci                                        VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
986bf215546Sopenharmony_ci   if (!sem)
987bf215546Sopenharmony_ci      return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
988bf215546Sopenharmony_ci
989bf215546Sopenharmony_ci   vn_object_base_init(&sem->base, VK_OBJECT_TYPE_SEMAPHORE, &dev->base);
990bf215546Sopenharmony_ci
991bf215546Sopenharmony_ci   const VkSemaphoreTypeCreateInfo *type_info =
992bf215546Sopenharmony_ci      vk_find_struct_const(pCreateInfo->pNext, SEMAPHORE_TYPE_CREATE_INFO);
993bf215546Sopenharmony_ci   uint64_t initial_val = 0;
994bf215546Sopenharmony_ci   if (type_info && type_info->semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE) {
995bf215546Sopenharmony_ci      sem->type = VK_SEMAPHORE_TYPE_TIMELINE;
996bf215546Sopenharmony_ci      initial_val = type_info->initialValue;
997bf215546Sopenharmony_ci   } else {
998bf215546Sopenharmony_ci      sem->type = VK_SEMAPHORE_TYPE_BINARY;
999bf215546Sopenharmony_ci   }
1000bf215546Sopenharmony_ci
1001bf215546Sopenharmony_ci   VkResult result = vn_semaphore_init_payloads(dev, sem, initial_val, alloc);
1002bf215546Sopenharmony_ci   if (result != VK_SUCCESS) {
1003bf215546Sopenharmony_ci      vn_object_base_fini(&sem->base);
1004bf215546Sopenharmony_ci      vk_free(alloc, sem);
1005bf215546Sopenharmony_ci      return vn_error(dev->instance, result);
1006bf215546Sopenharmony_ci   }
1007bf215546Sopenharmony_ci
1008bf215546Sopenharmony_ci   VkSemaphore sem_handle = vn_semaphore_to_handle(sem);
1009bf215546Sopenharmony_ci   vn_async_vkCreateSemaphore(dev->instance, device, pCreateInfo, NULL,
1010bf215546Sopenharmony_ci                              &sem_handle);
1011bf215546Sopenharmony_ci
1012bf215546Sopenharmony_ci   *pSemaphore = sem_handle;
1013bf215546Sopenharmony_ci
1014bf215546Sopenharmony_ci   return VK_SUCCESS;
1015bf215546Sopenharmony_ci}
1016bf215546Sopenharmony_ci
1017bf215546Sopenharmony_civoid
1018bf215546Sopenharmony_civn_DestroySemaphore(VkDevice device,
1019bf215546Sopenharmony_ci                    VkSemaphore semaphore,
1020bf215546Sopenharmony_ci                    const VkAllocationCallbacks *pAllocator)
1021bf215546Sopenharmony_ci{
1022bf215546Sopenharmony_ci   VN_TRACE_FUNC();
1023bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
1024bf215546Sopenharmony_ci   struct vn_semaphore *sem = vn_semaphore_from_handle(semaphore);
1025bf215546Sopenharmony_ci   const VkAllocationCallbacks *alloc =
1026bf215546Sopenharmony_ci      pAllocator ? pAllocator : &dev->base.base.alloc;
1027bf215546Sopenharmony_ci
1028bf215546Sopenharmony_ci   if (!sem)
1029bf215546Sopenharmony_ci      return;
1030bf215546Sopenharmony_ci
1031bf215546Sopenharmony_ci   vn_async_vkDestroySemaphore(dev->instance, device, semaphore, NULL);
1032bf215546Sopenharmony_ci
1033bf215546Sopenharmony_ci   vn_sync_payload_release(dev, &sem->permanent);
1034bf215546Sopenharmony_ci   vn_sync_payload_release(dev, &sem->temporary);
1035bf215546Sopenharmony_ci
1036bf215546Sopenharmony_ci   vn_object_base_fini(&sem->base);
1037bf215546Sopenharmony_ci   vk_free(alloc, sem);
1038bf215546Sopenharmony_ci}
1039bf215546Sopenharmony_ci
1040bf215546Sopenharmony_ciVkResult
1041bf215546Sopenharmony_civn_GetSemaphoreCounterValue(VkDevice device,
1042bf215546Sopenharmony_ci                            VkSemaphore semaphore,
1043bf215546Sopenharmony_ci                            uint64_t *pValue)
1044bf215546Sopenharmony_ci{
1045bf215546Sopenharmony_ci   VN_TRACE_FUNC();
1046bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
1047bf215546Sopenharmony_ci   struct vn_semaphore *sem = vn_semaphore_from_handle(semaphore);
1048bf215546Sopenharmony_ci   ASSERTED struct vn_sync_payload *payload = sem->payload;
1049bf215546Sopenharmony_ci
1050bf215546Sopenharmony_ci   assert(payload->type == VN_SYNC_TYPE_DEVICE_ONLY);
1051bf215546Sopenharmony_ci   return vn_call_vkGetSemaphoreCounterValue(dev->instance, device, semaphore,
1052bf215546Sopenharmony_ci                                             pValue);
1053bf215546Sopenharmony_ci}
1054bf215546Sopenharmony_ci
1055bf215546Sopenharmony_ciVkResult
1056bf215546Sopenharmony_civn_SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo *pSignalInfo)
1057bf215546Sopenharmony_ci{
1058bf215546Sopenharmony_ci   VN_TRACE_FUNC();
1059bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
1060bf215546Sopenharmony_ci
1061bf215546Sopenharmony_ci   /* TODO if the semaphore is shared-by-ref, this needs to be synchronous */
1062bf215546Sopenharmony_ci   if (false)
1063bf215546Sopenharmony_ci      vn_call_vkSignalSemaphore(dev->instance, device, pSignalInfo);
1064bf215546Sopenharmony_ci   else
1065bf215546Sopenharmony_ci      vn_async_vkSignalSemaphore(dev->instance, device, pSignalInfo);
1066bf215546Sopenharmony_ci
1067bf215546Sopenharmony_ci   return VK_SUCCESS;
1068bf215546Sopenharmony_ci}
1069bf215546Sopenharmony_ci
1070bf215546Sopenharmony_cistatic VkResult
1071bf215546Sopenharmony_civn_find_first_signaled_semaphore(VkDevice device,
1072bf215546Sopenharmony_ci                                 const VkSemaphore *semaphores,
1073bf215546Sopenharmony_ci                                 const uint64_t *values,
1074bf215546Sopenharmony_ci                                 uint32_t count)
1075bf215546Sopenharmony_ci{
1076bf215546Sopenharmony_ci   for (uint32_t i = 0; i < count; i++) {
1077bf215546Sopenharmony_ci      uint64_t val = 0;
1078bf215546Sopenharmony_ci      VkResult result =
1079bf215546Sopenharmony_ci         vn_GetSemaphoreCounterValue(device, semaphores[i], &val);
1080bf215546Sopenharmony_ci      if (result != VK_SUCCESS || val >= values[i])
1081bf215546Sopenharmony_ci         return result;
1082bf215546Sopenharmony_ci   }
1083bf215546Sopenharmony_ci   return VK_NOT_READY;
1084bf215546Sopenharmony_ci}
1085bf215546Sopenharmony_ci
1086bf215546Sopenharmony_cistatic VkResult
1087bf215546Sopenharmony_civn_remove_signaled_semaphores(VkDevice device,
1088bf215546Sopenharmony_ci                              VkSemaphore *semaphores,
1089bf215546Sopenharmony_ci                              uint64_t *values,
1090bf215546Sopenharmony_ci                              uint32_t *count)
1091bf215546Sopenharmony_ci{
1092bf215546Sopenharmony_ci   uint32_t cur = 0;
1093bf215546Sopenharmony_ci   for (uint32_t i = 0; i < *count; i++) {
1094bf215546Sopenharmony_ci      uint64_t val = 0;
1095bf215546Sopenharmony_ci      VkResult result =
1096bf215546Sopenharmony_ci         vn_GetSemaphoreCounterValue(device, semaphores[i], &val);
1097bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
1098bf215546Sopenharmony_ci         return result;
1099bf215546Sopenharmony_ci      if (val < values[i])
1100bf215546Sopenharmony_ci         semaphores[cur++] = semaphores[i];
1101bf215546Sopenharmony_ci   }
1102bf215546Sopenharmony_ci
1103bf215546Sopenharmony_ci   *count = cur;
1104bf215546Sopenharmony_ci   return cur ? VK_NOT_READY : VK_SUCCESS;
1105bf215546Sopenharmony_ci}
1106bf215546Sopenharmony_ci
1107bf215546Sopenharmony_ciVkResult
1108bf215546Sopenharmony_civn_WaitSemaphores(VkDevice device,
1109bf215546Sopenharmony_ci                  const VkSemaphoreWaitInfo *pWaitInfo,
1110bf215546Sopenharmony_ci                  uint64_t timeout)
1111bf215546Sopenharmony_ci{
1112bf215546Sopenharmony_ci   VN_TRACE_FUNC();
1113bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
1114bf215546Sopenharmony_ci   const VkAllocationCallbacks *alloc = &dev->base.base.alloc;
1115bf215546Sopenharmony_ci
1116bf215546Sopenharmony_ci   const int64_t abs_timeout = os_time_get_absolute_timeout(timeout);
1117bf215546Sopenharmony_ci   VkResult result = VK_NOT_READY;
1118bf215546Sopenharmony_ci   uint32_t iter = 0;
1119bf215546Sopenharmony_ci   if (pWaitInfo->semaphoreCount > 1 &&
1120bf215546Sopenharmony_ci       !(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT)) {
1121bf215546Sopenharmony_ci      uint32_t semaphore_count = pWaitInfo->semaphoreCount;
1122bf215546Sopenharmony_ci      VkSemaphore local_semaphores[8];
1123bf215546Sopenharmony_ci      uint64_t local_values[8];
1124bf215546Sopenharmony_ci      VkSemaphore *semaphores = local_semaphores;
1125bf215546Sopenharmony_ci      uint64_t *values = local_values;
1126bf215546Sopenharmony_ci      if (semaphore_count > ARRAY_SIZE(local_semaphores)) {
1127bf215546Sopenharmony_ci         semaphores = vk_alloc(
1128bf215546Sopenharmony_ci            alloc, (sizeof(*semaphores) + sizeof(*values)) * semaphore_count,
1129bf215546Sopenharmony_ci            VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
1130bf215546Sopenharmony_ci         if (!semaphores)
1131bf215546Sopenharmony_ci            return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
1132bf215546Sopenharmony_ci
1133bf215546Sopenharmony_ci         values = (uint64_t *)&semaphores[semaphore_count];
1134bf215546Sopenharmony_ci      }
1135bf215546Sopenharmony_ci      memcpy(semaphores, pWaitInfo->pSemaphores,
1136bf215546Sopenharmony_ci             sizeof(*semaphores) * semaphore_count);
1137bf215546Sopenharmony_ci      memcpy(values, pWaitInfo->pValues, sizeof(*values) * semaphore_count);
1138bf215546Sopenharmony_ci
1139bf215546Sopenharmony_ci      while (result == VK_NOT_READY) {
1140bf215546Sopenharmony_ci         result = vn_remove_signaled_semaphores(device, semaphores, values,
1141bf215546Sopenharmony_ci                                                &semaphore_count);
1142bf215546Sopenharmony_ci         result = vn_update_sync_result(result, abs_timeout, &iter);
1143bf215546Sopenharmony_ci      }
1144bf215546Sopenharmony_ci
1145bf215546Sopenharmony_ci      if (semaphores != local_semaphores)
1146bf215546Sopenharmony_ci         vk_free(alloc, semaphores);
1147bf215546Sopenharmony_ci   } else {
1148bf215546Sopenharmony_ci      while (result == VK_NOT_READY) {
1149bf215546Sopenharmony_ci         result = vn_find_first_signaled_semaphore(
1150bf215546Sopenharmony_ci            device, pWaitInfo->pSemaphores, pWaitInfo->pValues,
1151bf215546Sopenharmony_ci            pWaitInfo->semaphoreCount);
1152bf215546Sopenharmony_ci         result = vn_update_sync_result(result, abs_timeout, &iter);
1153bf215546Sopenharmony_ci      }
1154bf215546Sopenharmony_ci   }
1155bf215546Sopenharmony_ci
1156bf215546Sopenharmony_ci   return vn_result(dev->instance, result);
1157bf215546Sopenharmony_ci}
1158bf215546Sopenharmony_ci
1159bf215546Sopenharmony_ciVkResult
1160bf215546Sopenharmony_civn_ImportSemaphoreFdKHR(
1161bf215546Sopenharmony_ci   VkDevice device, const VkImportSemaphoreFdInfoKHR *pImportSemaphoreFdInfo)
1162bf215546Sopenharmony_ci{
1163bf215546Sopenharmony_ci   VN_TRACE_FUNC();
1164bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
1165bf215546Sopenharmony_ci   struct vn_semaphore *sem =
1166bf215546Sopenharmony_ci      vn_semaphore_from_handle(pImportSemaphoreFdInfo->semaphore);
1167bf215546Sopenharmony_ci   ASSERTED const bool sync_file =
1168bf215546Sopenharmony_ci      pImportSemaphoreFdInfo->handleType ==
1169bf215546Sopenharmony_ci      VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
1170bf215546Sopenharmony_ci   const int fd = pImportSemaphoreFdInfo->fd;
1171bf215546Sopenharmony_ci
1172bf215546Sopenharmony_ci   assert(dev->instance->experimental.globalFencing);
1173bf215546Sopenharmony_ci   assert(sync_file);
1174bf215546Sopenharmony_ci   if (fd >= 0) {
1175bf215546Sopenharmony_ci      if (sync_wait(fd, -1))
1176bf215546Sopenharmony_ci         return vn_error(dev->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE);
1177bf215546Sopenharmony_ci
1178bf215546Sopenharmony_ci      close(fd);
1179bf215546Sopenharmony_ci   }
1180bf215546Sopenharmony_ci
1181bf215546Sopenharmony_ci   /* abuse VN_SYNC_TYPE_WSI_SIGNALED */
1182bf215546Sopenharmony_ci   vn_semaphore_signal_wsi(dev, sem);
1183bf215546Sopenharmony_ci
1184bf215546Sopenharmony_ci   return VK_SUCCESS;
1185bf215546Sopenharmony_ci}
1186bf215546Sopenharmony_ci
1187bf215546Sopenharmony_ciVkResult
1188bf215546Sopenharmony_civn_GetSemaphoreFdKHR(VkDevice device,
1189bf215546Sopenharmony_ci                     const VkSemaphoreGetFdInfoKHR *pGetFdInfo,
1190bf215546Sopenharmony_ci                     int *pFd)
1191bf215546Sopenharmony_ci{
1192bf215546Sopenharmony_ci   VN_TRACE_FUNC();
1193bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
1194bf215546Sopenharmony_ci   struct vn_semaphore *sem = vn_semaphore_from_handle(pGetFdInfo->semaphore);
1195bf215546Sopenharmony_ci   const bool sync_file =
1196bf215546Sopenharmony_ci      pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
1197bf215546Sopenharmony_ci   struct vn_sync_payload *payload = sem->payload;
1198bf215546Sopenharmony_ci
1199bf215546Sopenharmony_ci   assert(dev->instance->experimental.globalFencing);
1200bf215546Sopenharmony_ci   assert(sync_file);
1201bf215546Sopenharmony_ci   int fd = -1;
1202bf215546Sopenharmony_ci   if (payload->type == VN_SYNC_TYPE_DEVICE_ONLY) {
1203bf215546Sopenharmony_ci      VkResult result = vn_create_sync_file(dev, &fd);
1204bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
1205bf215546Sopenharmony_ci         return vn_error(dev->instance, result);
1206bf215546Sopenharmony_ci   }
1207bf215546Sopenharmony_ci
1208bf215546Sopenharmony_ci   if (sync_file) {
1209bf215546Sopenharmony_ci      vn_sync_payload_release(dev, &sem->temporary);
1210bf215546Sopenharmony_ci      sem->payload = &sem->permanent;
1211bf215546Sopenharmony_ci
1212bf215546Sopenharmony_ci      /* XXX implies wait operation on the host semaphore */
1213bf215546Sopenharmony_ci   }
1214bf215546Sopenharmony_ci
1215bf215546Sopenharmony_ci   *pFd = fd;
1216bf215546Sopenharmony_ci   return VK_SUCCESS;
1217bf215546Sopenharmony_ci}
1218bf215546Sopenharmony_ci
1219bf215546Sopenharmony_ci/* event commands */
1220bf215546Sopenharmony_ci
1221bf215546Sopenharmony_cistatic VkResult
1222bf215546Sopenharmony_civn_event_feedback_init(struct vn_device *dev, struct vn_event *ev)
1223bf215546Sopenharmony_ci{
1224bf215546Sopenharmony_ci   struct vn_feedback_slot *slot;
1225bf215546Sopenharmony_ci
1226bf215546Sopenharmony_ci   if (VN_PERF(NO_EVENT_FEEDBACK))
1227bf215546Sopenharmony_ci      return VK_SUCCESS;
1228bf215546Sopenharmony_ci
1229bf215546Sopenharmony_ci   slot = vn_feedback_pool_alloc(&dev->feedback_pool, VN_FEEDBACK_TYPE_EVENT);
1230bf215546Sopenharmony_ci   if (!slot)
1231bf215546Sopenharmony_ci      return VK_ERROR_OUT_OF_HOST_MEMORY;
1232bf215546Sopenharmony_ci
1233bf215546Sopenharmony_ci   /* newly created event object is in the unsignaled state */
1234bf215546Sopenharmony_ci   vn_feedback_set_status(slot, VK_EVENT_RESET);
1235bf215546Sopenharmony_ci
1236bf215546Sopenharmony_ci   ev->feedback_slot = slot;
1237bf215546Sopenharmony_ci
1238bf215546Sopenharmony_ci   return VK_SUCCESS;
1239bf215546Sopenharmony_ci}
1240bf215546Sopenharmony_ci
1241bf215546Sopenharmony_cistatic inline void
1242bf215546Sopenharmony_civn_event_feedback_fini(struct vn_device *dev, struct vn_event *ev)
1243bf215546Sopenharmony_ci{
1244bf215546Sopenharmony_ci   if (ev->feedback_slot)
1245bf215546Sopenharmony_ci      vn_feedback_pool_free(&dev->feedback_pool, ev->feedback_slot);
1246bf215546Sopenharmony_ci}
1247bf215546Sopenharmony_ci
1248bf215546Sopenharmony_ciVkResult
1249bf215546Sopenharmony_civn_CreateEvent(VkDevice device,
1250bf215546Sopenharmony_ci               const VkEventCreateInfo *pCreateInfo,
1251bf215546Sopenharmony_ci               const VkAllocationCallbacks *pAllocator,
1252bf215546Sopenharmony_ci               VkEvent *pEvent)
1253bf215546Sopenharmony_ci{
1254bf215546Sopenharmony_ci   VN_TRACE_FUNC();
1255bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
1256bf215546Sopenharmony_ci   const VkAllocationCallbacks *alloc =
1257bf215546Sopenharmony_ci      pAllocator ? pAllocator : &dev->base.base.alloc;
1258bf215546Sopenharmony_ci
1259bf215546Sopenharmony_ci   struct vn_event *ev = vk_zalloc(alloc, sizeof(*ev), VN_DEFAULT_ALIGN,
1260bf215546Sopenharmony_ci                                   VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1261bf215546Sopenharmony_ci   if (!ev)
1262bf215546Sopenharmony_ci      return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
1263bf215546Sopenharmony_ci
1264bf215546Sopenharmony_ci   vn_object_base_init(&ev->base, VK_OBJECT_TYPE_EVENT, &dev->base);
1265bf215546Sopenharmony_ci
1266bf215546Sopenharmony_ci   /* feedback is only needed to speed up host operations */
1267bf215546Sopenharmony_ci   if (!(pCreateInfo->flags & VK_EVENT_CREATE_DEVICE_ONLY_BIT)) {
1268bf215546Sopenharmony_ci      VkResult result = vn_event_feedback_init(dev, ev);
1269bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
1270bf215546Sopenharmony_ci         return vn_error(dev->instance, result);
1271bf215546Sopenharmony_ci   }
1272bf215546Sopenharmony_ci
1273bf215546Sopenharmony_ci   VkEvent ev_handle = vn_event_to_handle(ev);
1274bf215546Sopenharmony_ci   vn_async_vkCreateEvent(dev->instance, device, pCreateInfo, NULL,
1275bf215546Sopenharmony_ci                          &ev_handle);
1276bf215546Sopenharmony_ci
1277bf215546Sopenharmony_ci   *pEvent = ev_handle;
1278bf215546Sopenharmony_ci
1279bf215546Sopenharmony_ci   return VK_SUCCESS;
1280bf215546Sopenharmony_ci}
1281bf215546Sopenharmony_ci
1282bf215546Sopenharmony_civoid
1283bf215546Sopenharmony_civn_DestroyEvent(VkDevice device,
1284bf215546Sopenharmony_ci                VkEvent event,
1285bf215546Sopenharmony_ci                const VkAllocationCallbacks *pAllocator)
1286bf215546Sopenharmony_ci{
1287bf215546Sopenharmony_ci   VN_TRACE_FUNC();
1288bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
1289bf215546Sopenharmony_ci   struct vn_event *ev = vn_event_from_handle(event);
1290bf215546Sopenharmony_ci   const VkAllocationCallbacks *alloc =
1291bf215546Sopenharmony_ci      pAllocator ? pAllocator : &dev->base.base.alloc;
1292bf215546Sopenharmony_ci
1293bf215546Sopenharmony_ci   if (!ev)
1294bf215546Sopenharmony_ci      return;
1295bf215546Sopenharmony_ci
1296bf215546Sopenharmony_ci   vn_async_vkDestroyEvent(dev->instance, device, event, NULL);
1297bf215546Sopenharmony_ci
1298bf215546Sopenharmony_ci   vn_event_feedback_fini(dev, ev);
1299bf215546Sopenharmony_ci
1300bf215546Sopenharmony_ci   vn_object_base_fini(&ev->base);
1301bf215546Sopenharmony_ci   vk_free(alloc, ev);
1302bf215546Sopenharmony_ci}
1303bf215546Sopenharmony_ci
1304bf215546Sopenharmony_ciVkResult
1305bf215546Sopenharmony_civn_GetEventStatus(VkDevice device, VkEvent event)
1306bf215546Sopenharmony_ci{
1307bf215546Sopenharmony_ci   VN_TRACE_FUNC();
1308bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
1309bf215546Sopenharmony_ci   struct vn_event *ev = vn_event_from_handle(event);
1310bf215546Sopenharmony_ci   VkResult result;
1311bf215546Sopenharmony_ci
1312bf215546Sopenharmony_ci   if (ev->feedback_slot)
1313bf215546Sopenharmony_ci      result = vn_feedback_get_status(ev->feedback_slot);
1314bf215546Sopenharmony_ci   else
1315bf215546Sopenharmony_ci      result = vn_call_vkGetEventStatus(dev->instance, device, event);
1316bf215546Sopenharmony_ci
1317bf215546Sopenharmony_ci   return vn_result(dev->instance, result);
1318bf215546Sopenharmony_ci}
1319bf215546Sopenharmony_ci
1320bf215546Sopenharmony_ciVkResult
1321bf215546Sopenharmony_civn_SetEvent(VkDevice device, VkEvent event)
1322bf215546Sopenharmony_ci{
1323bf215546Sopenharmony_ci   VN_TRACE_FUNC();
1324bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
1325bf215546Sopenharmony_ci   struct vn_event *ev = vn_event_from_handle(event);
1326bf215546Sopenharmony_ci
1327bf215546Sopenharmony_ci   if (ev->feedback_slot) {
1328bf215546Sopenharmony_ci      vn_feedback_set_status(ev->feedback_slot, VK_EVENT_SET);
1329bf215546Sopenharmony_ci      vn_async_vkSetEvent(dev->instance, device, event);
1330bf215546Sopenharmony_ci   } else {
1331bf215546Sopenharmony_ci      VkResult result = vn_call_vkSetEvent(dev->instance, device, event);
1332bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
1333bf215546Sopenharmony_ci         return vn_error(dev->instance, result);
1334bf215546Sopenharmony_ci   }
1335bf215546Sopenharmony_ci
1336bf215546Sopenharmony_ci   return VK_SUCCESS;
1337bf215546Sopenharmony_ci}
1338bf215546Sopenharmony_ci
1339bf215546Sopenharmony_ciVkResult
1340bf215546Sopenharmony_civn_ResetEvent(VkDevice device, VkEvent event)
1341bf215546Sopenharmony_ci{
1342bf215546Sopenharmony_ci   VN_TRACE_FUNC();
1343bf215546Sopenharmony_ci   struct vn_device *dev = vn_device_from_handle(device);
1344bf215546Sopenharmony_ci   struct vn_event *ev = vn_event_from_handle(event);
1345bf215546Sopenharmony_ci
1346bf215546Sopenharmony_ci   if (ev->feedback_slot) {
1347bf215546Sopenharmony_ci      vn_feedback_reset_status(ev->feedback_slot);
1348bf215546Sopenharmony_ci      vn_async_vkResetEvent(dev->instance, device, event);
1349bf215546Sopenharmony_ci   } else {
1350bf215546Sopenharmony_ci      VkResult result = vn_call_vkResetEvent(dev->instance, device, event);
1351bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
1352bf215546Sopenharmony_ci         return vn_error(dev->instance, result);
1353bf215546Sopenharmony_ci   }
1354bf215546Sopenharmony_ci
1355bf215546Sopenharmony_ci   return VK_SUCCESS;
1356bf215546Sopenharmony_ci}
1357