vn_queue.c revision 7ec681f3
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
19#include "vn_device.h"
20#include "vn_device_memory.h"
21#include "vn_renderer.h"
22#include "vn_wsi.h"
23
24/* queue commands */
25
26void
27vn_GetDeviceQueue(VkDevice device,
28                  uint32_t queueFamilyIndex,
29                  uint32_t queueIndex,
30                  VkQueue *pQueue)
31{
32   struct vn_device *dev = vn_device_from_handle(device);
33
34   for (uint32_t i = 0; i < dev->queue_count; i++) {
35      struct vn_queue *queue = &dev->queues[i];
36      if (queue->family == queueFamilyIndex && queue->index == queueIndex) {
37         assert(!queue->flags);
38         *pQueue = vn_queue_to_handle(queue);
39         return;
40      }
41   }
42   unreachable("bad queue family/index");
43}
44
45void
46vn_GetDeviceQueue2(VkDevice device,
47                   const VkDeviceQueueInfo2 *pQueueInfo,
48                   VkQueue *pQueue)
49{
50   struct vn_device *dev = vn_device_from_handle(device);
51
52   for (uint32_t i = 0; i < dev->queue_count; i++) {
53      struct vn_queue *queue = &dev->queues[i];
54      if (queue->family == pQueueInfo->queueFamilyIndex &&
55          queue->index == pQueueInfo->queueIndex &&
56          queue->flags == pQueueInfo->flags) {
57         *pQueue = vn_queue_to_handle(queue);
58         return;
59      }
60   }
61   unreachable("bad queue family/index");
62}
63
64static void
65vn_semaphore_reset_wsi(struct vn_device *dev, struct vn_semaphore *sem);
66
67struct vn_queue_submission {
68   VkStructureType batch_type;
69   VkQueue queue;
70   uint32_t batch_count;
71   union {
72      const void *batches;
73      const VkSubmitInfo *submit_batches;
74      const VkBindSparseInfo *bind_sparse_batches;
75   };
76   VkFence fence;
77
78   uint32_t wait_semaphore_count;
79   uint32_t wait_wsi_count;
80
81   struct {
82      void *storage;
83
84      union {
85         void *batches;
86         VkSubmitInfo *submit_batches;
87         VkBindSparseInfo *bind_sparse_batches;
88      };
89      VkSemaphore *semaphores;
90   } temp;
91};
92
93static void
94vn_queue_submission_count_batch_semaphores(struct vn_queue_submission *submit,
95                                           uint32_t batch_index)
96{
97   union {
98      const VkSubmitInfo *submit_batch;
99      const VkBindSparseInfo *bind_sparse_batch;
100   } u;
101   const VkSemaphore *wait_sems;
102   uint32_t wait_count;
103   switch (submit->batch_type) {
104   case VK_STRUCTURE_TYPE_SUBMIT_INFO:
105      u.submit_batch = &submit->submit_batches[batch_index];
106      wait_sems = u.submit_batch->pWaitSemaphores;
107      wait_count = u.submit_batch->waitSemaphoreCount;
108      break;
109   case VK_STRUCTURE_TYPE_BIND_SPARSE_INFO:
110      u.bind_sparse_batch = &submit->bind_sparse_batches[batch_index];
111      wait_sems = u.bind_sparse_batch->pWaitSemaphores;
112      wait_count = u.bind_sparse_batch->waitSemaphoreCount;
113      break;
114   default:
115      unreachable("unexpected batch type");
116      break;
117   }
118
119   submit->wait_semaphore_count += wait_count;
120   for (uint32_t i = 0; i < wait_count; i++) {
121      struct vn_semaphore *sem = vn_semaphore_from_handle(wait_sems[i]);
122      const struct vn_sync_payload *payload = sem->payload;
123
124      if (payload->type == VN_SYNC_TYPE_WSI_SIGNALED)
125         submit->wait_wsi_count++;
126   }
127}
128
129static void
130vn_queue_submission_count_semaphores(struct vn_queue_submission *submit)
131{
132   submit->wait_semaphore_count = 0;
133   submit->wait_wsi_count = 0;
134
135   for (uint32_t i = 0; i < submit->batch_count; i++)
136      vn_queue_submission_count_batch_semaphores(submit, i);
137}
138
139static VkResult
140vn_queue_submission_alloc_storage(struct vn_queue_submission *submit)
141{
142   struct vn_queue *queue = vn_queue_from_handle(submit->queue);
143   const VkAllocationCallbacks *alloc = &queue->device->base.base.alloc;
144   size_t alloc_size = 0;
145   size_t semaphores_offset = 0;
146
147   /* we want to filter out VN_SYNC_TYPE_WSI_SIGNALED wait semaphores */
148   if (submit->wait_wsi_count) {
149      switch (submit->batch_type) {
150      case VK_STRUCTURE_TYPE_SUBMIT_INFO:
151         alloc_size += sizeof(VkSubmitInfo) * submit->batch_count;
152         break;
153      case VK_STRUCTURE_TYPE_BIND_SPARSE_INFO:
154         alloc_size += sizeof(VkBindSparseInfo) * submit->batch_count;
155         break;
156      default:
157         unreachable("unexpected batch type");
158         break;
159      }
160
161      semaphores_offset = alloc_size;
162      alloc_size += sizeof(*submit->temp.semaphores) *
163                    (submit->wait_semaphore_count - submit->wait_wsi_count);
164   }
165
166   if (!alloc_size) {
167      submit->temp.storage = NULL;
168      return VK_SUCCESS;
169   }
170
171   submit->temp.storage = vk_alloc(alloc, alloc_size, VN_DEFAULT_ALIGN,
172                                   VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
173   if (!submit->temp.storage)
174      return VK_ERROR_OUT_OF_HOST_MEMORY;
175
176   submit->temp.batches = submit->temp.storage;
177   submit->temp.semaphores = submit->temp.storage + semaphores_offset;
178
179   return VK_SUCCESS;
180}
181
182static uint32_t
183vn_queue_submission_filter_batch_wsi_semaphores(
184   struct vn_queue_submission *submit,
185   uint32_t batch_index,
186   uint32_t sem_base)
187{
188   struct vn_queue *queue = vn_queue_from_handle(submit->queue);
189
190   union {
191      VkSubmitInfo *submit_batch;
192      VkBindSparseInfo *bind_sparse_batch;
193   } u;
194   const VkSemaphore *src_sems;
195   uint32_t src_count;
196   switch (submit->batch_type) {
197   case VK_STRUCTURE_TYPE_SUBMIT_INFO:
198      u.submit_batch = &submit->temp.submit_batches[batch_index];
199      src_sems = u.submit_batch->pWaitSemaphores;
200      src_count = u.submit_batch->waitSemaphoreCount;
201      break;
202   case VK_STRUCTURE_TYPE_BIND_SPARSE_INFO:
203      u.bind_sparse_batch = &submit->temp.bind_sparse_batches[batch_index];
204      src_sems = u.bind_sparse_batch->pWaitSemaphores;
205      src_count = u.bind_sparse_batch->waitSemaphoreCount;
206      break;
207   default:
208      unreachable("unexpected batch type");
209      break;
210   }
211
212   VkSemaphore *dst_sems = &submit->temp.semaphores[sem_base];
213   uint32_t dst_count = 0;
214
215   /* filter out VN_SYNC_TYPE_WSI_SIGNALED wait semaphores */
216   for (uint32_t i = 0; i < src_count; i++) {
217      struct vn_semaphore *sem = vn_semaphore_from_handle(src_sems[i]);
218      const struct vn_sync_payload *payload = sem->payload;
219
220      if (payload->type == VN_SYNC_TYPE_WSI_SIGNALED)
221         vn_semaphore_reset_wsi(queue->device, sem);
222      else
223         dst_sems[dst_count++] = src_sems[i];
224   }
225
226   switch (submit->batch_type) {
227   case VK_STRUCTURE_TYPE_SUBMIT_INFO:
228      u.submit_batch->pWaitSemaphores = dst_sems;
229      u.submit_batch->waitSemaphoreCount = dst_count;
230      break;
231   case VK_STRUCTURE_TYPE_BIND_SPARSE_INFO:
232      u.bind_sparse_batch->pWaitSemaphores = dst_sems;
233      u.bind_sparse_batch->waitSemaphoreCount = dst_count;
234      break;
235   default:
236      break;
237   }
238
239   return dst_count;
240}
241
242static void
243vn_queue_submission_setup_batches(struct vn_queue_submission *submit)
244{
245   if (!submit->temp.storage)
246      return;
247
248   /* make a copy because we need to filter out WSI semaphores */
249   if (submit->wait_wsi_count) {
250      switch (submit->batch_type) {
251      case VK_STRUCTURE_TYPE_SUBMIT_INFO:
252         memcpy(submit->temp.submit_batches, submit->submit_batches,
253                sizeof(submit->submit_batches[0]) * submit->batch_count);
254         submit->submit_batches = submit->temp.submit_batches;
255         break;
256      case VK_STRUCTURE_TYPE_BIND_SPARSE_INFO:
257         memcpy(submit->temp.bind_sparse_batches, submit->bind_sparse_batches,
258                sizeof(submit->bind_sparse_batches[0]) * submit->batch_count);
259         submit->bind_sparse_batches = submit->temp.bind_sparse_batches;
260         break;
261      default:
262         unreachable("unexpected batch type");
263         break;
264      }
265   }
266
267   uint32_t wait_sem_base = 0;
268   for (uint32_t i = 0; i < submit->batch_count; i++) {
269      if (submit->wait_wsi_count) {
270         wait_sem_base += vn_queue_submission_filter_batch_wsi_semaphores(
271            submit, i, wait_sem_base);
272      }
273   }
274}
275
276static VkResult
277vn_queue_submission_prepare_submit(struct vn_queue_submission *submit,
278                                   VkQueue queue,
279                                   uint32_t batch_count,
280                                   const VkSubmitInfo *submit_batches,
281                                   VkFence fence)
282{
283   submit->batch_type = VK_STRUCTURE_TYPE_SUBMIT_INFO;
284   submit->queue = queue;
285   submit->batch_count = batch_count;
286   submit->submit_batches = submit_batches;
287   submit->fence = fence;
288
289   vn_queue_submission_count_semaphores(submit);
290
291   VkResult result = vn_queue_submission_alloc_storage(submit);
292   if (result != VK_SUCCESS)
293      return result;
294
295   vn_queue_submission_setup_batches(submit);
296
297   return VK_SUCCESS;
298}
299
300static VkResult
301vn_queue_submission_prepare_bind_sparse(
302   struct vn_queue_submission *submit,
303   VkQueue queue,
304   uint32_t batch_count,
305   const VkBindSparseInfo *bind_sparse_batches,
306   VkFence fence)
307{
308   submit->batch_type = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO;
309   submit->queue = queue;
310   submit->batch_count = batch_count;
311   submit->bind_sparse_batches = bind_sparse_batches;
312   submit->fence = fence;
313
314   vn_queue_submission_count_semaphores(submit);
315
316   VkResult result = vn_queue_submission_alloc_storage(submit);
317   if (result != VK_SUCCESS)
318      return result;
319
320   vn_queue_submission_setup_batches(submit);
321
322   return VK_SUCCESS;
323}
324
325static void
326vn_queue_submission_cleanup(struct vn_queue_submission *submit)
327{
328   struct vn_queue *queue = vn_queue_from_handle(submit->queue);
329   const VkAllocationCallbacks *alloc = &queue->device->base.base.alloc;
330
331   vk_free(alloc, submit->temp.storage);
332}
333
334VkResult
335vn_QueueSubmit(VkQueue _queue,
336               uint32_t submitCount,
337               const VkSubmitInfo *pSubmits,
338               VkFence fence)
339{
340   struct vn_queue *queue = vn_queue_from_handle(_queue);
341   struct vn_device *dev = queue->device;
342
343   struct vn_queue_submission submit;
344   VkResult result = vn_queue_submission_prepare_submit(
345      &submit, _queue, submitCount, pSubmits, fence);
346   if (result != VK_SUCCESS)
347      return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
348
349   const struct vn_device_memory *wsi_mem = NULL;
350   if (submit.batch_count == 1) {
351      const struct wsi_memory_signal_submit_info *info = vk_find_struct_const(
352         submit.submit_batches[0].pNext, WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA);
353      if (info) {
354         wsi_mem = vn_device_memory_from_handle(info->memory);
355         assert(!wsi_mem->base_memory && wsi_mem->base_bo);
356      }
357   }
358
359   result =
360      vn_call_vkQueueSubmit(dev->instance, submit.queue, submit.batch_count,
361                            submit.submit_batches, submit.fence);
362   if (result != VK_SUCCESS) {
363      vn_queue_submission_cleanup(&submit);
364      return vn_error(dev->instance, result);
365   }
366
367   if (wsi_mem) {
368      /* XXX this is always false and kills the performance */
369      if (dev->instance->renderer_info.has_implicit_fencing) {
370         vn_renderer_submit(dev->renderer, &(const struct vn_renderer_submit){
371                                              .bos = &wsi_mem->base_bo,
372                                              .bo_count = 1,
373                                           });
374      } else {
375         if (VN_DEBUG(WSI)) {
376            static uint32_t ratelimit;
377            if (ratelimit < 10) {
378               vn_log(dev->instance,
379                      "forcing vkQueueWaitIdle before presenting");
380               ratelimit++;
381            }
382         }
383
384         vn_QueueWaitIdle(submit.queue);
385      }
386   }
387
388   vn_queue_submission_cleanup(&submit);
389
390   return VK_SUCCESS;
391}
392
393VkResult
394vn_QueueBindSparse(VkQueue _queue,
395                   uint32_t bindInfoCount,
396                   const VkBindSparseInfo *pBindInfo,
397                   VkFence fence)
398{
399   struct vn_queue *queue = vn_queue_from_handle(_queue);
400   struct vn_device *dev = queue->device;
401
402   struct vn_queue_submission submit;
403   VkResult result = vn_queue_submission_prepare_bind_sparse(
404      &submit, _queue, bindInfoCount, pBindInfo, fence);
405   if (result != VK_SUCCESS)
406      return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
407
408   result = vn_call_vkQueueBindSparse(
409      dev->instance, submit.queue, submit.batch_count,
410      submit.bind_sparse_batches, submit.fence);
411   if (result != VK_SUCCESS) {
412      vn_queue_submission_cleanup(&submit);
413      return vn_error(dev->instance, result);
414   }
415
416   vn_queue_submission_cleanup(&submit);
417
418   return VK_SUCCESS;
419}
420
421VkResult
422vn_QueueWaitIdle(VkQueue _queue)
423{
424   struct vn_queue *queue = vn_queue_from_handle(_queue);
425   VkDevice device = vn_device_to_handle(queue->device);
426
427   VkResult result = vn_QueueSubmit(_queue, 0, NULL, queue->wait_fence);
428   if (result != VK_SUCCESS)
429      return result;
430
431   result = vn_WaitForFences(device, 1, &queue->wait_fence, true, UINT64_MAX);
432   vn_ResetFences(device, 1, &queue->wait_fence);
433
434   return vn_result(queue->device->instance, result);
435}
436
437/* fence commands */
438
439static void
440vn_sync_payload_release(struct vn_device *dev,
441                        struct vn_sync_payload *payload)
442{
443   payload->type = VN_SYNC_TYPE_INVALID;
444}
445
446static VkResult
447vn_fence_init_payloads(struct vn_device *dev,
448                       struct vn_fence *fence,
449                       bool signaled,
450                       const VkAllocationCallbacks *alloc)
451{
452   fence->permanent.type = VN_SYNC_TYPE_DEVICE_ONLY;
453   fence->temporary.type = VN_SYNC_TYPE_INVALID;
454   fence->payload = &fence->permanent;
455
456   return VK_SUCCESS;
457}
458
459void
460vn_fence_signal_wsi(struct vn_device *dev, struct vn_fence *fence)
461{
462   struct vn_sync_payload *temp = &fence->temporary;
463
464   vn_sync_payload_release(dev, temp);
465   temp->type = VN_SYNC_TYPE_WSI_SIGNALED;
466   fence->payload = temp;
467}
468
469VkResult
470vn_CreateFence(VkDevice device,
471               const VkFenceCreateInfo *pCreateInfo,
472               const VkAllocationCallbacks *pAllocator,
473               VkFence *pFence)
474{
475   struct vn_device *dev = vn_device_from_handle(device);
476   const VkAllocationCallbacks *alloc =
477      pAllocator ? pAllocator : &dev->base.base.alloc;
478
479   VkFenceCreateInfo local_create_info;
480   if (vk_find_struct_const(pCreateInfo->pNext, EXPORT_FENCE_CREATE_INFO)) {
481      local_create_info = *pCreateInfo;
482      local_create_info.pNext = NULL;
483      pCreateInfo = &local_create_info;
484   }
485
486   struct vn_fence *fence = vk_zalloc(alloc, sizeof(*fence), VN_DEFAULT_ALIGN,
487                                      VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
488   if (!fence)
489      return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
490
491   vn_object_base_init(&fence->base, VK_OBJECT_TYPE_FENCE, &dev->base);
492
493   VkResult result = vn_fence_init_payloads(
494      dev, fence, pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT, alloc);
495   if (result != VK_SUCCESS) {
496      vn_object_base_fini(&fence->base);
497      vk_free(alloc, fence);
498      return vn_error(dev->instance, result);
499   }
500
501   VkFence fence_handle = vn_fence_to_handle(fence);
502   vn_async_vkCreateFence(dev->instance, device, pCreateInfo, NULL,
503                          &fence_handle);
504
505   *pFence = fence_handle;
506
507   return VK_SUCCESS;
508}
509
510void
511vn_DestroyFence(VkDevice device,
512                VkFence _fence,
513                const VkAllocationCallbacks *pAllocator)
514{
515   struct vn_device *dev = vn_device_from_handle(device);
516   struct vn_fence *fence = vn_fence_from_handle(_fence);
517   const VkAllocationCallbacks *alloc =
518      pAllocator ? pAllocator : &dev->base.base.alloc;
519
520   if (!fence)
521      return;
522
523   vn_async_vkDestroyFence(dev->instance, device, _fence, NULL);
524
525   vn_sync_payload_release(dev, &fence->permanent);
526   vn_sync_payload_release(dev, &fence->temporary);
527
528   vn_object_base_fini(&fence->base);
529   vk_free(alloc, fence);
530}
531
532VkResult
533vn_ResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences)
534{
535   struct vn_device *dev = vn_device_from_handle(device);
536
537   /* TODO if the fence is shared-by-ref, this needs to be synchronous */
538   if (false)
539      vn_call_vkResetFences(dev->instance, device, fenceCount, pFences);
540   else
541      vn_async_vkResetFences(dev->instance, device, fenceCount, pFences);
542
543   for (uint32_t i = 0; i < fenceCount; i++) {
544      struct vn_fence *fence = vn_fence_from_handle(pFences[i]);
545      struct vn_sync_payload *perm = &fence->permanent;
546
547      vn_sync_payload_release(dev, &fence->temporary);
548
549      assert(perm->type == VN_SYNC_TYPE_DEVICE_ONLY);
550      fence->payload = perm;
551   }
552
553   return VK_SUCCESS;
554}
555
556VkResult
557vn_GetFenceStatus(VkDevice device, VkFence _fence)
558{
559   struct vn_device *dev = vn_device_from_handle(device);
560   struct vn_fence *fence = vn_fence_from_handle(_fence);
561   struct vn_sync_payload *payload = fence->payload;
562
563   VkResult result;
564   switch (payload->type) {
565   case VN_SYNC_TYPE_DEVICE_ONLY:
566      result = vn_call_vkGetFenceStatus(dev->instance, device, _fence);
567      break;
568   case VN_SYNC_TYPE_WSI_SIGNALED:
569      result = VK_SUCCESS;
570      break;
571   default:
572      unreachable("unexpected fence payload type");
573      break;
574   }
575
576   return vn_result(dev->instance, result);
577}
578
579static VkResult
580vn_find_first_signaled_fence(VkDevice device,
581                             const VkFence *fences,
582                             uint32_t count)
583{
584   for (uint32_t i = 0; i < count; i++) {
585      VkResult result = vn_GetFenceStatus(device, fences[i]);
586      if (result == VK_SUCCESS || result < 0)
587         return result;
588   }
589   return VK_NOT_READY;
590}
591
592static VkResult
593vn_remove_signaled_fences(VkDevice device, VkFence *fences, uint32_t *count)
594{
595   uint32_t cur = 0;
596   for (uint32_t i = 0; i < *count; i++) {
597      VkResult result = vn_GetFenceStatus(device, fences[i]);
598      if (result != VK_SUCCESS) {
599         if (result < 0)
600            return result;
601         fences[cur++] = fences[i];
602      }
603   }
604
605   *count = cur;
606   return cur ? VK_NOT_READY : VK_SUCCESS;
607}
608
609static VkResult
610vn_update_sync_result(VkResult result, int64_t abs_timeout, uint32_t *iter)
611{
612   switch (result) {
613   case VK_NOT_READY:
614      if (abs_timeout != OS_TIMEOUT_INFINITE &&
615          os_time_get_nano() >= abs_timeout)
616         result = VK_TIMEOUT;
617      else
618         vn_relax(iter, "client");
619      break;
620   default:
621      assert(result == VK_SUCCESS || result < 0);
622      break;
623   }
624
625   return result;
626}
627
628VkResult
629vn_WaitForFences(VkDevice device,
630                 uint32_t fenceCount,
631                 const VkFence *pFences,
632                 VkBool32 waitAll,
633                 uint64_t timeout)
634{
635   struct vn_device *dev = vn_device_from_handle(device);
636   const VkAllocationCallbacks *alloc = &dev->base.base.alloc;
637
638   const int64_t abs_timeout = os_time_get_absolute_timeout(timeout);
639   VkResult result = VK_NOT_READY;
640   uint32_t iter = 0;
641   if (fenceCount > 1 && waitAll) {
642      VkFence local_fences[8];
643      VkFence *fences = local_fences;
644      if (fenceCount > ARRAY_SIZE(local_fences)) {
645         fences =
646            vk_alloc(alloc, sizeof(*fences) * fenceCount, VN_DEFAULT_ALIGN,
647                     VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
648         if (!fences)
649            return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
650      }
651      memcpy(fences, pFences, sizeof(*fences) * fenceCount);
652
653      while (result == VK_NOT_READY) {
654         result = vn_remove_signaled_fences(device, fences, &fenceCount);
655         result = vn_update_sync_result(result, abs_timeout, &iter);
656      }
657
658      if (fences != local_fences)
659         vk_free(alloc, fences);
660   } else {
661      while (result == VK_NOT_READY) {
662         result = vn_find_first_signaled_fence(device, pFences, fenceCount);
663         result = vn_update_sync_result(result, abs_timeout, &iter);
664      }
665   }
666
667   return vn_result(dev->instance, result);
668}
669
670static VkResult
671vn_create_sync_file(struct vn_device *dev, int *out_fd)
672{
673   struct vn_renderer_sync *sync;
674   VkResult result = vn_renderer_sync_create(dev->renderer, 0,
675                                             VN_RENDERER_SYNC_BINARY, &sync);
676   if (result != VK_SUCCESS)
677      return vn_error(dev->instance, result);
678
679   const struct vn_renderer_submit submit = {
680      .batches =
681         &(const struct vn_renderer_submit_batch){
682            .syncs = &sync,
683            .sync_values = &(const uint64_t){ 1 },
684            .sync_count = 1,
685         },
686      .batch_count = 1,
687   };
688   result = vn_renderer_submit(dev->renderer, &submit);
689   if (result != VK_SUCCESS) {
690      vn_renderer_sync_destroy(dev->renderer, sync);
691      return vn_error(dev->instance, result);
692   }
693
694   *out_fd = vn_renderer_sync_export_syncobj(dev->renderer, sync, true);
695   vn_renderer_sync_destroy(dev->renderer, sync);
696
697   return *out_fd >= 0 ? VK_SUCCESS : VK_ERROR_TOO_MANY_OBJECTS;
698}
699
700VkResult
701vn_ImportFenceFdKHR(VkDevice device,
702                    const VkImportFenceFdInfoKHR *pImportFenceFdInfo)
703{
704   struct vn_device *dev = vn_device_from_handle(device);
705   struct vn_fence *fence = vn_fence_from_handle(pImportFenceFdInfo->fence);
706   ASSERTED const bool sync_file = pImportFenceFdInfo->handleType ==
707                                   VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
708   const int fd = pImportFenceFdInfo->fd;
709
710   assert(dev->instance->experimental.globalFencing);
711   assert(sync_file);
712   if (fd >= 0) {
713      if (sync_wait(fd, -1))
714         return vn_error(dev->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE);
715
716      close(fd);
717   }
718
719   /* abuse VN_SYNC_TYPE_WSI_SIGNALED */
720   vn_fence_signal_wsi(dev, fence);
721
722   return VK_SUCCESS;
723}
724
725VkResult
726vn_GetFenceFdKHR(VkDevice device,
727                 const VkFenceGetFdInfoKHR *pGetFdInfo,
728                 int *pFd)
729{
730   struct vn_device *dev = vn_device_from_handle(device);
731   struct vn_fence *fence = vn_fence_from_handle(pGetFdInfo->fence);
732   const bool sync_file =
733      pGetFdInfo->handleType == VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
734   struct vn_sync_payload *payload = fence->payload;
735
736   assert(dev->instance->experimental.globalFencing);
737   assert(sync_file);
738   int fd = -1;
739   if (payload->type == VN_SYNC_TYPE_DEVICE_ONLY) {
740      VkResult result = vn_create_sync_file(dev, &fd);
741      if (result != VK_SUCCESS)
742         return vn_error(dev->instance, result);
743   }
744
745   if (sync_file) {
746      vn_sync_payload_release(dev, &fence->temporary);
747      fence->payload = &fence->permanent;
748
749      /* XXX implies reset operation on the host fence */
750   }
751
752   *pFd = fd;
753   return VK_SUCCESS;
754}
755
756/* semaphore commands */
757
758static VkResult
759vn_semaphore_init_payloads(struct vn_device *dev,
760                           struct vn_semaphore *sem,
761                           uint64_t initial_val,
762                           const VkAllocationCallbacks *alloc)
763{
764   sem->permanent.type = VN_SYNC_TYPE_DEVICE_ONLY;
765   sem->temporary.type = VN_SYNC_TYPE_INVALID;
766   sem->payload = &sem->permanent;
767
768   return VK_SUCCESS;
769}
770
771static void
772vn_semaphore_reset_wsi(struct vn_device *dev, struct vn_semaphore *sem)
773{
774   struct vn_sync_payload *perm = &sem->permanent;
775
776   vn_sync_payload_release(dev, &sem->temporary);
777
778   sem->payload = perm;
779}
780
781void
782vn_semaphore_signal_wsi(struct vn_device *dev, struct vn_semaphore *sem)
783{
784   struct vn_sync_payload *temp = &sem->temporary;
785
786   vn_sync_payload_release(dev, temp);
787   temp->type = VN_SYNC_TYPE_WSI_SIGNALED;
788   sem->payload = temp;
789}
790
791VkResult
792vn_CreateSemaphore(VkDevice device,
793                   const VkSemaphoreCreateInfo *pCreateInfo,
794                   const VkAllocationCallbacks *pAllocator,
795                   VkSemaphore *pSemaphore)
796{
797   struct vn_device *dev = vn_device_from_handle(device);
798   const VkAllocationCallbacks *alloc =
799      pAllocator ? pAllocator : &dev->base.base.alloc;
800
801   struct vn_semaphore *sem = vk_zalloc(alloc, sizeof(*sem), VN_DEFAULT_ALIGN,
802                                        VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
803   if (!sem)
804      return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
805
806   vn_object_base_init(&sem->base, VK_OBJECT_TYPE_SEMAPHORE, &dev->base);
807
808   const VkSemaphoreTypeCreateInfo *type_info =
809      vk_find_struct_const(pCreateInfo->pNext, SEMAPHORE_TYPE_CREATE_INFO);
810   uint64_t initial_val = 0;
811   if (type_info && type_info->semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE) {
812      sem->type = VK_SEMAPHORE_TYPE_TIMELINE;
813      initial_val = type_info->initialValue;
814   } else {
815      sem->type = VK_SEMAPHORE_TYPE_BINARY;
816   }
817
818   VkResult result = vn_semaphore_init_payloads(dev, sem, initial_val, alloc);
819   if (result != VK_SUCCESS) {
820      vn_object_base_fini(&sem->base);
821      vk_free(alloc, sem);
822      return vn_error(dev->instance, result);
823   }
824
825   VkSemaphore sem_handle = vn_semaphore_to_handle(sem);
826   vn_async_vkCreateSemaphore(dev->instance, device, pCreateInfo, NULL,
827                              &sem_handle);
828
829   *pSemaphore = sem_handle;
830
831   return VK_SUCCESS;
832}
833
834void
835vn_DestroySemaphore(VkDevice device,
836                    VkSemaphore semaphore,
837                    const VkAllocationCallbacks *pAllocator)
838{
839   struct vn_device *dev = vn_device_from_handle(device);
840   struct vn_semaphore *sem = vn_semaphore_from_handle(semaphore);
841   const VkAllocationCallbacks *alloc =
842      pAllocator ? pAllocator : &dev->base.base.alloc;
843
844   if (!sem)
845      return;
846
847   vn_async_vkDestroySemaphore(dev->instance, device, semaphore, NULL);
848
849   vn_sync_payload_release(dev, &sem->permanent);
850   vn_sync_payload_release(dev, &sem->temporary);
851
852   vn_object_base_fini(&sem->base);
853   vk_free(alloc, sem);
854}
855
856VkResult
857vn_GetSemaphoreCounterValue(VkDevice device,
858                            VkSemaphore semaphore,
859                            uint64_t *pValue)
860{
861   struct vn_device *dev = vn_device_from_handle(device);
862   struct vn_semaphore *sem = vn_semaphore_from_handle(semaphore);
863   ASSERTED struct vn_sync_payload *payload = sem->payload;
864
865   assert(payload->type == VN_SYNC_TYPE_DEVICE_ONLY);
866   return vn_call_vkGetSemaphoreCounterValue(dev->instance, device, semaphore,
867                                             pValue);
868}
869
870VkResult
871vn_SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo *pSignalInfo)
872{
873   struct vn_device *dev = vn_device_from_handle(device);
874
875   /* TODO if the semaphore is shared-by-ref, this needs to be synchronous */
876   if (false)
877      vn_call_vkSignalSemaphore(dev->instance, device, pSignalInfo);
878   else
879      vn_async_vkSignalSemaphore(dev->instance, device, pSignalInfo);
880
881   return VK_SUCCESS;
882}
883
884static VkResult
885vn_find_first_signaled_semaphore(VkDevice device,
886                                 const VkSemaphore *semaphores,
887                                 const uint64_t *values,
888                                 uint32_t count)
889{
890   for (uint32_t i = 0; i < count; i++) {
891      uint64_t val = 0;
892      VkResult result =
893         vn_GetSemaphoreCounterValue(device, semaphores[i], &val);
894      if (result != VK_SUCCESS || val >= values[i])
895         return result;
896   }
897   return VK_NOT_READY;
898}
899
900static VkResult
901vn_remove_signaled_semaphores(VkDevice device,
902                              VkSemaphore *semaphores,
903                              uint64_t *values,
904                              uint32_t *count)
905{
906   uint32_t cur = 0;
907   for (uint32_t i = 0; i < *count; i++) {
908      uint64_t val = 0;
909      VkResult result =
910         vn_GetSemaphoreCounterValue(device, semaphores[i], &val);
911      if (result != VK_SUCCESS)
912         return result;
913      if (val < values[i])
914         semaphores[cur++] = semaphores[i];
915   }
916
917   *count = cur;
918   return cur ? VK_NOT_READY : VK_SUCCESS;
919}
920
921VkResult
922vn_WaitSemaphores(VkDevice device,
923                  const VkSemaphoreWaitInfo *pWaitInfo,
924                  uint64_t timeout)
925{
926   struct vn_device *dev = vn_device_from_handle(device);
927   const VkAllocationCallbacks *alloc = &dev->base.base.alloc;
928
929   const int64_t abs_timeout = os_time_get_absolute_timeout(timeout);
930   VkResult result = VK_NOT_READY;
931   uint32_t iter = 0;
932   if (pWaitInfo->semaphoreCount > 1 &&
933       !(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT)) {
934      uint32_t semaphore_count = pWaitInfo->semaphoreCount;
935      VkSemaphore local_semaphores[8];
936      uint64_t local_values[8];
937      VkSemaphore *semaphores = local_semaphores;
938      uint64_t *values = local_values;
939      if (semaphore_count > ARRAY_SIZE(local_semaphores)) {
940         semaphores = vk_alloc(
941            alloc, (sizeof(*semaphores) + sizeof(*values)) * semaphore_count,
942            VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
943         if (!semaphores)
944            return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
945
946         values = (uint64_t *)&semaphores[semaphore_count];
947      }
948      memcpy(semaphores, pWaitInfo->pSemaphores,
949             sizeof(*semaphores) * semaphore_count);
950      memcpy(values, pWaitInfo->pValues, sizeof(*values) * semaphore_count);
951
952      while (result == VK_NOT_READY) {
953         result = vn_remove_signaled_semaphores(device, semaphores, values,
954                                                &semaphore_count);
955         result = vn_update_sync_result(result, abs_timeout, &iter);
956      }
957
958      if (semaphores != local_semaphores)
959         vk_free(alloc, semaphores);
960   } else {
961      while (result == VK_NOT_READY) {
962         result = vn_find_first_signaled_semaphore(
963            device, pWaitInfo->pSemaphores, pWaitInfo->pValues,
964            pWaitInfo->semaphoreCount);
965         result = vn_update_sync_result(result, abs_timeout, &iter);
966      }
967   }
968
969   return vn_result(dev->instance, result);
970}
971
972VkResult
973vn_ImportSemaphoreFdKHR(
974   VkDevice device, const VkImportSemaphoreFdInfoKHR *pImportSemaphoreFdInfo)
975{
976   struct vn_device *dev = vn_device_from_handle(device);
977   struct vn_semaphore *sem =
978      vn_semaphore_from_handle(pImportSemaphoreFdInfo->semaphore);
979   ASSERTED const bool sync_file =
980      pImportSemaphoreFdInfo->handleType ==
981      VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
982   const int fd = pImportSemaphoreFdInfo->fd;
983
984   assert(dev->instance->experimental.globalFencing);
985   assert(sync_file);
986   if (fd >= 0) {
987      if (sync_wait(fd, -1))
988         return vn_error(dev->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE);
989
990      close(fd);
991   }
992
993   /* abuse VN_SYNC_TYPE_WSI_SIGNALED */
994   vn_semaphore_signal_wsi(dev, sem);
995
996   return VK_SUCCESS;
997}
998
999VkResult
1000vn_GetSemaphoreFdKHR(VkDevice device,
1001                     const VkSemaphoreGetFdInfoKHR *pGetFdInfo,
1002                     int *pFd)
1003{
1004   struct vn_device *dev = vn_device_from_handle(device);
1005   struct vn_semaphore *sem = vn_semaphore_from_handle(pGetFdInfo->semaphore);
1006   const bool sync_file =
1007      pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
1008   struct vn_sync_payload *payload = sem->payload;
1009
1010   assert(dev->instance->experimental.globalFencing);
1011   assert(sync_file);
1012   int fd = -1;
1013   if (payload->type == VN_SYNC_TYPE_DEVICE_ONLY) {
1014      VkResult result = vn_create_sync_file(dev, &fd);
1015      if (result != VK_SUCCESS)
1016         return vn_error(dev->instance, result);
1017   }
1018
1019   if (sync_file) {
1020      vn_sync_payload_release(dev, &sem->temporary);
1021      sem->payload = &sem->permanent;
1022
1023      /* XXX implies wait operation on the host semaphore */
1024   }
1025
1026   *pFd = fd;
1027   return VK_SUCCESS;
1028}
1029
1030/* event commands */
1031
1032VkResult
1033vn_CreateEvent(VkDevice device,
1034               const VkEventCreateInfo *pCreateInfo,
1035               const VkAllocationCallbacks *pAllocator,
1036               VkEvent *pEvent)
1037{
1038   struct vn_device *dev = vn_device_from_handle(device);
1039   const VkAllocationCallbacks *alloc =
1040      pAllocator ? pAllocator : &dev->base.base.alloc;
1041
1042   struct vn_event *ev = vk_zalloc(alloc, sizeof(*ev), VN_DEFAULT_ALIGN,
1043                                   VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1044   if (!ev)
1045      return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
1046
1047   vn_object_base_init(&ev->base, VK_OBJECT_TYPE_EVENT, &dev->base);
1048
1049   VkEvent ev_handle = vn_event_to_handle(ev);
1050   vn_async_vkCreateEvent(dev->instance, device, pCreateInfo, NULL,
1051                          &ev_handle);
1052
1053   *pEvent = ev_handle;
1054
1055   return VK_SUCCESS;
1056}
1057
1058void
1059vn_DestroyEvent(VkDevice device,
1060                VkEvent event,
1061                const VkAllocationCallbacks *pAllocator)
1062{
1063   struct vn_device *dev = vn_device_from_handle(device);
1064   struct vn_event *ev = vn_event_from_handle(event);
1065   const VkAllocationCallbacks *alloc =
1066      pAllocator ? pAllocator : &dev->base.base.alloc;
1067
1068   if (!ev)
1069      return;
1070
1071   vn_async_vkDestroyEvent(dev->instance, device, event, NULL);
1072
1073   vn_object_base_fini(&ev->base);
1074   vk_free(alloc, ev);
1075}
1076
1077VkResult
1078vn_GetEventStatus(VkDevice device, VkEvent event)
1079{
1080   struct vn_device *dev = vn_device_from_handle(device);
1081
1082   /* TODO When the renderer supports it (requires a new vk extension), there
1083    * should be a coherent memory backing the event.
1084    */
1085   VkResult result = vn_call_vkGetEventStatus(dev->instance, device, event);
1086
1087   return vn_result(dev->instance, result);
1088}
1089
1090VkResult
1091vn_SetEvent(VkDevice device, VkEvent event)
1092{
1093   struct vn_device *dev = vn_device_from_handle(device);
1094
1095   VkResult result = vn_call_vkSetEvent(dev->instance, device, event);
1096
1097   return vn_result(dev->instance, result);
1098}
1099
1100VkResult
1101vn_ResetEvent(VkDevice device, VkEvent event)
1102{
1103   struct vn_device *dev = vn_device_from_handle(device);
1104
1105   VkResult result = vn_call_vkResetEvent(dev->instance, device, event);
1106
1107   return vn_result(dev->instance, result);
1108}
1109