101e04c3fSmrg/*
201e04c3fSmrg * Copyright © 2015 Intel Corporation
301e04c3fSmrg *
401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
501e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
601e04c3fSmrg * to deal in the Software without restriction, including without limitation
701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
901e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1001e04c3fSmrg *
1101e04c3fSmrg * The above copyright notice and this permission notice (including the next
1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1301e04c3fSmrg * Software.
1401e04c3fSmrg *
1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2101e04c3fSmrg * IN THE SOFTWARE.
2201e04c3fSmrg */
2301e04c3fSmrg
2401e04c3fSmrg/**
2501e04c3fSmrg * This file implements VkQueue, VkFence, and VkSemaphore
2601e04c3fSmrg */
2701e04c3fSmrg
287ec681f3Smrg#include <errno.h>
2901e04c3fSmrg#include <fcntl.h>
3001e04c3fSmrg#include <unistd.h>
3101e04c3fSmrg
327ec681f3Smrg#include "util/os_file.h"
337ec681f3Smrg
3401e04c3fSmrg#include "anv_private.h"
357ec681f3Smrg#include "anv_measure.h"
3601e04c3fSmrg#include "vk_util.h"
3701e04c3fSmrg
387ec681f3Smrg#include "genxml/gen7_pack.h"
397ec681f3Smrg
407ec681f3Smrguint64_t anv_gettime_ns(void)
417ec681f3Smrg{
427ec681f3Smrg   struct timespec current;
437ec681f3Smrg   clock_gettime(CLOCK_MONOTONIC, &current);
447ec681f3Smrg   return (uint64_t)current.tv_sec * NSEC_PER_SEC + current.tv_nsec;
457ec681f3Smrg}
467ec681f3Smrg
477ec681f3Smrguint64_t anv_get_absolute_timeout(uint64_t timeout)
487ec681f3Smrg{
497ec681f3Smrg   if (timeout == 0)
507ec681f3Smrg      return 0;
517ec681f3Smrg   uint64_t current_time = anv_gettime_ns();
527ec681f3Smrg   uint64_t max_timeout = (uint64_t) INT64_MAX - current_time;
537ec681f3Smrg
547ec681f3Smrg   timeout = MIN2(max_timeout, timeout);
557ec681f3Smrg
567ec681f3Smrg   return (current_time + timeout);
577ec681f3Smrg}
587ec681f3Smrg
597ec681f3Smrgstatic int64_t anv_get_relative_timeout(uint64_t abs_timeout)
607ec681f3Smrg{
617ec681f3Smrg   uint64_t now = anv_gettime_ns();
627ec681f3Smrg
637ec681f3Smrg   /* We don't want negative timeouts.
647ec681f3Smrg    *
657ec681f3Smrg    * DRM_IOCTL_I915_GEM_WAIT uses a signed 64 bit timeout and is
667ec681f3Smrg    * supposed to block indefinitely timeouts < 0.  Unfortunately,
677ec681f3Smrg    * this was broken for a couple of kernel releases.  Since there's
687ec681f3Smrg    * no way to know whether or not the kernel we're using is one of
697ec681f3Smrg    * the broken ones, the best we can do is to clamp the timeout to
707ec681f3Smrg    * INT64_MAX.  This limits the maximum timeout from 584 years to
717ec681f3Smrg    * 292 years - likely not a big deal.
727ec681f3Smrg    */
737ec681f3Smrg   if (abs_timeout < now)
747ec681f3Smrg      return 0;
757ec681f3Smrg
767ec681f3Smrg   uint64_t rel_timeout = abs_timeout - now;
777ec681f3Smrg   if (rel_timeout > (uint64_t) INT64_MAX)
787ec681f3Smrg      rel_timeout = INT64_MAX;
797ec681f3Smrg
807ec681f3Smrg   return rel_timeout;
817ec681f3Smrg}
827ec681f3Smrg
837ec681f3Smrgstatic void anv_semaphore_impl_cleanup(struct anv_device *device,
847ec681f3Smrg                                       struct anv_semaphore_impl *impl);
857ec681f3Smrg
867ec681f3Smrgstatic void
877ec681f3Smrganv_queue_submit_free(struct anv_device *device,
887ec681f3Smrg                      struct anv_queue_submit *submit)
897ec681f3Smrg{
907ec681f3Smrg   const VkAllocationCallbacks *alloc = submit->alloc;
917ec681f3Smrg
927ec681f3Smrg   for (uint32_t i = 0; i < submit->temporary_semaphore_count; i++)
937ec681f3Smrg      anv_semaphore_impl_cleanup(device, &submit->temporary_semaphores[i]);
947ec681f3Smrg   /* Execbuf does not consume the in_fence.  It's our job to close it. */
957ec681f3Smrg   if (submit->in_fence != -1) {
967ec681f3Smrg      assert(!device->has_thread_submit);
977ec681f3Smrg      close(submit->in_fence);
987ec681f3Smrg   }
997ec681f3Smrg   if (submit->out_fence != -1) {
1007ec681f3Smrg      assert(!device->has_thread_submit);
1017ec681f3Smrg      close(submit->out_fence);
1027ec681f3Smrg   }
1037ec681f3Smrg   vk_free(alloc, submit->fences);
1047ec681f3Smrg   vk_free(alloc, submit->fence_values);
1057ec681f3Smrg   vk_free(alloc, submit->temporary_semaphores);
1067ec681f3Smrg   vk_free(alloc, submit->wait_timelines);
1077ec681f3Smrg   vk_free(alloc, submit->wait_timeline_values);
1087ec681f3Smrg   vk_free(alloc, submit->signal_timelines);
1097ec681f3Smrg   vk_free(alloc, submit->signal_timeline_values);
1107ec681f3Smrg   vk_free(alloc, submit->fence_bos);
1117ec681f3Smrg   vk_free(alloc, submit->cmd_buffers);
1127ec681f3Smrg   vk_free(alloc, submit);
1137ec681f3Smrg}
1147ec681f3Smrg
1157ec681f3Smrgstatic bool
1167ec681f3Smrganv_queue_submit_ready_locked(struct anv_queue_submit *submit)
1177ec681f3Smrg{
1187ec681f3Smrg   for (uint32_t i = 0; i < submit->wait_timeline_count; i++) {
1197ec681f3Smrg      if (submit->wait_timeline_values[i] > submit->wait_timelines[i]->highest_pending)
1207ec681f3Smrg         return false;
1217ec681f3Smrg   }
1227ec681f3Smrg
1237ec681f3Smrg   return true;
1247ec681f3Smrg}
1257ec681f3Smrg
1267ec681f3Smrgstatic VkResult
1277ec681f3Smrganv_timeline_init(struct anv_device *device,
1287ec681f3Smrg                  struct anv_timeline *timeline,
1297ec681f3Smrg                  uint64_t initial_value)
1307ec681f3Smrg{
1317ec681f3Smrg   timeline->highest_past =
1327ec681f3Smrg      timeline->highest_pending = initial_value;
1337ec681f3Smrg   list_inithead(&timeline->points);
1347ec681f3Smrg   list_inithead(&timeline->free_points);
1357ec681f3Smrg
1367ec681f3Smrg   return VK_SUCCESS;
1377ec681f3Smrg}
1387ec681f3Smrg
1397ec681f3Smrgstatic void
1407ec681f3Smrganv_timeline_finish(struct anv_device *device,
1417ec681f3Smrg                    struct anv_timeline *timeline)
1427ec681f3Smrg{
1437ec681f3Smrg   list_for_each_entry_safe(struct anv_timeline_point, point,
1447ec681f3Smrg                            &timeline->free_points, link) {
1457ec681f3Smrg      list_del(&point->link);
1467ec681f3Smrg      anv_device_release_bo(device, point->bo);
1477ec681f3Smrg      vk_free(&device->vk.alloc, point);
1487ec681f3Smrg   }
1497ec681f3Smrg   list_for_each_entry_safe(struct anv_timeline_point, point,
1507ec681f3Smrg                            &timeline->points, link) {
1517ec681f3Smrg      list_del(&point->link);
1527ec681f3Smrg      anv_device_release_bo(device, point->bo);
1537ec681f3Smrg      vk_free(&device->vk.alloc, point);
1547ec681f3Smrg   }
1557ec681f3Smrg}
1567ec681f3Smrg
1577ec681f3Smrgstatic VkResult
1587ec681f3Smrganv_timeline_add_point_locked(struct anv_device *device,
1597ec681f3Smrg                              struct anv_timeline *timeline,
1607ec681f3Smrg                              uint64_t value,
1617ec681f3Smrg                              struct anv_timeline_point **point)
1627ec681f3Smrg{
1637ec681f3Smrg   VkResult result = VK_SUCCESS;
1647ec681f3Smrg
1657ec681f3Smrg   if (list_is_empty(&timeline->free_points)) {
1667ec681f3Smrg      *point =
1677ec681f3Smrg         vk_zalloc(&device->vk.alloc, sizeof(**point),
1687ec681f3Smrg                   8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1697ec681f3Smrg      if (!(*point))
1707ec681f3Smrg         result = vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
1717ec681f3Smrg      if (result == VK_SUCCESS) {
1727ec681f3Smrg         result = anv_device_alloc_bo(device, "timeline-semaphore", 4096,
1737ec681f3Smrg                                      ANV_BO_ALLOC_EXTERNAL |
1747ec681f3Smrg                                      ANV_BO_ALLOC_IMPLICIT_SYNC,
1757ec681f3Smrg                                      0 /* explicit_address */,
1767ec681f3Smrg                                      &(*point)->bo);
1777ec681f3Smrg         if (result != VK_SUCCESS)
1787ec681f3Smrg            vk_free(&device->vk.alloc, *point);
1797ec681f3Smrg      }
1807ec681f3Smrg   } else {
1817ec681f3Smrg      *point = list_first_entry(&timeline->free_points,
1827ec681f3Smrg                                struct anv_timeline_point, link);
1837ec681f3Smrg      list_del(&(*point)->link);
1847ec681f3Smrg   }
1857ec681f3Smrg
1867ec681f3Smrg   if (result == VK_SUCCESS) {
1877ec681f3Smrg      (*point)->serial = value;
1887ec681f3Smrg      list_addtail(&(*point)->link, &timeline->points);
1897ec681f3Smrg   }
1907ec681f3Smrg
1917ec681f3Smrg   return result;
1927ec681f3Smrg}
1937ec681f3Smrg
1947ec681f3Smrgstatic VkResult
1957ec681f3Smrganv_timeline_gc_locked(struct anv_device *device,
1967ec681f3Smrg                       struct anv_timeline *timeline)
1977ec681f3Smrg{
1987ec681f3Smrg   list_for_each_entry_safe(struct anv_timeline_point, point,
1997ec681f3Smrg                            &timeline->points, link) {
2007ec681f3Smrg      /* timeline->higest_pending is only incremented once submission has
2017ec681f3Smrg       * happened. If this point has a greater serial, it means the point
2027ec681f3Smrg       * hasn't been submitted yet.
2037ec681f3Smrg       */
2047ec681f3Smrg      if (point->serial > timeline->highest_pending)
2057ec681f3Smrg         return VK_SUCCESS;
2067ec681f3Smrg
2077ec681f3Smrg      /* If someone is waiting on this time point, consider it busy and don't
2087ec681f3Smrg       * try to recycle it. There's a slim possibility that it's no longer
2097ec681f3Smrg       * busy by the time we look at it but we would be recycling it out from
2107ec681f3Smrg       * under a waiter and that can lead to weird races.
2117ec681f3Smrg       *
2127ec681f3Smrg       * We walk the list in-order so if this time point is still busy so is
2137ec681f3Smrg       * every following time point
2147ec681f3Smrg       */
2157ec681f3Smrg      assert(point->waiting >= 0);
2167ec681f3Smrg      if (point->waiting)
2177ec681f3Smrg         return VK_SUCCESS;
2187ec681f3Smrg
2197ec681f3Smrg      /* Garbage collect any signaled point. */
2207ec681f3Smrg      VkResult result = anv_device_bo_busy(device, point->bo);
2217ec681f3Smrg      if (result == VK_NOT_READY) {
2227ec681f3Smrg         /* We walk the list in-order so if this time point is still busy so
2237ec681f3Smrg          * is every following time point
2247ec681f3Smrg          */
2257ec681f3Smrg         return VK_SUCCESS;
2267ec681f3Smrg      } else if (result != VK_SUCCESS) {
2277ec681f3Smrg         return result;
2287ec681f3Smrg      }
2297ec681f3Smrg
2307ec681f3Smrg      assert(timeline->highest_past < point->serial);
2317ec681f3Smrg      timeline->highest_past = point->serial;
2327ec681f3Smrg
2337ec681f3Smrg      list_del(&point->link);
2347ec681f3Smrg      list_add(&point->link, &timeline->free_points);
2357ec681f3Smrg   }
2367ec681f3Smrg
2377ec681f3Smrg   return VK_SUCCESS;
2387ec681f3Smrg}
2397ec681f3Smrg
2407ec681f3Smrgstatic VkResult anv_queue_submit_add_fence_bo(struct anv_queue *queue,
2417ec681f3Smrg                                              struct anv_queue_submit *submit,
2427ec681f3Smrg                                              struct anv_bo *bo,
2437ec681f3Smrg                                              bool signal);
2447ec681f3Smrg
2457ec681f3Smrgstatic VkResult
2467ec681f3Smrganv_queue_submit_timeline_locked(struct anv_queue *queue,
2477ec681f3Smrg                                 struct anv_queue_submit *submit)
2487ec681f3Smrg{
2497ec681f3Smrg   VkResult result;
2507ec681f3Smrg
2517ec681f3Smrg   for (uint32_t i = 0; i < submit->wait_timeline_count; i++) {
2527ec681f3Smrg      struct anv_timeline *timeline = submit->wait_timelines[i];
2537ec681f3Smrg      uint64_t wait_value = submit->wait_timeline_values[i];
2547ec681f3Smrg
2557ec681f3Smrg      if (timeline->highest_past >= wait_value)
2567ec681f3Smrg         continue;
2577ec681f3Smrg
2587ec681f3Smrg      list_for_each_entry(struct anv_timeline_point, point, &timeline->points, link) {
2597ec681f3Smrg         if (point->serial < wait_value)
2607ec681f3Smrg            continue;
2617ec681f3Smrg         result = anv_queue_submit_add_fence_bo(queue, submit, point->bo, false);
2627ec681f3Smrg         if (result != VK_SUCCESS)
2637ec681f3Smrg            return result;
2647ec681f3Smrg         break;
2657ec681f3Smrg      }
2667ec681f3Smrg   }
2677ec681f3Smrg   for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {
2687ec681f3Smrg      struct anv_timeline *timeline = submit->signal_timelines[i];
2697ec681f3Smrg      uint64_t signal_value = submit->signal_timeline_values[i];
2707ec681f3Smrg      struct anv_timeline_point *point;
2717ec681f3Smrg
2727ec681f3Smrg      result = anv_timeline_add_point_locked(queue->device, timeline,
2737ec681f3Smrg                                             signal_value, &point);
2747ec681f3Smrg      if (result != VK_SUCCESS)
2757ec681f3Smrg         return result;
2767ec681f3Smrg
2777ec681f3Smrg      result = anv_queue_submit_add_fence_bo(queue, submit, point->bo, true);
2787ec681f3Smrg      if (result != VK_SUCCESS)
2797ec681f3Smrg         return result;
2807ec681f3Smrg   }
2817ec681f3Smrg
2827ec681f3Smrg   result = anv_queue_execbuf_locked(queue, submit);
2837ec681f3Smrg
2847ec681f3Smrg   if (result == VK_SUCCESS) {
2857ec681f3Smrg      /* Update the pending values in the timeline objects. */
2867ec681f3Smrg      for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {
2877ec681f3Smrg         struct anv_timeline *timeline = submit->signal_timelines[i];
2887ec681f3Smrg         uint64_t signal_value = submit->signal_timeline_values[i];
2897ec681f3Smrg
2907ec681f3Smrg         assert(signal_value > timeline->highest_pending);
2917ec681f3Smrg         timeline->highest_pending = signal_value;
2927ec681f3Smrg      }
2937ec681f3Smrg   } else {
2947ec681f3Smrg      /* Unblock any waiter by signaling the points, the application will get
2957ec681f3Smrg       * a device lost error code.
2967ec681f3Smrg       */
2977ec681f3Smrg      for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {
2987ec681f3Smrg         struct anv_timeline *timeline = submit->signal_timelines[i];
2997ec681f3Smrg         uint64_t signal_value = submit->signal_timeline_values[i];
3007ec681f3Smrg
3017ec681f3Smrg         assert(signal_value > timeline->highest_pending);
3027ec681f3Smrg         timeline->highest_past = timeline->highest_pending = signal_value;
3037ec681f3Smrg      }
3047ec681f3Smrg   }
3057ec681f3Smrg
3067ec681f3Smrg   return result;
3077ec681f3Smrg}
3087ec681f3Smrg
3097ec681f3Smrgstatic VkResult
3107ec681f3Smrganv_queue_submit_deferred_locked(struct anv_queue *queue, uint32_t *advance)
3117ec681f3Smrg{
3127ec681f3Smrg   VkResult result = VK_SUCCESS;
3137ec681f3Smrg
3147ec681f3Smrg   /* Go through all the queued submissions and submit then until we find one
3157ec681f3Smrg    * that's waiting on a point that hasn't materialized yet.
3167ec681f3Smrg    */
3177ec681f3Smrg   list_for_each_entry_safe(struct anv_queue_submit, submit,
3187ec681f3Smrg                            &queue->queued_submits, link) {
3197ec681f3Smrg      if (!anv_queue_submit_ready_locked(submit))
3207ec681f3Smrg         break;
3217ec681f3Smrg
3227ec681f3Smrg      (*advance)++;
3237ec681f3Smrg      list_del(&submit->link);
3247ec681f3Smrg
3257ec681f3Smrg      result = anv_queue_submit_timeline_locked(queue, submit);
3267ec681f3Smrg
3277ec681f3Smrg      anv_queue_submit_free(queue->device, submit);
3287ec681f3Smrg
3297ec681f3Smrg      if (result != VK_SUCCESS)
3307ec681f3Smrg         break;
3317ec681f3Smrg   }
3327ec681f3Smrg
3337ec681f3Smrg   return result;
3347ec681f3Smrg}
3357ec681f3Smrg
3367ec681f3Smrgstatic VkResult
3377ec681f3Smrganv_device_submit_deferred_locked(struct anv_device *device)
3387ec681f3Smrg{
3397ec681f3Smrg   VkResult result = VK_SUCCESS;
3407ec681f3Smrg
3417ec681f3Smrg   uint32_t advance;
3427ec681f3Smrg   do {
3437ec681f3Smrg      advance = 0;
3447ec681f3Smrg      for (uint32_t i = 0; i < device->queue_count; i++) {
3457ec681f3Smrg         struct anv_queue *queue = &device->queues[i];
3467ec681f3Smrg         VkResult qres = anv_queue_submit_deferred_locked(queue, &advance);
3477ec681f3Smrg         if (qres != VK_SUCCESS)
3487ec681f3Smrg            result = qres;
3497ec681f3Smrg      }
3507ec681f3Smrg   } while (advance);
3517ec681f3Smrg
3527ec681f3Smrg   return result;
3537ec681f3Smrg}
3547ec681f3Smrg
3557ec681f3Smrgstatic void
3567ec681f3Smrganv_queue_submit_signal_fences(struct anv_device *device,
3577ec681f3Smrg                               struct anv_queue_submit *submit)
3587ec681f3Smrg{
3597ec681f3Smrg   for (uint32_t i = 0; i < submit->fence_count; i++) {
3607ec681f3Smrg      if (submit->fences[i].flags & I915_EXEC_FENCE_SIGNAL) {
3617ec681f3Smrg         anv_gem_syncobj_timeline_signal(device, &submit->fences[i].handle,
3627ec681f3Smrg                                         &submit->fence_values[i], 1);
3637ec681f3Smrg      }
3647ec681f3Smrg   }
3657ec681f3Smrg}
3667ec681f3Smrg
3677ec681f3Smrgstatic void *
3687ec681f3Smrganv_queue_task(void *_queue)
3697ec681f3Smrg{
3707ec681f3Smrg   struct anv_queue *queue = _queue;
3717ec681f3Smrg
3727ec681f3Smrg   pthread_mutex_lock(&queue->mutex);
3737ec681f3Smrg
3747ec681f3Smrg   while (!queue->quit) {
3757ec681f3Smrg      while (!list_is_empty(&queue->queued_submits)) {
3767ec681f3Smrg         struct anv_queue_submit *submit =
3777ec681f3Smrg            list_first_entry(&queue->queued_submits, struct anv_queue_submit, link);
3787ec681f3Smrg         list_del(&submit->link);
3797ec681f3Smrg
3807ec681f3Smrg         pthread_mutex_unlock(&queue->mutex);
3817ec681f3Smrg
3827ec681f3Smrg         VkResult result = VK_ERROR_DEVICE_LOST;
3837ec681f3Smrg
3847ec681f3Smrg         /* Wait for timeline points to materialize before submitting. We need
3857ec681f3Smrg          * to do this because we're using threads to do the submit to i915.
3867ec681f3Smrg          * We could end up in a situation where the application submits to 2
3877ec681f3Smrg          * queues with the first submit creating the dma-fence for the
3887ec681f3Smrg          * second. But because the scheduling of the submission threads might
3897ec681f3Smrg          * wakeup the second queue thread first, this would make that execbuf
3907ec681f3Smrg          * fail because the dma-fence it depends on hasn't materialized yet.
3917ec681f3Smrg          */
3927ec681f3Smrg         if (!queue->lost && submit->wait_timeline_count > 0) {
3937ec681f3Smrg            int ret = queue->device->info.no_hw ? 0 :
3947ec681f3Smrg               anv_gem_syncobj_timeline_wait(
3957ec681f3Smrg                  queue->device, submit->wait_timeline_syncobjs,
3967ec681f3Smrg                  submit->wait_timeline_values, submit->wait_timeline_count,
3977ec681f3Smrg                  anv_get_absolute_timeout(UINT64_MAX) /* wait forever */,
3987ec681f3Smrg                  true /* wait for all */, true /* wait for materialize */);
3997ec681f3Smrg            if (ret) {
4007ec681f3Smrg               result = anv_queue_set_lost(queue, "timeline timeout: %s",
4017ec681f3Smrg                                           strerror(errno));
4027ec681f3Smrg            }
4037ec681f3Smrg         }
4047ec681f3Smrg
4057ec681f3Smrg         /* Now submit */
4067ec681f3Smrg         if (!queue->lost) {
4077ec681f3Smrg            pthread_mutex_lock(&queue->device->mutex);
4087ec681f3Smrg            result = anv_queue_execbuf_locked(queue, submit);
4097ec681f3Smrg            pthread_mutex_unlock(&queue->device->mutex);
4107ec681f3Smrg         }
4117ec681f3Smrg
4127ec681f3Smrg         if (result != VK_SUCCESS) {
4137ec681f3Smrg            /* vkQueueSubmit or some other entry point will report the
4147ec681f3Smrg             * DEVICE_LOST error at some point, but until we have emptied our
4157ec681f3Smrg             * list of execbufs we need to wake up all potential the waiters
4167ec681f3Smrg             * until one of them spots the error.
4177ec681f3Smrg             */
4187ec681f3Smrg            anv_queue_submit_signal_fences(queue->device, submit);
4197ec681f3Smrg         }
4207ec681f3Smrg
4217ec681f3Smrg         anv_queue_submit_free(queue->device, submit);
4227ec681f3Smrg
4237ec681f3Smrg         pthread_mutex_lock(&queue->mutex);
4247ec681f3Smrg      }
4257ec681f3Smrg
4267ec681f3Smrg      if (!queue->quit)
4277ec681f3Smrg         pthread_cond_wait(&queue->cond, &queue->mutex);
4287ec681f3Smrg   }
4297ec681f3Smrg
4307ec681f3Smrg   pthread_mutex_unlock(&queue->mutex);
4317ec681f3Smrg
4327ec681f3Smrg   return NULL;
4337ec681f3Smrg}
4347ec681f3Smrg
4357ec681f3Smrgstatic VkResult
4367ec681f3Smrganv_queue_submit_post(struct anv_queue *queue,
4377ec681f3Smrg                      struct anv_queue_submit **_submit,
4387ec681f3Smrg                      bool flush_queue)
4397ec681f3Smrg{
4407ec681f3Smrg   struct anv_queue_submit *submit = *_submit;
4417ec681f3Smrg
4427ec681f3Smrg   /* Wait before signal behavior means we might keep alive the
4437ec681f3Smrg    * anv_queue_submit object a bit longer, so transfer the ownership to the
4447ec681f3Smrg    * anv_queue.
4457ec681f3Smrg    */
4467ec681f3Smrg   *_submit = NULL;
4477ec681f3Smrg   if (queue->device->has_thread_submit) {
4487ec681f3Smrg      pthread_mutex_lock(&queue->mutex);
4497ec681f3Smrg      pthread_cond_broadcast(&queue->cond);
4507ec681f3Smrg      list_addtail(&submit->link, &queue->queued_submits);
4517ec681f3Smrg      pthread_mutex_unlock(&queue->mutex);
4527ec681f3Smrg      return VK_SUCCESS;
4537ec681f3Smrg   } else {
4547ec681f3Smrg      pthread_mutex_lock(&queue->device->mutex);
4557ec681f3Smrg      list_addtail(&submit->link, &queue->queued_submits);
4567ec681f3Smrg      VkResult result = anv_device_submit_deferred_locked(queue->device);
4577ec681f3Smrg      if (flush_queue) {
4587ec681f3Smrg         while (result == VK_SUCCESS && !list_is_empty(&queue->queued_submits)) {
4597ec681f3Smrg            int ret = pthread_cond_wait(&queue->device->queue_submit,
4607ec681f3Smrg                                        &queue->device->mutex);
4617ec681f3Smrg            if (ret != 0) {
4627ec681f3Smrg               result = anv_device_set_lost(queue->device, "wait timeout");
4637ec681f3Smrg               break;
4647ec681f3Smrg            }
4657ec681f3Smrg
4667ec681f3Smrg            result = anv_device_submit_deferred_locked(queue->device);
4677ec681f3Smrg         }
4687ec681f3Smrg      }
4697ec681f3Smrg      pthread_mutex_unlock(&queue->device->mutex);
4707ec681f3Smrg      return result;
4717ec681f3Smrg   }
4727ec681f3Smrg}
4737ec681f3Smrg
4747ec681f3SmrgVkResult
4757ec681f3Smrganv_queue_init(struct anv_device *device, struct anv_queue *queue,
4767ec681f3Smrg               uint32_t exec_flags,
4777ec681f3Smrg               const VkDeviceQueueCreateInfo *pCreateInfo,
4787ec681f3Smrg               uint32_t index_in_family)
4797ec681f3Smrg{
4807ec681f3Smrg   struct anv_physical_device *pdevice = device->physical;
4817ec681f3Smrg   VkResult result;
4827ec681f3Smrg
4837ec681f3Smrg   result = vk_queue_init(&queue->vk, &device->vk, pCreateInfo,
4847ec681f3Smrg                          index_in_family);
4857ec681f3Smrg   if (result != VK_SUCCESS)
4867ec681f3Smrg      return result;
4877ec681f3Smrg
4887ec681f3Smrg   queue->device = device;
4897ec681f3Smrg
4907ec681f3Smrg   assert(queue->vk.queue_family_index < pdevice->queue.family_count);
4917ec681f3Smrg   queue->family = &pdevice->queue.families[queue->vk.queue_family_index];
4927ec681f3Smrg
4937ec681f3Smrg   queue->exec_flags = exec_flags;
4947ec681f3Smrg   queue->lost = false;
4957ec681f3Smrg   queue->quit = false;
4967ec681f3Smrg
4977ec681f3Smrg   list_inithead(&queue->queued_submits);
4987ec681f3Smrg
4997ec681f3Smrg   /* We only need those additional thread/mutex when using a thread for
5007ec681f3Smrg    * submission.
5017ec681f3Smrg    */
5027ec681f3Smrg   if (device->has_thread_submit) {
5037ec681f3Smrg      if (pthread_mutex_init(&queue->mutex, NULL) != 0) {
5047ec681f3Smrg         result = vk_error(device, VK_ERROR_INITIALIZATION_FAILED);
5057ec681f3Smrg         goto fail_queue;
5067ec681f3Smrg      }
5077ec681f3Smrg      if (pthread_cond_init(&queue->cond, NULL) != 0) {
5087ec681f3Smrg         result = vk_error(device, VK_ERROR_INITIALIZATION_FAILED);
5097ec681f3Smrg         goto fail_mutex;
5107ec681f3Smrg      }
5117ec681f3Smrg      if (pthread_create(&queue->thread, NULL, anv_queue_task, queue)) {
5127ec681f3Smrg         result = vk_error(device, VK_ERROR_INITIALIZATION_FAILED);
5137ec681f3Smrg         goto fail_cond;
5147ec681f3Smrg      }
5157ec681f3Smrg   }
5167ec681f3Smrg
5177ec681f3Smrg   return VK_SUCCESS;
5187ec681f3Smrg
5197ec681f3Smrg fail_cond:
5207ec681f3Smrg   pthread_cond_destroy(&queue->cond);
5217ec681f3Smrg fail_mutex:
5227ec681f3Smrg   pthread_mutex_destroy(&queue->mutex);
5237ec681f3Smrg fail_queue:
5247ec681f3Smrg   vk_queue_finish(&queue->vk);
5257ec681f3Smrg
5267ec681f3Smrg   return result;
5277ec681f3Smrg}
5287ec681f3Smrg
5297ec681f3Smrgvoid
5307ec681f3Smrganv_queue_finish(struct anv_queue *queue)
5317ec681f3Smrg{
5327ec681f3Smrg   if (queue->device->has_thread_submit) {
5337ec681f3Smrg      pthread_mutex_lock(&queue->mutex);
5347ec681f3Smrg      pthread_cond_broadcast(&queue->cond);
5357ec681f3Smrg      queue->quit = true;
5367ec681f3Smrg      pthread_mutex_unlock(&queue->mutex);
5377ec681f3Smrg
5387ec681f3Smrg      void *ret;
5397ec681f3Smrg      pthread_join(queue->thread, &ret);
5407ec681f3Smrg
5417ec681f3Smrg      pthread_cond_destroy(&queue->cond);
5427ec681f3Smrg      pthread_mutex_destroy(&queue->mutex);
5437ec681f3Smrg   }
5447ec681f3Smrg
5457ec681f3Smrg   vk_queue_finish(&queue->vk);
5467ec681f3Smrg}
5477ec681f3Smrg
5487ec681f3Smrgstatic VkResult
5497ec681f3Smrganv_queue_submit_add_fence_bo(struct anv_queue *queue,
5507ec681f3Smrg                              struct anv_queue_submit *submit,
5517ec681f3Smrg                              struct anv_bo *bo,
5527ec681f3Smrg                              bool signal)
5537ec681f3Smrg{
5547ec681f3Smrg   if (submit->fence_bo_count >= submit->fence_bo_array_length) {
5557ec681f3Smrg      uint32_t new_len = MAX2(submit->fence_bo_array_length * 2, 64);
5567ec681f3Smrg      uintptr_t *new_fence_bos =
5577ec681f3Smrg         vk_realloc(submit->alloc,
5587ec681f3Smrg                    submit->fence_bos, new_len * sizeof(*submit->fence_bos),
5597ec681f3Smrg                    8, submit->alloc_scope);
5607ec681f3Smrg      if (new_fence_bos == NULL)
5617ec681f3Smrg         return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
5627ec681f3Smrg
5637ec681f3Smrg      submit->fence_bos = new_fence_bos;
5647ec681f3Smrg      submit->fence_bo_array_length = new_len;
5657ec681f3Smrg   }
5667ec681f3Smrg
5677ec681f3Smrg   /* Take advantage that anv_bo are allocated at 8 byte alignement so we can
5687ec681f3Smrg    * use the lowest bit to store whether this is a BO we need to signal.
5697ec681f3Smrg    */
5707ec681f3Smrg   submit->fence_bos[submit->fence_bo_count++] = anv_pack_ptr(bo, 1, signal);
5717ec681f3Smrg
5727ec681f3Smrg   return VK_SUCCESS;
5737ec681f3Smrg}
5747ec681f3Smrg
5757ec681f3Smrgstatic VkResult
5767ec681f3Smrganv_queue_submit_add_syncobj(struct anv_queue *queue,
5777ec681f3Smrg                             struct anv_queue_submit* submit,
5787ec681f3Smrg                             uint32_t handle, uint32_t flags,
5797ec681f3Smrg                             uint64_t value)
5807ec681f3Smrg{
5817ec681f3Smrg   assert(flags != 0);
5827ec681f3Smrg
5837ec681f3Smrg   if (queue->device->has_thread_submit && (flags & I915_EXEC_FENCE_WAIT)) {
5847ec681f3Smrg      if (submit->wait_timeline_count >= submit->wait_timeline_array_length) {
5857ec681f3Smrg         uint32_t new_len = MAX2(submit->wait_timeline_array_length * 2, 64);
5867ec681f3Smrg
5877ec681f3Smrg         uint32_t *new_wait_timeline_syncobjs =
5887ec681f3Smrg            vk_realloc(submit->alloc,
5897ec681f3Smrg                       submit->wait_timeline_syncobjs,
5907ec681f3Smrg                       new_len * sizeof(*submit->wait_timeline_syncobjs),
5917ec681f3Smrg                       8, submit->alloc_scope);
5927ec681f3Smrg         if (new_wait_timeline_syncobjs == NULL)
5937ec681f3Smrg            return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
5947ec681f3Smrg
5957ec681f3Smrg         submit->wait_timeline_syncobjs = new_wait_timeline_syncobjs;
5967ec681f3Smrg
5977ec681f3Smrg         uint64_t *new_wait_timeline_values =
5987ec681f3Smrg            vk_realloc(submit->alloc,
5997ec681f3Smrg                       submit->wait_timeline_values, new_len * sizeof(*submit->wait_timeline_values),
6007ec681f3Smrg                       8, submit->alloc_scope);
6017ec681f3Smrg         if (new_wait_timeline_values == NULL)
6027ec681f3Smrg            return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
6037ec681f3Smrg
6047ec681f3Smrg         submit->wait_timeline_values = new_wait_timeline_values;
6057ec681f3Smrg         submit->wait_timeline_array_length = new_len;
6067ec681f3Smrg      }
6077ec681f3Smrg
6087ec681f3Smrg      submit->wait_timeline_syncobjs[submit->wait_timeline_count] = handle;
6097ec681f3Smrg      submit->wait_timeline_values[submit->wait_timeline_count] = value;
6107ec681f3Smrg
6117ec681f3Smrg      submit->wait_timeline_count++;
6127ec681f3Smrg   }
6137ec681f3Smrg
6147ec681f3Smrg   if (submit->fence_count >= submit->fence_array_length) {
6157ec681f3Smrg      uint32_t new_len = MAX2(submit->fence_array_length * 2, 64);
6167ec681f3Smrg      struct drm_i915_gem_exec_fence *new_fences =
6177ec681f3Smrg         vk_realloc(submit->alloc,
6187ec681f3Smrg                    submit->fences, new_len * sizeof(*submit->fences),
6197ec681f3Smrg                    8, submit->alloc_scope);
6207ec681f3Smrg      if (new_fences == NULL)
6217ec681f3Smrg         return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
6227ec681f3Smrg
6237ec681f3Smrg      submit->fences = new_fences;
6247ec681f3Smrg
6257ec681f3Smrg      uint64_t *new_fence_values =
6267ec681f3Smrg         vk_realloc(submit->alloc,
6277ec681f3Smrg                    submit->fence_values, new_len * sizeof(*submit->fence_values),
6287ec681f3Smrg                    8, submit->alloc_scope);
6297ec681f3Smrg      if (new_fence_values == NULL)
6307ec681f3Smrg         return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
6317ec681f3Smrg
6327ec681f3Smrg      submit->fence_values = new_fence_values;
6337ec681f3Smrg      submit->fence_array_length = new_len;
6347ec681f3Smrg   }
6357ec681f3Smrg
6367ec681f3Smrg   submit->fences[submit->fence_count] = (struct drm_i915_gem_exec_fence) {
6377ec681f3Smrg      .handle = handle,
6387ec681f3Smrg      .flags = flags,
6397ec681f3Smrg   };
6407ec681f3Smrg   submit->fence_values[submit->fence_count] = value;
6417ec681f3Smrg   submit->fence_count++;
6427ec681f3Smrg
6437ec681f3Smrg   return VK_SUCCESS;
6447ec681f3Smrg}
6457ec681f3Smrg
6467ec681f3Smrgstatic VkResult
6477ec681f3Smrganv_queue_submit_add_timeline_wait(struct anv_queue *queue,
6487ec681f3Smrg                                   struct anv_queue_submit* submit,
6497ec681f3Smrg                                   struct anv_timeline *timeline,
6507ec681f3Smrg                                   uint64_t value)
6517ec681f3Smrg{
6527ec681f3Smrg   if (submit->wait_timeline_count >= submit->wait_timeline_array_length) {
6537ec681f3Smrg      uint32_t new_len = MAX2(submit->wait_timeline_array_length * 2, 64);
6547ec681f3Smrg      struct anv_timeline **new_wait_timelines =
6557ec681f3Smrg         vk_realloc(submit->alloc,
6567ec681f3Smrg                    submit->wait_timelines, new_len * sizeof(*submit->wait_timelines),
6577ec681f3Smrg                    8, submit->alloc_scope);
6587ec681f3Smrg      if (new_wait_timelines == NULL)
6597ec681f3Smrg         return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
6607ec681f3Smrg
6617ec681f3Smrg      submit->wait_timelines = new_wait_timelines;
6627ec681f3Smrg
6637ec681f3Smrg      uint64_t *new_wait_timeline_values =
6647ec681f3Smrg         vk_realloc(submit->alloc,
6657ec681f3Smrg                    submit->wait_timeline_values, new_len * sizeof(*submit->wait_timeline_values),
6667ec681f3Smrg                    8, submit->alloc_scope);
6677ec681f3Smrg      if (new_wait_timeline_values == NULL)
6687ec681f3Smrg         return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
6697ec681f3Smrg
6707ec681f3Smrg      submit->wait_timeline_values = new_wait_timeline_values;
6717ec681f3Smrg
6727ec681f3Smrg      submit->wait_timeline_array_length = new_len;
6737ec681f3Smrg   }
6747ec681f3Smrg
6757ec681f3Smrg   submit->wait_timelines[submit->wait_timeline_count] = timeline;
6767ec681f3Smrg   submit->wait_timeline_values[submit->wait_timeline_count] = value;
6777ec681f3Smrg
6787ec681f3Smrg   submit->wait_timeline_count++;
6797ec681f3Smrg
6807ec681f3Smrg   return VK_SUCCESS;
6817ec681f3Smrg}
6827ec681f3Smrg
6837ec681f3Smrgstatic VkResult
6847ec681f3Smrganv_queue_submit_add_timeline_signal(struct anv_queue *queue,
6857ec681f3Smrg                                     struct anv_queue_submit* submit,
6867ec681f3Smrg                                     struct anv_timeline *timeline,
6877ec681f3Smrg                                     uint64_t value)
6887ec681f3Smrg{
6897ec681f3Smrg   assert(timeline->highest_pending < value);
6907ec681f3Smrg
6917ec681f3Smrg   if (submit->signal_timeline_count >= submit->signal_timeline_array_length) {
6927ec681f3Smrg      uint32_t new_len = MAX2(submit->signal_timeline_array_length * 2, 64);
6937ec681f3Smrg      struct anv_timeline **new_signal_timelines =
6947ec681f3Smrg         vk_realloc(submit->alloc,
6957ec681f3Smrg                    submit->signal_timelines, new_len * sizeof(*submit->signal_timelines),
6967ec681f3Smrg                    8, submit->alloc_scope);
6977ec681f3Smrg      if (new_signal_timelines == NULL)
6987ec681f3Smrg            return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
6997ec681f3Smrg
7007ec681f3Smrg      submit->signal_timelines = new_signal_timelines;
7017ec681f3Smrg
7027ec681f3Smrg      uint64_t *new_signal_timeline_values =
7037ec681f3Smrg         vk_realloc(submit->alloc,
7047ec681f3Smrg                    submit->signal_timeline_values, new_len * sizeof(*submit->signal_timeline_values),
7057ec681f3Smrg                    8, submit->alloc_scope);
7067ec681f3Smrg      if (new_signal_timeline_values == NULL)
7077ec681f3Smrg         return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
7087ec681f3Smrg
7097ec681f3Smrg      submit->signal_timeline_values = new_signal_timeline_values;
7107ec681f3Smrg
7117ec681f3Smrg      submit->signal_timeline_array_length = new_len;
7127ec681f3Smrg   }
7137ec681f3Smrg
7147ec681f3Smrg   submit->signal_timelines[submit->signal_timeline_count] = timeline;
7157ec681f3Smrg   submit->signal_timeline_values[submit->signal_timeline_count] = value;
7167ec681f3Smrg
7177ec681f3Smrg   submit->signal_timeline_count++;
7187ec681f3Smrg
7197ec681f3Smrg   return VK_SUCCESS;
7207ec681f3Smrg}
7217ec681f3Smrg
7227ec681f3Smrgstatic struct anv_queue_submit *
7237ec681f3Smrganv_queue_submit_alloc(struct anv_device *device)
7247ec681f3Smrg{
7257ec681f3Smrg   const VkAllocationCallbacks *alloc = &device->vk.alloc;
7267ec681f3Smrg   VkSystemAllocationScope alloc_scope = VK_SYSTEM_ALLOCATION_SCOPE_DEVICE;
7277ec681f3Smrg
7287ec681f3Smrg   struct anv_queue_submit *submit = vk_zalloc(alloc, sizeof(*submit), 8, alloc_scope);
7297ec681f3Smrg   if (!submit)
7307ec681f3Smrg      return NULL;
7317ec681f3Smrg
7327ec681f3Smrg   submit->alloc = alloc;
7337ec681f3Smrg   submit->alloc_scope = alloc_scope;
7347ec681f3Smrg   submit->in_fence = -1;
7357ec681f3Smrg   submit->out_fence = -1;
7367ec681f3Smrg   submit->perf_query_pass = -1;
7377ec681f3Smrg
7387ec681f3Smrg   return submit;
7397ec681f3Smrg}
7407ec681f3Smrg
7417ec681f3SmrgVkResult
7427ec681f3Smrganv_queue_submit_simple_batch(struct anv_queue *queue,
7437ec681f3Smrg                              struct anv_batch *batch)
7447ec681f3Smrg{
7457ec681f3Smrg   if (queue->device->info.no_hw)
7467ec681f3Smrg      return VK_SUCCESS;
7477ec681f3Smrg
7487ec681f3Smrg   struct anv_device *device = queue->device;
7497ec681f3Smrg   struct anv_queue_submit *submit = anv_queue_submit_alloc(device);
7507ec681f3Smrg   if (!submit)
7517ec681f3Smrg      return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
7527ec681f3Smrg
7537ec681f3Smrg   bool has_syncobj_wait = device->physical->has_syncobj_wait;
7547ec681f3Smrg   VkResult result;
7557ec681f3Smrg   uint32_t syncobj;
7567ec681f3Smrg   struct anv_bo *batch_bo, *sync_bo;
7577ec681f3Smrg
7587ec681f3Smrg   if (has_syncobj_wait) {
7597ec681f3Smrg      syncobj = anv_gem_syncobj_create(device, 0);
7607ec681f3Smrg      if (!syncobj) {
7617ec681f3Smrg         result = vk_error(queue, VK_ERROR_OUT_OF_DEVICE_MEMORY);
7627ec681f3Smrg         goto err_free_submit;
7637ec681f3Smrg      }
7647ec681f3Smrg
7657ec681f3Smrg      result = anv_queue_submit_add_syncobj(queue, submit, syncobj,
7667ec681f3Smrg                                            I915_EXEC_FENCE_SIGNAL, 0);
7677ec681f3Smrg   } else {
7687ec681f3Smrg      result = anv_device_alloc_bo(device, "simple-batch-sync", 4096,
7697ec681f3Smrg                                   ANV_BO_ALLOC_EXTERNAL |
7707ec681f3Smrg                                   ANV_BO_ALLOC_IMPLICIT_SYNC,
7717ec681f3Smrg                                   0 /* explicit_address */,
7727ec681f3Smrg                                   &sync_bo);
7737ec681f3Smrg      if (result != VK_SUCCESS)
7747ec681f3Smrg         goto err_free_submit;
7757ec681f3Smrg
7767ec681f3Smrg      result = anv_queue_submit_add_fence_bo(queue, submit, sync_bo,
7777ec681f3Smrg                                             true /* signal */);
7787ec681f3Smrg   }
7797ec681f3Smrg
7807ec681f3Smrg   if (result != VK_SUCCESS)
7817ec681f3Smrg      goto err_destroy_sync_primitive;
7827ec681f3Smrg
7837ec681f3Smrg   if (batch) {
7847ec681f3Smrg      uint32_t size = align_u32(batch->next - batch->start, 8);
7857ec681f3Smrg      result = anv_bo_pool_alloc(&device->batch_bo_pool, size, &batch_bo);
7867ec681f3Smrg      if (result != VK_SUCCESS)
7877ec681f3Smrg         goto err_destroy_sync_primitive;
7887ec681f3Smrg
7897ec681f3Smrg      memcpy(batch_bo->map, batch->start, size);
7907ec681f3Smrg      if (!device->info.has_llc)
7917ec681f3Smrg         intel_flush_range(batch_bo->map, size);
7927ec681f3Smrg
7937ec681f3Smrg      submit->simple_bo = batch_bo;
7947ec681f3Smrg      submit->simple_bo_size = size;
7957ec681f3Smrg   }
7967ec681f3Smrg
7977ec681f3Smrg   result = anv_queue_submit_post(queue, &submit, true);
7987ec681f3Smrg
7997ec681f3Smrg   if (result == VK_SUCCESS) {
8007ec681f3Smrg      if (has_syncobj_wait) {
8017ec681f3Smrg         if (anv_gem_syncobj_wait(device, &syncobj, 1,
8027ec681f3Smrg                                  anv_get_absolute_timeout(INT64_MAX), true))
8037ec681f3Smrg            result = anv_device_set_lost(device, "anv_gem_syncobj_wait failed: %m");
8047ec681f3Smrg         anv_gem_syncobj_destroy(device, syncobj);
8057ec681f3Smrg      } else {
8067ec681f3Smrg         result = anv_device_wait(device, sync_bo,
8077ec681f3Smrg                                  anv_get_relative_timeout(INT64_MAX));
8087ec681f3Smrg         anv_device_release_bo(device, sync_bo);
8097ec681f3Smrg      }
8107ec681f3Smrg   }
8117ec681f3Smrg
8127ec681f3Smrg   if (batch)
8137ec681f3Smrg      anv_bo_pool_free(&device->batch_bo_pool, batch_bo);
8147ec681f3Smrg
8157ec681f3Smrg   if (submit)
8167ec681f3Smrg      anv_queue_submit_free(device, submit);
8177ec681f3Smrg
8187ec681f3Smrg   return result;
8197ec681f3Smrg
8207ec681f3Smrg err_destroy_sync_primitive:
8217ec681f3Smrg   if (has_syncobj_wait)
8227ec681f3Smrg      anv_gem_syncobj_destroy(device, syncobj);
8237ec681f3Smrg   else
8247ec681f3Smrg      anv_device_release_bo(device, sync_bo);
8257ec681f3Smrg err_free_submit:
8267ec681f3Smrg   if (submit)
8277ec681f3Smrg      anv_queue_submit_free(device, submit);
8287ec681f3Smrg
8297ec681f3Smrg   return result;
8307ec681f3Smrg}
8317ec681f3Smrg
8327ec681f3Smrgstatic VkResult
8337ec681f3Smrgadd_temporary_semaphore(struct anv_queue *queue,
8347ec681f3Smrg                        struct anv_queue_submit *submit,
8357ec681f3Smrg                        struct anv_semaphore_impl *impl,
8367ec681f3Smrg                        struct anv_semaphore_impl **out_impl)
8377ec681f3Smrg{
8387ec681f3Smrg   /*
8397ec681f3Smrg    * There is a requirement to reset semaphore to their permanent state after
8407ec681f3Smrg    * submission. From the Vulkan 1.0.53 spec:
8417ec681f3Smrg    *
8427ec681f3Smrg    *    "If the import is temporary, the implementation must restore the
8437ec681f3Smrg    *    semaphore to its prior permanent state after submitting the next
8447ec681f3Smrg    *    semaphore wait operation."
8457ec681f3Smrg    *
8467ec681f3Smrg    * In the case we defer the actual submission to a thread because of the
8477ec681f3Smrg    * wait-before-submit behavior required for timeline semaphores, we need to
8487ec681f3Smrg    * make copies of the temporary syncobj to ensure they stay alive until we
8497ec681f3Smrg    * do the actual execbuffer ioctl.
8507ec681f3Smrg    */
8517ec681f3Smrg   if (submit->temporary_semaphore_count >= submit->temporary_semaphore_array_length) {
8527ec681f3Smrg      uint32_t new_len = MAX2(submit->temporary_semaphore_array_length * 2, 8);
8537ec681f3Smrg      /* Make sure that if the realloc fails, we still have the old semaphore
8547ec681f3Smrg       * array around to properly clean things up on failure.
8557ec681f3Smrg       */
8567ec681f3Smrg      struct anv_semaphore_impl *new_array =
8577ec681f3Smrg         vk_realloc(submit->alloc,
8587ec681f3Smrg                    submit->temporary_semaphores,
8597ec681f3Smrg                    new_len * sizeof(*submit->temporary_semaphores),
8607ec681f3Smrg                    8, submit->alloc_scope);
8617ec681f3Smrg      if (new_array == NULL)
8627ec681f3Smrg         return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
8637ec681f3Smrg
8647ec681f3Smrg      submit->temporary_semaphores = new_array;
8657ec681f3Smrg      submit->temporary_semaphore_array_length = new_len;
8667ec681f3Smrg   }
8677ec681f3Smrg
8687ec681f3Smrg   /* Copy anv_semaphore_impl into anv_queue_submit. */
8697ec681f3Smrg   submit->temporary_semaphores[submit->temporary_semaphore_count++] = *impl;
8707ec681f3Smrg   *out_impl = &submit->temporary_semaphores[submit->temporary_semaphore_count - 1];
8717ec681f3Smrg
8727ec681f3Smrg   return VK_SUCCESS;
8737ec681f3Smrg}
8747ec681f3Smrg
8757ec681f3Smrgstatic VkResult
8767ec681f3Smrgclone_syncobj_dma_fence(struct anv_queue *queue,
8777ec681f3Smrg                        struct anv_semaphore_impl *out,
8787ec681f3Smrg                        const struct anv_semaphore_impl *in)
8797ec681f3Smrg{
8807ec681f3Smrg   struct anv_device *device = queue->device;
8817ec681f3Smrg
8827ec681f3Smrg   out->syncobj = anv_gem_syncobj_create(device, 0);
8837ec681f3Smrg   if (!out->syncobj)
8847ec681f3Smrg      return vk_error(queue, VK_ERROR_OUT_OF_DEVICE_MEMORY);
8857ec681f3Smrg
8867ec681f3Smrg   int fd = anv_gem_syncobj_export_sync_file(device, in->syncobj);
8877ec681f3Smrg   if (fd < 0) {
8887ec681f3Smrg      anv_gem_syncobj_destroy(device, out->syncobj);
8897ec681f3Smrg      return vk_error(queue, VK_ERROR_OUT_OF_DEVICE_MEMORY);
8907ec681f3Smrg   }
8917ec681f3Smrg
8927ec681f3Smrg   int ret = anv_gem_syncobj_import_sync_file(device,
8937ec681f3Smrg                                              out->syncobj,
8947ec681f3Smrg                                              fd);
8957ec681f3Smrg   close(fd);
8967ec681f3Smrg   if (ret < 0) {
8977ec681f3Smrg      anv_gem_syncobj_destroy(device, out->syncobj);
8987ec681f3Smrg      return vk_error(queue, VK_ERROR_OUT_OF_DEVICE_MEMORY);
8997ec681f3Smrg   }
9007ec681f3Smrg
9017ec681f3Smrg   return VK_SUCCESS;
9027ec681f3Smrg}
9037ec681f3Smrg
9047ec681f3Smrg/* Clone semaphore in the following cases :
9057ec681f3Smrg *
9067ec681f3Smrg *   - We're dealing with a temporary semaphore that needs to be reset to
9077ec681f3Smrg *     follow the Vulkan spec requirements.
9087ec681f3Smrg *
9097ec681f3Smrg *   - We're dealing with a syncobj semaphore and are using threaded
9107ec681f3Smrg *     submission to i915. Because we might want to export the semaphore right
9117ec681f3Smrg *     after calling vkQueueSubmit, we need to make sure it doesn't contain a
9127ec681f3Smrg *     staled DMA fence. In this case we reset the original syncobj, but make
9137ec681f3Smrg *     a clone of the contained DMA fence into another syncobj for submission
9147ec681f3Smrg *     to i915.
9157ec681f3Smrg *
9167ec681f3Smrg * Those temporary semaphores are later freed in anv_queue_submit_free().
9177ec681f3Smrg */
9187ec681f3Smrgstatic VkResult
9197ec681f3Smrgmaybe_transfer_temporary_semaphore(struct anv_queue *queue,
9207ec681f3Smrg                                   struct anv_queue_submit *submit,
9217ec681f3Smrg                                   struct anv_semaphore *semaphore,
9227ec681f3Smrg                                   struct anv_semaphore_impl **out_impl)
9237ec681f3Smrg{
9247ec681f3Smrg   struct anv_semaphore_impl *impl = &semaphore->temporary;
9257ec681f3Smrg   VkResult result;
9267ec681f3Smrg
9277ec681f3Smrg   if (impl->type == ANV_SEMAPHORE_TYPE_NONE) {
9287ec681f3Smrg      /* No temporary, use the permanent semaphore. */
9297ec681f3Smrg      impl = &semaphore->permanent;
9307ec681f3Smrg
9317ec681f3Smrg      /* We need to reset syncobj before submission so that they do not
9327ec681f3Smrg       * contain a stale DMA fence. When using a submission thread this is
9337ec681f3Smrg       * problematic because the i915 EXECBUF ioctl happens after
9347ec681f3Smrg       * vkQueueSubmit has returned. A subsequent vkQueueSubmit() call could
9357ec681f3Smrg       * reset the syncobj that i915 is about to see from the submission
9367ec681f3Smrg       * thread.
9377ec681f3Smrg       *
9387ec681f3Smrg       * To avoid this, clone the DMA fence in the semaphore, into a another
9397ec681f3Smrg       * syncobj that the submission thread will destroy when it's done with
9407ec681f3Smrg       * it.
9417ec681f3Smrg       */
9427ec681f3Smrg      if (queue->device->physical->has_thread_submit &&
9437ec681f3Smrg          impl->type == ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ) {
9447ec681f3Smrg         struct anv_semaphore_impl template = {
9457ec681f3Smrg            .type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ,
9467ec681f3Smrg         };
9477ec681f3Smrg
9487ec681f3Smrg         /* Put the fence into a new syncobj so the old one can be reset. */
9497ec681f3Smrg         result = clone_syncobj_dma_fence(queue, &template, impl);
9507ec681f3Smrg         if (result != VK_SUCCESS)
9517ec681f3Smrg            return result;
9527ec681f3Smrg
9537ec681f3Smrg         /* Create a copy of the anv_semaphore structure. */
9547ec681f3Smrg         result = add_temporary_semaphore(queue, submit, &template, out_impl);
9557ec681f3Smrg         if (result != VK_SUCCESS) {
9567ec681f3Smrg            anv_gem_syncobj_destroy(queue->device, template.syncobj);
9577ec681f3Smrg            return result;
9587ec681f3Smrg         }
9597ec681f3Smrg
9607ec681f3Smrg         return VK_SUCCESS;
9617ec681f3Smrg      }
9627ec681f3Smrg
9637ec681f3Smrg      *out_impl = impl;
9647ec681f3Smrg      return VK_SUCCESS;
9657ec681f3Smrg   }
9667ec681f3Smrg
9677ec681f3Smrg   /* BO backed timeline semaphores cannot be temporary. */
9687ec681f3Smrg   assert(impl->type != ANV_SEMAPHORE_TYPE_TIMELINE);
96901e04c3fSmrg
9707ec681f3Smrg   /* Copy anv_semaphore_impl into anv_queue_submit. */
9717ec681f3Smrg   result = add_temporary_semaphore(queue, submit, impl, out_impl);
9727ec681f3Smrg   if (result != VK_SUCCESS)
9737ec681f3Smrg      return result;
9747ec681f3Smrg
9757ec681f3Smrg   /* Clear the incoming semaphore */
9767ec681f3Smrg   impl->type = ANV_SEMAPHORE_TYPE_NONE;
9777ec681f3Smrg
9787ec681f3Smrg   return VK_SUCCESS;
9797ec681f3Smrg}
9807ec681f3Smrg
9817ec681f3Smrgstatic VkResult
9827ec681f3Smrganv_queue_submit_add_in_semaphore(struct anv_queue *queue,
9837ec681f3Smrg                                  struct anv_queue_submit *submit,
9847ec681f3Smrg                                  const VkSemaphore _semaphore,
9857ec681f3Smrg                                  const uint64_t value)
98601e04c3fSmrg{
9877ec681f3Smrg   ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
9887ec681f3Smrg   struct anv_semaphore_impl *impl =
9897ec681f3Smrg      semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
9907ec681f3Smrg      &semaphore->temporary : &semaphore->permanent;
9917ec681f3Smrg   VkResult result;
9927ec681f3Smrg
9937ec681f3Smrg   /* When using a binary semaphore with threaded submission, wait for the
9947ec681f3Smrg    * dma-fence to materialize in the syncobj. This is needed to be able to
9957ec681f3Smrg    * clone in maybe_transfer_temporary_semaphore().
9967ec681f3Smrg    */
9977ec681f3Smrg   if (queue->device->has_thread_submit &&
9987ec681f3Smrg       impl->type == ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ) {
9997ec681f3Smrg      uint64_t value = 0;
10007ec681f3Smrg      int ret =
10017ec681f3Smrg         anv_gem_syncobj_timeline_wait(queue->device,
10027ec681f3Smrg                                       &impl->syncobj, &value, 1,
10037ec681f3Smrg                                       anv_get_absolute_timeout(INT64_MAX),
10047ec681f3Smrg                                       true /* wait_all */,
10057ec681f3Smrg                                       true /* wait_materialize */);
10067ec681f3Smrg      if (ret != 0) {
10077ec681f3Smrg         return anv_queue_set_lost(queue,
10087ec681f3Smrg                                   "unable to wait on syncobj to materialize");
10097ec681f3Smrg      }
101001e04c3fSmrg   }
101101e04c3fSmrg
10127ec681f3Smrg   result = maybe_transfer_temporary_semaphore(queue, submit, semaphore, &impl);
10137ec681f3Smrg   if (result != VK_SUCCESS)
10147ec681f3Smrg      return result;
10157ec681f3Smrg
10167ec681f3Smrg   switch (impl->type) {
10177ec681f3Smrg   case ANV_SEMAPHORE_TYPE_WSI_BO:
10187ec681f3Smrg      /* When using a window-system buffer as a semaphore, always enable
10197ec681f3Smrg       * EXEC_OBJECT_WRITE. This gives us a WaR hazard with the display or
10207ec681f3Smrg       * compositor's read of the buffer and enforces that we don't start
10217ec681f3Smrg       * rendering until they are finished. This is exactly the
10227ec681f3Smrg       * synchronization we want with vkAcquireNextImage.
10237ec681f3Smrg       */
10247ec681f3Smrg      result = anv_queue_submit_add_fence_bo(queue, submit, impl->bo,
10257ec681f3Smrg                                             true /* signal */);
10267ec681f3Smrg      if (result != VK_SUCCESS)
10277ec681f3Smrg         return result;
10287ec681f3Smrg      break;
10297ec681f3Smrg
10307ec681f3Smrg   case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
10317ec681f3Smrg      result = anv_queue_submit_add_syncobj(queue, submit,
10327ec681f3Smrg                                            impl->syncobj,
10337ec681f3Smrg                                            I915_EXEC_FENCE_WAIT,
10347ec681f3Smrg                                            0);
10357ec681f3Smrg      if (result != VK_SUCCESS)
10367ec681f3Smrg         return result;
10377ec681f3Smrg      break;
10387ec681f3Smrg
10397ec681f3Smrg   case ANV_SEMAPHORE_TYPE_TIMELINE:
10407ec681f3Smrg      if (value == 0)
10417ec681f3Smrg         break;
10427ec681f3Smrg      result = anv_queue_submit_add_timeline_wait(queue, submit,
10437ec681f3Smrg                                                  &impl->timeline,
10447ec681f3Smrg                                                  value);
10457ec681f3Smrg      if (result != VK_SUCCESS)
10467ec681f3Smrg         return result;
10477ec681f3Smrg      break;
10487ec681f3Smrg
10497ec681f3Smrg   case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE:
10507ec681f3Smrg      if (value == 0)
10517ec681f3Smrg         break;
10527ec681f3Smrg      result = anv_queue_submit_add_syncobj(queue, submit,
10537ec681f3Smrg                                            impl->syncobj,
10547ec681f3Smrg                                            I915_EXEC_FENCE_WAIT,
10557ec681f3Smrg                                            value);
10567ec681f3Smrg      if (result != VK_SUCCESS)
10577ec681f3Smrg         return result;
10587ec681f3Smrg      break;
10597ec681f3Smrg
10607ec681f3Smrg   default:
10617ec681f3Smrg      break;
106201e04c3fSmrg   }
106301e04c3fSmrg
106401e04c3fSmrg   return VK_SUCCESS;
106501e04c3fSmrg}
106601e04c3fSmrg
10677ec681f3Smrgstatic VkResult
10687ec681f3Smrganv_queue_submit_add_out_semaphore(struct anv_queue *queue,
10697ec681f3Smrg                                   struct anv_queue_submit *submit,
10707ec681f3Smrg                                   const VkSemaphore _semaphore,
10717ec681f3Smrg                                   const uint64_t value)
107201e04c3fSmrg{
10737ec681f3Smrg   ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
10747ec681f3Smrg   VkResult result;
107501e04c3fSmrg
10767ec681f3Smrg   /* Under most circumstances, out fences won't be temporary. However, the
10777ec681f3Smrg    * spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec:
10787ec681f3Smrg    *
10797ec681f3Smrg    *    "If the import is temporary, the implementation must restore the
10807ec681f3Smrg    *    semaphore to its prior permanent state after submitting the next
10817ec681f3Smrg    *    semaphore wait operation."
10827ec681f3Smrg    *
10837ec681f3Smrg    * The spec says nothing whatsoever about signal operations on temporarily
10847ec681f3Smrg    * imported semaphores so it appears they are allowed. There are also CTS
10857ec681f3Smrg    * tests that require this to work.
10867ec681f3Smrg    */
10877ec681f3Smrg   struct anv_semaphore_impl *impl =
10887ec681f3Smrg      semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
10897ec681f3Smrg      &semaphore->temporary : &semaphore->permanent;
109001e04c3fSmrg
10917ec681f3Smrg   switch (impl->type) {
10927ec681f3Smrg   case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: {
10937ec681f3Smrg      /*
10947ec681f3Smrg       * Reset the content of the syncobj so it doesn't contain a previously
10957ec681f3Smrg       * signaled dma-fence, until one is added by EXECBUFFER by the
10967ec681f3Smrg       * submission thread.
10977ec681f3Smrg       */
10987ec681f3Smrg      anv_gem_syncobj_reset(queue->device, impl->syncobj);
10997ec681f3Smrg
11007ec681f3Smrg      result = anv_queue_submit_add_syncobj(queue, submit, impl->syncobj,
11017ec681f3Smrg                                            I915_EXEC_FENCE_SIGNAL,
11027ec681f3Smrg                                            0);
11037ec681f3Smrg      if (result != VK_SUCCESS)
11047ec681f3Smrg         return result;
11057ec681f3Smrg      break;
11067ec681f3Smrg   }
110701e04c3fSmrg
11087ec681f3Smrg   case ANV_SEMAPHORE_TYPE_TIMELINE:
11097ec681f3Smrg      if (value == 0)
11107ec681f3Smrg         break;
11117ec681f3Smrg      result = anv_queue_submit_add_timeline_signal(queue, submit,
11127ec681f3Smrg                                                    &impl->timeline,
11137ec681f3Smrg                                                    value);
11147ec681f3Smrg      if (result != VK_SUCCESS)
11157ec681f3Smrg         return result;
11167ec681f3Smrg      break;
111701e04c3fSmrg
11187ec681f3Smrg   case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE:
11197ec681f3Smrg      if (value == 0)
11207ec681f3Smrg         break;
11217ec681f3Smrg      result = anv_queue_submit_add_syncobj(queue, submit, impl->syncobj,
11227ec681f3Smrg                                            I915_EXEC_FENCE_SIGNAL,
11237ec681f3Smrg                                            value);
11247ec681f3Smrg      if (result != VK_SUCCESS)
11257ec681f3Smrg         return result;
11267ec681f3Smrg      break;
112701e04c3fSmrg
11287ec681f3Smrg   default:
11297ec681f3Smrg      break;
11307ec681f3Smrg   }
11317ec681f3Smrg
11327ec681f3Smrg   return VK_SUCCESS;
11337ec681f3Smrg}
11347ec681f3Smrg
11357ec681f3Smrgstatic VkResult
11367ec681f3Smrganv_queue_submit_add_fence(struct anv_queue *queue,
11377ec681f3Smrg                           struct anv_queue_submit *submit,
11387ec681f3Smrg                           struct anv_fence *fence)
11397ec681f3Smrg{
11407ec681f3Smrg   /* Under most circumstances, out fences won't be temporary. However, the
11417ec681f3Smrg    * spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec:
11427ec681f3Smrg    *
11437ec681f3Smrg    *    "If the import is temporary, the implementation must restore the
11447ec681f3Smrg    *    semaphore to its prior permanent state after submitting the next
11457ec681f3Smrg    *    semaphore wait operation."
11467ec681f3Smrg    *
11477ec681f3Smrg    * The spec says nothing whatsoever about signal operations on temporarily
11487ec681f3Smrg    * imported semaphores so it appears they are allowed. There are also CTS
11497ec681f3Smrg    * tests that require this to work.
11507ec681f3Smrg    */
11517ec681f3Smrg   struct anv_fence_impl *impl =
11527ec681f3Smrg      fence->temporary.type != ANV_FENCE_TYPE_NONE ?
11537ec681f3Smrg      &fence->temporary : &fence->permanent;
11547ec681f3Smrg
11557ec681f3Smrg   VkResult result;
11567ec681f3Smrg
11577ec681f3Smrg   switch (impl->type) {
11587ec681f3Smrg   case ANV_FENCE_TYPE_BO:
11597ec681f3Smrg      assert(!queue->device->has_thread_submit);
11607ec681f3Smrg      result = anv_queue_submit_add_fence_bo(queue, submit, impl->bo.bo,
11617ec681f3Smrg                                             true /* signal */);
11627ec681f3Smrg      if (result != VK_SUCCESS)
11637ec681f3Smrg         return result;
11647ec681f3Smrg      break;
11657ec681f3Smrg
11667ec681f3Smrg   case ANV_FENCE_TYPE_SYNCOBJ: {
11677ec681f3Smrg      /*
11687ec681f3Smrg       * For the same reason we reset the signaled binary syncobj above, also
11697ec681f3Smrg       * reset the fence's syncobj so that they don't contain a signaled
11707ec681f3Smrg       * dma-fence.
11717ec681f3Smrg       */
11727ec681f3Smrg      anv_gem_syncobj_reset(queue->device, impl->syncobj);
11737ec681f3Smrg
11747ec681f3Smrg      result = anv_queue_submit_add_syncobj(queue, submit, impl->syncobj,
11757ec681f3Smrg                                            I915_EXEC_FENCE_SIGNAL,
11767ec681f3Smrg                                            0);
11777ec681f3Smrg      if (result != VK_SUCCESS)
11787ec681f3Smrg         return result;
11797ec681f3Smrg      break;
11807ec681f3Smrg      }
11817ec681f3Smrg
11827ec681f3Smrg   default:
11837ec681f3Smrg      unreachable("Invalid fence type");
11847ec681f3Smrg   }
11857ec681f3Smrg
11867ec681f3Smrg   return VK_SUCCESS;
11877ec681f3Smrg}
11887ec681f3Smrg
11897ec681f3Smrgstatic void
11907ec681f3Smrganv_post_queue_fence_update(struct anv_device *device, struct anv_fence *fence)
11917ec681f3Smrg{
11927ec681f3Smrg   if (fence->permanent.type == ANV_FENCE_TYPE_BO) {
11937ec681f3Smrg      assert(!device->has_thread_submit);
11947ec681f3Smrg      /* If we have permanent BO fence, the only type of temporary possible
11957ec681f3Smrg       * would be BO_WSI (because BO fences are not shareable). The Vulkan spec
11967ec681f3Smrg       * also requires that the fence passed to vkQueueSubmit() be :
11977ec681f3Smrg       *
11987ec681f3Smrg       *    * unsignaled
11997ec681f3Smrg       *    * not be associated with any other queue command that has not yet
12007ec681f3Smrg       *      completed execution on that queue
12017ec681f3Smrg       *
12027ec681f3Smrg       * So the only acceptable type for the temporary is NONE.
12037ec681f3Smrg       */
12047ec681f3Smrg      assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
12057ec681f3Smrg
12067ec681f3Smrg      /* Once the execbuf has returned, we need to set the fence state to
12077ec681f3Smrg       * SUBMITTED.  We can't do this before calling execbuf because
12087ec681f3Smrg       * anv_GetFenceStatus does take the global device lock before checking
12097ec681f3Smrg       * fence->state.
12107ec681f3Smrg       *
12117ec681f3Smrg       * We set the fence state to SUBMITTED regardless of whether or not the
12127ec681f3Smrg       * execbuf succeeds because we need to ensure that vkWaitForFences() and
12137ec681f3Smrg       * vkGetFenceStatus() return a valid result (VK_ERROR_DEVICE_LOST or
12147ec681f3Smrg       * VK_SUCCESS) in a finite amount of time even if execbuf fails.
12157ec681f3Smrg       */
12167ec681f3Smrg      fence->permanent.bo.state = ANV_BO_FENCE_STATE_SUBMITTED;
12177ec681f3Smrg   }
12187ec681f3Smrg}
12197ec681f3Smrg
12207ec681f3Smrgstatic VkResult
12217ec681f3Smrganv_queue_submit_add_cmd_buffer(struct anv_queue *queue,
12227ec681f3Smrg                                struct anv_queue_submit *submit,
12237ec681f3Smrg                                struct anv_cmd_buffer *cmd_buffer,
12247ec681f3Smrg                                int perf_pass)
12257ec681f3Smrg{
12267ec681f3Smrg   if (submit->cmd_buffer_count >= submit->cmd_buffer_array_length) {
12277ec681f3Smrg      uint32_t new_len = MAX2(submit->cmd_buffer_array_length * 2, 4);
12287ec681f3Smrg      struct anv_cmd_buffer **new_cmd_buffers =
12297ec681f3Smrg         vk_realloc(submit->alloc,
12307ec681f3Smrg                    submit->cmd_buffers, new_len * sizeof(*submit->cmd_buffers),
12317ec681f3Smrg                    8, submit->alloc_scope);
12327ec681f3Smrg      if (new_cmd_buffers == NULL)
12337ec681f3Smrg         return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
12347ec681f3Smrg
12357ec681f3Smrg      submit->cmd_buffers = new_cmd_buffers;
12367ec681f3Smrg      submit->cmd_buffer_array_length = new_len;
12377ec681f3Smrg   }
12387ec681f3Smrg
12397ec681f3Smrg   submit->cmd_buffers[submit->cmd_buffer_count++] = cmd_buffer;
12407ec681f3Smrg   /* Only update the perf_query_pool if there is one. We can decide to batch
12417ec681f3Smrg    * 2 command buffers if the second one doesn't use a query pool, but we
12427ec681f3Smrg    * can't drop the already chosen one.
12437ec681f3Smrg    */
12447ec681f3Smrg   if (cmd_buffer->perf_query_pool)
12457ec681f3Smrg      submit->perf_query_pool = cmd_buffer->perf_query_pool;
12467ec681f3Smrg   submit->perf_query_pass = perf_pass;
12477ec681f3Smrg
12487ec681f3Smrg   return VK_SUCCESS;
12497ec681f3Smrg}
12507ec681f3Smrg
12517ec681f3Smrgstatic bool
12527ec681f3Smrganv_queue_submit_can_add_cmd_buffer(const struct anv_queue_submit *submit,
12537ec681f3Smrg                                    const struct anv_cmd_buffer *cmd_buffer,
12547ec681f3Smrg                                    int perf_pass)
12557ec681f3Smrg{
12567ec681f3Smrg   /* If first command buffer, no problem. */
12577ec681f3Smrg   if (submit->cmd_buffer_count == 0)
12587ec681f3Smrg      return true;
12597ec681f3Smrg
12607ec681f3Smrg   /* Can we chain the last buffer into the next one? */
12617ec681f3Smrg   if (!anv_cmd_buffer_is_chainable(submit->cmd_buffers[submit->cmd_buffer_count - 1]))
12627ec681f3Smrg      return false;
12637ec681f3Smrg
12647ec681f3Smrg   /* A change of perf query pools between VkSubmitInfo elements means we
12657ec681f3Smrg    * can't batch things up.
12667ec681f3Smrg    */
12677ec681f3Smrg   if (cmd_buffer->perf_query_pool &&
12687ec681f3Smrg       submit->perf_query_pool &&
12697ec681f3Smrg       submit->perf_query_pool != cmd_buffer->perf_query_pool)
12707ec681f3Smrg      return false;
12717ec681f3Smrg
12727ec681f3Smrg   /* A change of perf pass also prevents batching things up.
12737ec681f3Smrg    */
12747ec681f3Smrg   if (submit->perf_query_pass != -1 &&
12757ec681f3Smrg       submit->perf_query_pass != perf_pass)
12767ec681f3Smrg      return false;
12777ec681f3Smrg
12787ec681f3Smrg   return true;
12797ec681f3Smrg}
12807ec681f3Smrg
12817ec681f3Smrgstatic bool
12827ec681f3Smrganv_queue_submit_can_add_submit(const struct anv_queue_submit *submit,
12837ec681f3Smrg                                uint32_t n_wait_semaphores,
12847ec681f3Smrg                                uint32_t n_signal_semaphores,
12857ec681f3Smrg                                int perf_pass)
12867ec681f3Smrg{
12877ec681f3Smrg   /* We can add to an empty anv_queue_submit. */
12887ec681f3Smrg   if (submit->cmd_buffer_count == 0 &&
12897ec681f3Smrg       submit->fence_count == 0 &&
12907ec681f3Smrg       submit->wait_timeline_count == 0 &&
12917ec681f3Smrg       submit->signal_timeline_count == 0 &&
12927ec681f3Smrg       submit->fence_bo_count == 0)
12937ec681f3Smrg      return true;
12947ec681f3Smrg
12957ec681f3Smrg   /* Different perf passes will require different EXECBUF ioctls. */
12967ec681f3Smrg   if (perf_pass != submit->perf_query_pass)
12977ec681f3Smrg      return false;
12987ec681f3Smrg
12997ec681f3Smrg   /* If the current submit is signaling anything, we can't add anything. */
13007ec681f3Smrg   if (submit->signal_timeline_count)
13017ec681f3Smrg      return false;
13027ec681f3Smrg
13037ec681f3Smrg   /* If a submit is waiting on anything, anything that happened before needs
13047ec681f3Smrg    * to be submitted.
13057ec681f3Smrg    */
13067ec681f3Smrg   if (n_wait_semaphores)
13077ec681f3Smrg      return false;
13087ec681f3Smrg
13097ec681f3Smrg   return true;
13107ec681f3Smrg}
13117ec681f3Smrg
13127ec681f3Smrgstatic VkResult
13137ec681f3Smrganv_queue_submit_post_and_alloc_new(struct anv_queue *queue,
13147ec681f3Smrg                                    struct anv_queue_submit **submit)
13157ec681f3Smrg{
13167ec681f3Smrg   VkResult result = anv_queue_submit_post(queue, submit, false);
13177ec681f3Smrg   if (result != VK_SUCCESS)
13187ec681f3Smrg      return result;
13197ec681f3Smrg
13207ec681f3Smrg   *submit = anv_queue_submit_alloc(queue->device);
13217ec681f3Smrg   if (!*submit)
13227ec681f3Smrg      return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
13237ec681f3Smrg   return VK_SUCCESS;
132401e04c3fSmrg}
132501e04c3fSmrg
13267ec681f3SmrgVkResult anv_QueueSubmit2KHR(
132701e04c3fSmrg    VkQueue                                     _queue,
132801e04c3fSmrg    uint32_t                                    submitCount,
13297ec681f3Smrg    const VkSubmitInfo2KHR*                     pSubmits,
13307ec681f3Smrg    VkFence                                     _fence)
133101e04c3fSmrg{
133201e04c3fSmrg   ANV_FROM_HANDLE(anv_queue, queue, _queue);
13337ec681f3Smrg   ANV_FROM_HANDLE(anv_fence, fence, _fence);
133401e04c3fSmrg   struct anv_device *device = queue->device;
133501e04c3fSmrg
13367ec681f3Smrg   if (device->info.no_hw)
13377ec681f3Smrg      return VK_SUCCESS;
13387ec681f3Smrg
133901e04c3fSmrg   /* Query for device status prior to submitting.  Technically, we don't need
134001e04c3fSmrg    * to do this.  However, if we have a client that's submitting piles of
134101e04c3fSmrg    * garbage, we would rather break as early as possible to keep the GPU
134201e04c3fSmrg    * hanging contained.  If we don't check here, we'll either be waiting for
134301e04c3fSmrg    * the kernel to kick us or we'll have to wait until the client waits on a
134401e04c3fSmrg    * fence before we actually know whether or not we've hung.
134501e04c3fSmrg    */
134601e04c3fSmrg   VkResult result = anv_device_query_status(device);
134701e04c3fSmrg   if (result != VK_SUCCESS)
134801e04c3fSmrg      return result;
134901e04c3fSmrg
13507ec681f3Smrg   struct anv_queue_submit *submit = anv_queue_submit_alloc(device);
13517ec681f3Smrg   if (!submit)
13527ec681f3Smrg      return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
135301e04c3fSmrg
135401e04c3fSmrg   for (uint32_t i = 0; i < submitCount; i++) {
13557ec681f3Smrg      const struct wsi_memory_signal_submit_info *mem_signal_info =
13567ec681f3Smrg         vk_find_struct_const(pSubmits[i].pNext,
13577ec681f3Smrg                              WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA);
13587ec681f3Smrg      struct anv_bo *wsi_signal_bo =
13597ec681f3Smrg         mem_signal_info && mem_signal_info->memory != VK_NULL_HANDLE ?
13607ec681f3Smrg         anv_device_memory_from_handle(mem_signal_info->memory)->bo : NULL;
13617ec681f3Smrg
13627ec681f3Smrg      const VkPerformanceQuerySubmitInfoKHR *perf_info =
13637ec681f3Smrg         vk_find_struct_const(pSubmits[i].pNext,
13647ec681f3Smrg                              PERFORMANCE_QUERY_SUBMIT_INFO_KHR);
13657ec681f3Smrg      const int perf_pass = perf_info ? perf_info->counterPassIndex : 0;
13667ec681f3Smrg
13677ec681f3Smrg      if (!anv_queue_submit_can_add_submit(submit,
13687ec681f3Smrg                                           pSubmits[i].waitSemaphoreInfoCount,
13697ec681f3Smrg                                           pSubmits[i].signalSemaphoreInfoCount,
13707ec681f3Smrg                                           perf_pass)) {
13717ec681f3Smrg         result = anv_queue_submit_post_and_alloc_new(queue, &submit);
137201e04c3fSmrg         if (result != VK_SUCCESS)
137301e04c3fSmrg            goto out;
13747ec681f3Smrg      }
137501e04c3fSmrg
13767ec681f3Smrg      /* Wait semaphores */
13777ec681f3Smrg      for (uint32_t j = 0; j < pSubmits[i].waitSemaphoreInfoCount; j++) {
13787ec681f3Smrg         result = anv_queue_submit_add_in_semaphore(queue, submit,
13797ec681f3Smrg                                                    pSubmits[i].pWaitSemaphoreInfos[j].semaphore,
13807ec681f3Smrg                                                    pSubmits[i].pWaitSemaphoreInfos[j].value);
13817ec681f3Smrg         if (result != VK_SUCCESS)
13827ec681f3Smrg            goto out;
138301e04c3fSmrg      }
138401e04c3fSmrg
13857ec681f3Smrg      /* Command buffers */
13867ec681f3Smrg      for (uint32_t j = 0; j < pSubmits[i].commandBufferInfoCount; j++) {
138701e04c3fSmrg         ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer,
13887ec681f3Smrg                         pSubmits[i].pCommandBufferInfos[j].commandBuffer);
138901e04c3fSmrg         assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY);
139001e04c3fSmrg         assert(!anv_batch_has_error(&cmd_buffer->batch));
13917ec681f3Smrg         anv_measure_submit(cmd_buffer);
139201e04c3fSmrg
13937ec681f3Smrg         /* If we can't add an additional command buffer to the existing
13947ec681f3Smrg          * anv_queue_submit, post it and create a new one.
13957ec681f3Smrg          */
13967ec681f3Smrg         if (!anv_queue_submit_can_add_cmd_buffer(submit, cmd_buffer, perf_pass)) {
13977ec681f3Smrg            result = anv_queue_submit_post_and_alloc_new(queue, &submit);
13987ec681f3Smrg            if (result != VK_SUCCESS)
13997ec681f3Smrg               goto out;
140001e04c3fSmrg         }
140101e04c3fSmrg
14027ec681f3Smrg         result = anv_queue_submit_add_cmd_buffer(queue, submit,
14037ec681f3Smrg                                                  cmd_buffer, perf_pass);
14047ec681f3Smrg         if (result != VK_SUCCESS)
14057ec681f3Smrg            goto out;
14067ec681f3Smrg      }
14077ec681f3Smrg
14087ec681f3Smrg      /* Signal semaphores */
14097ec681f3Smrg      for (uint32_t j = 0; j < pSubmits[i].signalSemaphoreInfoCount; j++) {
14107ec681f3Smrg         result = anv_queue_submit_add_out_semaphore(queue, submit,
14117ec681f3Smrg                                                     pSubmits[i].pSignalSemaphoreInfos[j].semaphore,
14127ec681f3Smrg                                                     pSubmits[i].pSignalSemaphoreInfos[j].value);
14137ec681f3Smrg         if (result != VK_SUCCESS)
14147ec681f3Smrg            goto out;
14157ec681f3Smrg      }
141601e04c3fSmrg
14177ec681f3Smrg      /* WSI BO */
14187ec681f3Smrg      if (wsi_signal_bo) {
14197ec681f3Smrg         result = anv_queue_submit_add_fence_bo(queue, submit, wsi_signal_bo,
14207ec681f3Smrg                                                true /* signal */);
142101e04c3fSmrg         if (result != VK_SUCCESS)
142201e04c3fSmrg            goto out;
142301e04c3fSmrg      }
142401e04c3fSmrg   }
142501e04c3fSmrg
14267ec681f3Smrg   if (fence) {
14277ec681f3Smrg      result = anv_queue_submit_add_fence(queue, submit, fence);
14287ec681f3Smrg      if (result != VK_SUCCESS)
14297ec681f3Smrg         goto out;
14307ec681f3Smrg   }
14317ec681f3Smrg
14327ec681f3Smrg   result = anv_queue_submit_post(queue, &submit, false);
14337ec681f3Smrg   if (result != VK_SUCCESS)
14347ec681f3Smrg      goto out;
14357ec681f3Smrg
14367ec681f3Smrg   if (fence)
14377ec681f3Smrg      anv_post_queue_fence_update(device, fence);
143801e04c3fSmrg
143901e04c3fSmrgout:
14407ec681f3Smrg   if (submit)
14417ec681f3Smrg      anv_queue_submit_free(device, submit);
14427ec681f3Smrg
14437ec681f3Smrg   if (result != VK_SUCCESS && result != VK_ERROR_DEVICE_LOST) {
144401e04c3fSmrg      /* In the case that something has gone wrong we may end up with an
144501e04c3fSmrg       * inconsistent state from which it may not be trivial to recover.
144601e04c3fSmrg       * For example, we might have computed address relocations and
144701e04c3fSmrg       * any future attempt to re-submit this job will need to know about
144801e04c3fSmrg       * this and avoid computing relocation addresses again.
144901e04c3fSmrg       *
145001e04c3fSmrg       * To avoid this sort of issues, we assume that if something was
145101e04c3fSmrg       * wrong during submission we must already be in a really bad situation
145201e04c3fSmrg       * anyway (such us being out of memory) and return
145301e04c3fSmrg       * VK_ERROR_DEVICE_LOST to ensure that clients do not attempt to
145401e04c3fSmrg       * submit the same job again to this device.
14557ec681f3Smrg       *
14567ec681f3Smrg       * We skip doing this on VK_ERROR_DEVICE_LOST because
14577ec681f3Smrg       * anv_device_set_lost() would have been called already by a callee of
14587ec681f3Smrg       * anv_queue_submit().
145901e04c3fSmrg       */
14607ec681f3Smrg      result = anv_device_set_lost(device, "vkQueueSubmit2KHR() failed");
146101e04c3fSmrg   }
146201e04c3fSmrg
146301e04c3fSmrg   return result;
146401e04c3fSmrg}
146501e04c3fSmrg
146601e04c3fSmrgVkResult anv_QueueWaitIdle(
146701e04c3fSmrg    VkQueue                                     _queue)
146801e04c3fSmrg{
146901e04c3fSmrg   ANV_FROM_HANDLE(anv_queue, queue, _queue);
147001e04c3fSmrg
14717ec681f3Smrg   if (anv_device_is_lost(queue->device))
14727ec681f3Smrg      return VK_ERROR_DEVICE_LOST;
14737ec681f3Smrg
14747ec681f3Smrg   return anv_queue_submit_simple_batch(queue, NULL);
147501e04c3fSmrg}
147601e04c3fSmrg
147701e04c3fSmrgVkResult anv_CreateFence(
147801e04c3fSmrg    VkDevice                                    _device,
147901e04c3fSmrg    const VkFenceCreateInfo*                    pCreateInfo,
148001e04c3fSmrg    const VkAllocationCallbacks*                pAllocator,
148101e04c3fSmrg    VkFence*                                    pFence)
148201e04c3fSmrg{
148301e04c3fSmrg   ANV_FROM_HANDLE(anv_device, device, _device);
148401e04c3fSmrg   struct anv_fence *fence;
148501e04c3fSmrg
148601e04c3fSmrg   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO);
148701e04c3fSmrg
14887ec681f3Smrg   fence = vk_object_zalloc(&device->vk, pAllocator, sizeof(*fence),
14897ec681f3Smrg                            VK_OBJECT_TYPE_FENCE);
149001e04c3fSmrg   if (fence == NULL)
14917ec681f3Smrg      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
149201e04c3fSmrg
14937ec681f3Smrg   if (device->physical->has_syncobj_wait) {
149401e04c3fSmrg      fence->permanent.type = ANV_FENCE_TYPE_SYNCOBJ;
149501e04c3fSmrg
149601e04c3fSmrg      uint32_t create_flags = 0;
149701e04c3fSmrg      if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT)
149801e04c3fSmrg         create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
149901e04c3fSmrg
150001e04c3fSmrg      fence->permanent.syncobj = anv_gem_syncobj_create(device, create_flags);
150101e04c3fSmrg      if (!fence->permanent.syncobj)
15027ec681f3Smrg         return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
150301e04c3fSmrg   } else {
150401e04c3fSmrg      fence->permanent.type = ANV_FENCE_TYPE_BO;
150501e04c3fSmrg
15067ec681f3Smrg      VkResult result = anv_bo_pool_alloc(&device->batch_bo_pool, 4096,
15077ec681f3Smrg                                          &fence->permanent.bo.bo);
150801e04c3fSmrg      if (result != VK_SUCCESS)
150901e04c3fSmrg         return result;
151001e04c3fSmrg
151101e04c3fSmrg      if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
151201e04c3fSmrg         fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED;
151301e04c3fSmrg      } else {
151401e04c3fSmrg         fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET;
151501e04c3fSmrg      }
151601e04c3fSmrg   }
151701e04c3fSmrg
151801e04c3fSmrg   *pFence = anv_fence_to_handle(fence);
151901e04c3fSmrg
152001e04c3fSmrg   return VK_SUCCESS;
152101e04c3fSmrg}
152201e04c3fSmrg
152301e04c3fSmrgstatic void
152401e04c3fSmrganv_fence_impl_cleanup(struct anv_device *device,
152501e04c3fSmrg                       struct anv_fence_impl *impl)
152601e04c3fSmrg{
152701e04c3fSmrg   switch (impl->type) {
152801e04c3fSmrg   case ANV_FENCE_TYPE_NONE:
152901e04c3fSmrg      /* Dummy.  Nothing to do */
153001e04c3fSmrg      break;
153101e04c3fSmrg
153201e04c3fSmrg   case ANV_FENCE_TYPE_BO:
15337ec681f3Smrg      anv_bo_pool_free(&device->batch_bo_pool, impl->bo.bo);
15347ec681f3Smrg      break;
15357ec681f3Smrg
15367ec681f3Smrg   case ANV_FENCE_TYPE_WSI_BO:
15377ec681f3Smrg      anv_device_release_bo(device, impl->bo.bo);
153801e04c3fSmrg      break;
153901e04c3fSmrg
154001e04c3fSmrg   case ANV_FENCE_TYPE_SYNCOBJ:
154101e04c3fSmrg      anv_gem_syncobj_destroy(device, impl->syncobj);
154201e04c3fSmrg      break;
154301e04c3fSmrg
154401e04c3fSmrg   case ANV_FENCE_TYPE_WSI:
154501e04c3fSmrg      impl->fence_wsi->destroy(impl->fence_wsi);
154601e04c3fSmrg      break;
154701e04c3fSmrg
154801e04c3fSmrg   default:
154901e04c3fSmrg      unreachable("Invalid fence type");
155001e04c3fSmrg   }
155101e04c3fSmrg
155201e04c3fSmrg   impl->type = ANV_FENCE_TYPE_NONE;
155301e04c3fSmrg}
155401e04c3fSmrg
15557ec681f3Smrgvoid
15567ec681f3Smrganv_fence_reset_temporary(struct anv_device *device,
15577ec681f3Smrg                          struct anv_fence *fence)
15587ec681f3Smrg{
15597ec681f3Smrg   if (fence->temporary.type == ANV_FENCE_TYPE_NONE)
15607ec681f3Smrg      return;
15617ec681f3Smrg
15627ec681f3Smrg   anv_fence_impl_cleanup(device, &fence->temporary);
15637ec681f3Smrg}
15647ec681f3Smrg
156501e04c3fSmrgvoid anv_DestroyFence(
156601e04c3fSmrg    VkDevice                                    _device,
156701e04c3fSmrg    VkFence                                     _fence,
156801e04c3fSmrg    const VkAllocationCallbacks*                pAllocator)
156901e04c3fSmrg{
157001e04c3fSmrg   ANV_FROM_HANDLE(anv_device, device, _device);
157101e04c3fSmrg   ANV_FROM_HANDLE(anv_fence, fence, _fence);
157201e04c3fSmrg
157301e04c3fSmrg   if (!fence)
157401e04c3fSmrg      return;
157501e04c3fSmrg
157601e04c3fSmrg   anv_fence_impl_cleanup(device, &fence->temporary);
157701e04c3fSmrg   anv_fence_impl_cleanup(device, &fence->permanent);
157801e04c3fSmrg
15797ec681f3Smrg   vk_object_free(&device->vk, pAllocator, fence);
158001e04c3fSmrg}
158101e04c3fSmrg
158201e04c3fSmrgVkResult anv_ResetFences(
158301e04c3fSmrg    VkDevice                                    _device,
158401e04c3fSmrg    uint32_t                                    fenceCount,
158501e04c3fSmrg    const VkFence*                              pFences)
158601e04c3fSmrg{
158701e04c3fSmrg   ANV_FROM_HANDLE(anv_device, device, _device);
158801e04c3fSmrg
158901e04c3fSmrg   for (uint32_t i = 0; i < fenceCount; i++) {
159001e04c3fSmrg      ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
159101e04c3fSmrg
159201e04c3fSmrg      /* From the Vulkan 1.0.53 spec:
159301e04c3fSmrg       *
159401e04c3fSmrg       *    "If any member of pFences currently has its payload imported with
159501e04c3fSmrg       *    temporary permanence, that fence’s prior permanent payload is
159601e04c3fSmrg       *    first restored. The remaining operations described therefore
159701e04c3fSmrg       *    operate on the restored payload.
159801e04c3fSmrg       */
15997ec681f3Smrg      anv_fence_reset_temporary(device, fence);
160001e04c3fSmrg
160101e04c3fSmrg      struct anv_fence_impl *impl = &fence->permanent;
160201e04c3fSmrg
160301e04c3fSmrg      switch (impl->type) {
160401e04c3fSmrg      case ANV_FENCE_TYPE_BO:
160501e04c3fSmrg         impl->bo.state = ANV_BO_FENCE_STATE_RESET;
160601e04c3fSmrg         break;
160701e04c3fSmrg
160801e04c3fSmrg      case ANV_FENCE_TYPE_SYNCOBJ:
160901e04c3fSmrg         anv_gem_syncobj_reset(device, impl->syncobj);
161001e04c3fSmrg         break;
161101e04c3fSmrg
161201e04c3fSmrg      default:
161301e04c3fSmrg         unreachable("Invalid fence type");
161401e04c3fSmrg      }
161501e04c3fSmrg   }
161601e04c3fSmrg
161701e04c3fSmrg   return VK_SUCCESS;
161801e04c3fSmrg}
161901e04c3fSmrg
162001e04c3fSmrgVkResult anv_GetFenceStatus(
162101e04c3fSmrg    VkDevice                                    _device,
162201e04c3fSmrg    VkFence                                     _fence)
162301e04c3fSmrg{
162401e04c3fSmrg   ANV_FROM_HANDLE(anv_device, device, _device);
162501e04c3fSmrg   ANV_FROM_HANDLE(anv_fence, fence, _fence);
162601e04c3fSmrg
162701e04c3fSmrg   if (anv_device_is_lost(device))
162801e04c3fSmrg      return VK_ERROR_DEVICE_LOST;
162901e04c3fSmrg
163001e04c3fSmrg   struct anv_fence_impl *impl =
163101e04c3fSmrg      fence->temporary.type != ANV_FENCE_TYPE_NONE ?
163201e04c3fSmrg      &fence->temporary : &fence->permanent;
163301e04c3fSmrg
163401e04c3fSmrg   switch (impl->type) {
163501e04c3fSmrg   case ANV_FENCE_TYPE_BO:
16367ec681f3Smrg   case ANV_FENCE_TYPE_WSI_BO:
163701e04c3fSmrg      switch (impl->bo.state) {
163801e04c3fSmrg      case ANV_BO_FENCE_STATE_RESET:
163901e04c3fSmrg         /* If it hasn't even been sent off to the GPU yet, it's not ready */
164001e04c3fSmrg         return VK_NOT_READY;
164101e04c3fSmrg
164201e04c3fSmrg      case ANV_BO_FENCE_STATE_SIGNALED:
164301e04c3fSmrg         /* It's been signaled, return success */
164401e04c3fSmrg         return VK_SUCCESS;
164501e04c3fSmrg
164601e04c3fSmrg      case ANV_BO_FENCE_STATE_SUBMITTED: {
16477ec681f3Smrg         VkResult result = anv_device_bo_busy(device, impl->bo.bo);
164801e04c3fSmrg         if (result == VK_SUCCESS) {
164901e04c3fSmrg            impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED;
165001e04c3fSmrg            return VK_SUCCESS;
165101e04c3fSmrg         } else {
165201e04c3fSmrg            return result;
165301e04c3fSmrg         }
165401e04c3fSmrg      }
165501e04c3fSmrg      default:
165601e04c3fSmrg         unreachable("Invalid fence status");
165701e04c3fSmrg      }
165801e04c3fSmrg
165901e04c3fSmrg   case ANV_FENCE_TYPE_SYNCOBJ: {
16607ec681f3Smrg      if (device->has_thread_submit) {
16617ec681f3Smrg         uint64_t binary_value = 0;
16627ec681f3Smrg         int ret = anv_gem_syncobj_timeline_wait(device, &impl->syncobj,
16637ec681f3Smrg                                             &binary_value, 1, 0,
16647ec681f3Smrg                                             true /* wait_all */,
16657ec681f3Smrg                                             false /* wait_materialize */);
16667ec681f3Smrg         if (ret == -1) {
16677ec681f3Smrg            if (errno == ETIME) {
16687ec681f3Smrg               return VK_NOT_READY;
16697ec681f3Smrg            } else {
16707ec681f3Smrg               /* We don't know the real error. */
16717ec681f3Smrg               return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");
16727ec681f3Smrg            }
167301e04c3fSmrg         } else {
16747ec681f3Smrg            return VK_SUCCESS;
167501e04c3fSmrg         }
167601e04c3fSmrg      } else {
16777ec681f3Smrg         int ret = anv_gem_syncobj_wait(device, &impl->syncobj, 1, 0, false);
16787ec681f3Smrg         if (ret == -1) {
16797ec681f3Smrg            if (errno == ETIME) {
16807ec681f3Smrg               return VK_NOT_READY;
16817ec681f3Smrg            } else {
16827ec681f3Smrg               /* We don't know the real error. */
16837ec681f3Smrg               return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");
16847ec681f3Smrg            }
16857ec681f3Smrg         } else {
16867ec681f3Smrg            return VK_SUCCESS;
16877ec681f3Smrg         }
16887ec681f3Smrg      }
16897ec681f3Smrg   }
169001e04c3fSmrg
16917ec681f3Smrg   default:
16927ec681f3Smrg      unreachable("Invalid fence type");
16937ec681f3Smrg   }
169401e04c3fSmrg}
169501e04c3fSmrg
169601e04c3fSmrgstatic VkResult
169701e04c3fSmrganv_wait_for_syncobj_fences(struct anv_device *device,
169801e04c3fSmrg                            uint32_t fenceCount,
169901e04c3fSmrg                            const VkFence *pFences,
170001e04c3fSmrg                            bool waitAll,
170101e04c3fSmrg                            uint64_t abs_timeout_ns)
170201e04c3fSmrg{
17037ec681f3Smrg   uint32_t *syncobjs = vk_zalloc(&device->vk.alloc,
170401e04c3fSmrg                                  sizeof(*syncobjs) * fenceCount, 8,
170501e04c3fSmrg                                  VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
170601e04c3fSmrg   if (!syncobjs)
17077ec681f3Smrg      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
170801e04c3fSmrg
170901e04c3fSmrg   for (uint32_t i = 0; i < fenceCount; i++) {
171001e04c3fSmrg      ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
171101e04c3fSmrg      assert(fence->permanent.type == ANV_FENCE_TYPE_SYNCOBJ);
171201e04c3fSmrg
171301e04c3fSmrg      struct anv_fence_impl *impl =
171401e04c3fSmrg         fence->temporary.type != ANV_FENCE_TYPE_NONE ?
171501e04c3fSmrg         &fence->temporary : &fence->permanent;
171601e04c3fSmrg
171701e04c3fSmrg      assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
171801e04c3fSmrg      syncobjs[i] = impl->syncobj;
171901e04c3fSmrg   }
172001e04c3fSmrg
17217ec681f3Smrg   int ret = 0;
172201e04c3fSmrg   /* The gem_syncobj_wait ioctl may return early due to an inherent
17237ec681f3Smrg    * limitation in the way it computes timeouts. Loop until we've actually
172401e04c3fSmrg    * passed the timeout.
172501e04c3fSmrg    */
172601e04c3fSmrg   do {
172701e04c3fSmrg      ret = anv_gem_syncobj_wait(device, syncobjs, fenceCount,
172801e04c3fSmrg                                 abs_timeout_ns, waitAll);
17297ec681f3Smrg   } while (ret == -1 && errno == ETIME && anv_gettime_ns() < abs_timeout_ns);
173001e04c3fSmrg
17317ec681f3Smrg   vk_free(&device->vk.alloc, syncobjs);
173201e04c3fSmrg
173301e04c3fSmrg   if (ret == -1) {
173401e04c3fSmrg      if (errno == ETIME) {
173501e04c3fSmrg         return VK_TIMEOUT;
173601e04c3fSmrg      } else {
173701e04c3fSmrg         /* We don't know the real error. */
173801e04c3fSmrg         return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");
173901e04c3fSmrg      }
174001e04c3fSmrg   } else {
174101e04c3fSmrg      return VK_SUCCESS;
174201e04c3fSmrg   }
174301e04c3fSmrg}
174401e04c3fSmrg
174501e04c3fSmrgstatic VkResult
174601e04c3fSmrganv_wait_for_bo_fences(struct anv_device *device,
174701e04c3fSmrg                       uint32_t fenceCount,
174801e04c3fSmrg                       const VkFence *pFences,
174901e04c3fSmrg                       bool waitAll,
175001e04c3fSmrg                       uint64_t abs_timeout_ns)
175101e04c3fSmrg{
175201e04c3fSmrg   VkResult result = VK_SUCCESS;
175301e04c3fSmrg   uint32_t pending_fences = fenceCount;
175401e04c3fSmrg   while (pending_fences) {
175501e04c3fSmrg      pending_fences = 0;
175601e04c3fSmrg      bool signaled_fences = false;
175701e04c3fSmrg      for (uint32_t i = 0; i < fenceCount; i++) {
175801e04c3fSmrg         ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
175901e04c3fSmrg
17607ec681f3Smrg         struct anv_fence_impl *impl =
17617ec681f3Smrg            fence->temporary.type != ANV_FENCE_TYPE_NONE ?
17627ec681f3Smrg            &fence->temporary : &fence->permanent;
17637ec681f3Smrg         assert(impl->type == ANV_FENCE_TYPE_BO ||
17647ec681f3Smrg                impl->type == ANV_FENCE_TYPE_WSI_BO);
176501e04c3fSmrg
176601e04c3fSmrg         switch (impl->bo.state) {
176701e04c3fSmrg         case ANV_BO_FENCE_STATE_RESET:
176801e04c3fSmrg            /* This fence hasn't been submitted yet, we'll catch it the next
176901e04c3fSmrg             * time around.  Yes, this may mean we dead-loop but, short of
177001e04c3fSmrg             * lots of locking and a condition variable, there's not much that
177101e04c3fSmrg             * we can do about that.
177201e04c3fSmrg             */
177301e04c3fSmrg            pending_fences++;
177401e04c3fSmrg            continue;
177501e04c3fSmrg
177601e04c3fSmrg         case ANV_BO_FENCE_STATE_SIGNALED:
177701e04c3fSmrg            /* This fence is not pending.  If waitAll isn't set, we can return
177801e04c3fSmrg             * early.  Otherwise, we have to keep going.
177901e04c3fSmrg             */
178001e04c3fSmrg            if (!waitAll) {
178101e04c3fSmrg               result = VK_SUCCESS;
178201e04c3fSmrg               goto done;
178301e04c3fSmrg            }
178401e04c3fSmrg            continue;
178501e04c3fSmrg
178601e04c3fSmrg         case ANV_BO_FENCE_STATE_SUBMITTED:
178701e04c3fSmrg            /* These are the fences we really care about.  Go ahead and wait
178801e04c3fSmrg             * on it until we hit a timeout.
178901e04c3fSmrg             */
17907ec681f3Smrg            result = anv_device_wait(device, impl->bo.bo,
179101e04c3fSmrg                                     anv_get_relative_timeout(abs_timeout_ns));
179201e04c3fSmrg            switch (result) {
179301e04c3fSmrg            case VK_SUCCESS:
179401e04c3fSmrg               impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED;
179501e04c3fSmrg               signaled_fences = true;
179601e04c3fSmrg               if (!waitAll)
179701e04c3fSmrg                  goto done;
179801e04c3fSmrg               break;
179901e04c3fSmrg
180001e04c3fSmrg            case VK_TIMEOUT:
180101e04c3fSmrg               goto done;
180201e04c3fSmrg
180301e04c3fSmrg            default:
180401e04c3fSmrg               return result;
180501e04c3fSmrg            }
180601e04c3fSmrg         }
180701e04c3fSmrg      }
180801e04c3fSmrg
180901e04c3fSmrg      if (pending_fences && !signaled_fences) {
181001e04c3fSmrg         /* If we've hit this then someone decided to vkWaitForFences before
181101e04c3fSmrg          * they've actually submitted any of them to a queue.  This is a
181201e04c3fSmrg          * fairly pessimal case, so it's ok to lock here and use a standard
181301e04c3fSmrg          * pthreads condition variable.
181401e04c3fSmrg          */
181501e04c3fSmrg         pthread_mutex_lock(&device->mutex);
181601e04c3fSmrg
181701e04c3fSmrg         /* It's possible that some of the fences have changed state since the
181801e04c3fSmrg          * last time we checked.  Now that we have the lock, check for
181901e04c3fSmrg          * pending fences again and don't wait if it's changed.
182001e04c3fSmrg          */
182101e04c3fSmrg         uint32_t now_pending_fences = 0;
182201e04c3fSmrg         for (uint32_t i = 0; i < fenceCount; i++) {
182301e04c3fSmrg            ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
182401e04c3fSmrg            if (fence->permanent.bo.state == ANV_BO_FENCE_STATE_RESET)
182501e04c3fSmrg               now_pending_fences++;
182601e04c3fSmrg         }
182701e04c3fSmrg         assert(now_pending_fences <= pending_fences);
182801e04c3fSmrg
182901e04c3fSmrg         if (now_pending_fences == pending_fences) {
183001e04c3fSmrg            struct timespec abstime = {
183101e04c3fSmrg               .tv_sec = abs_timeout_ns / NSEC_PER_SEC,
183201e04c3fSmrg               .tv_nsec = abs_timeout_ns % NSEC_PER_SEC,
183301e04c3fSmrg            };
183401e04c3fSmrg
18357ec681f3Smrg            ASSERTED int ret;
183601e04c3fSmrg            ret = pthread_cond_timedwait(&device->queue_submit,
183701e04c3fSmrg                                         &device->mutex, &abstime);
183801e04c3fSmrg            assert(ret != EINVAL);
18397ec681f3Smrg            if (anv_gettime_ns() >= abs_timeout_ns) {
184001e04c3fSmrg               pthread_mutex_unlock(&device->mutex);
184101e04c3fSmrg               result = VK_TIMEOUT;
184201e04c3fSmrg               goto done;
184301e04c3fSmrg            }
184401e04c3fSmrg         }
184501e04c3fSmrg
184601e04c3fSmrg         pthread_mutex_unlock(&device->mutex);
184701e04c3fSmrg      }
184801e04c3fSmrg   }
184901e04c3fSmrg
185001e04c3fSmrgdone:
185101e04c3fSmrg   if (anv_device_is_lost(device))
185201e04c3fSmrg      return VK_ERROR_DEVICE_LOST;
185301e04c3fSmrg
185401e04c3fSmrg   return result;
185501e04c3fSmrg}
185601e04c3fSmrg
185701e04c3fSmrgstatic VkResult
185801e04c3fSmrganv_wait_for_wsi_fence(struct anv_device *device,
18597ec681f3Smrg                       struct anv_fence_impl *impl,
186001e04c3fSmrg                       uint64_t abs_timeout)
186101e04c3fSmrg{
186201e04c3fSmrg   return impl->fence_wsi->wait(impl->fence_wsi, abs_timeout);
186301e04c3fSmrg}
186401e04c3fSmrg
186501e04c3fSmrgstatic VkResult
186601e04c3fSmrganv_wait_for_fences(struct anv_device *device,
186701e04c3fSmrg                    uint32_t fenceCount,
186801e04c3fSmrg                    const VkFence *pFences,
186901e04c3fSmrg                    bool waitAll,
187001e04c3fSmrg                    uint64_t abs_timeout)
187101e04c3fSmrg{
187201e04c3fSmrg   VkResult result = VK_SUCCESS;
187301e04c3fSmrg
187401e04c3fSmrg   if (fenceCount <= 1 || waitAll) {
187501e04c3fSmrg      for (uint32_t i = 0; i < fenceCount; i++) {
187601e04c3fSmrg         ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
18777ec681f3Smrg         struct anv_fence_impl *impl =
18787ec681f3Smrg            fence->temporary.type != ANV_FENCE_TYPE_NONE ?
18797ec681f3Smrg            &fence->temporary : &fence->permanent;
18807ec681f3Smrg
18817ec681f3Smrg         switch (impl->type) {
188201e04c3fSmrg         case ANV_FENCE_TYPE_BO:
18837ec681f3Smrg            assert(!device->physical->has_syncobj_wait);
18847ec681f3Smrg            FALLTHROUGH;
18857ec681f3Smrg         case ANV_FENCE_TYPE_WSI_BO:
188601e04c3fSmrg            result = anv_wait_for_bo_fences(device, 1, &pFences[i],
188701e04c3fSmrg                                            true, abs_timeout);
188801e04c3fSmrg            break;
188901e04c3fSmrg         case ANV_FENCE_TYPE_SYNCOBJ:
189001e04c3fSmrg            result = anv_wait_for_syncobj_fences(device, 1, &pFences[i],
189101e04c3fSmrg                                                 true, abs_timeout);
189201e04c3fSmrg            break;
189301e04c3fSmrg         case ANV_FENCE_TYPE_WSI:
18947ec681f3Smrg            result = anv_wait_for_wsi_fence(device, impl, abs_timeout);
189501e04c3fSmrg            break;
189601e04c3fSmrg         case ANV_FENCE_TYPE_NONE:
189701e04c3fSmrg            result = VK_SUCCESS;
189801e04c3fSmrg            break;
189901e04c3fSmrg         }
190001e04c3fSmrg         if (result != VK_SUCCESS)
190101e04c3fSmrg            return result;
190201e04c3fSmrg      }
190301e04c3fSmrg   } else {
190401e04c3fSmrg      do {
190501e04c3fSmrg         for (uint32_t i = 0; i < fenceCount; i++) {
190601e04c3fSmrg            if (anv_wait_for_fences(device, 1, &pFences[i], true, 0) == VK_SUCCESS)
190701e04c3fSmrg               return VK_SUCCESS;
190801e04c3fSmrg         }
19097ec681f3Smrg      } while (anv_gettime_ns() < abs_timeout);
191001e04c3fSmrg      result = VK_TIMEOUT;
191101e04c3fSmrg   }
191201e04c3fSmrg   return result;
191301e04c3fSmrg}
191401e04c3fSmrg
191501e04c3fSmrgstatic bool anv_all_fences_syncobj(uint32_t fenceCount, const VkFence *pFences)
191601e04c3fSmrg{
191701e04c3fSmrg   for (uint32_t i = 0; i < fenceCount; ++i) {
191801e04c3fSmrg      ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
19197ec681f3Smrg      struct anv_fence_impl *impl =
19207ec681f3Smrg         fence->temporary.type != ANV_FENCE_TYPE_NONE ?
19217ec681f3Smrg         &fence->temporary : &fence->permanent;
19227ec681f3Smrg      if (impl->type != ANV_FENCE_TYPE_SYNCOBJ)
192301e04c3fSmrg         return false;
192401e04c3fSmrg   }
192501e04c3fSmrg   return true;
192601e04c3fSmrg}
192701e04c3fSmrg
192801e04c3fSmrgstatic bool anv_all_fences_bo(uint32_t fenceCount, const VkFence *pFences)
192901e04c3fSmrg{
193001e04c3fSmrg   for (uint32_t i = 0; i < fenceCount; ++i) {
193101e04c3fSmrg      ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
19327ec681f3Smrg      struct anv_fence_impl *impl =
19337ec681f3Smrg         fence->temporary.type != ANV_FENCE_TYPE_NONE ?
19347ec681f3Smrg         &fence->temporary : &fence->permanent;
19357ec681f3Smrg      if (impl->type != ANV_FENCE_TYPE_BO &&
19367ec681f3Smrg          impl->type != ANV_FENCE_TYPE_WSI_BO)
193701e04c3fSmrg         return false;
193801e04c3fSmrg   }
193901e04c3fSmrg   return true;
194001e04c3fSmrg}
194101e04c3fSmrg
194201e04c3fSmrgVkResult anv_WaitForFences(
194301e04c3fSmrg    VkDevice                                    _device,
194401e04c3fSmrg    uint32_t                                    fenceCount,
194501e04c3fSmrg    const VkFence*                              pFences,
194601e04c3fSmrg    VkBool32                                    waitAll,
194701e04c3fSmrg    uint64_t                                    timeout)
194801e04c3fSmrg{
194901e04c3fSmrg   ANV_FROM_HANDLE(anv_device, device, _device);
195001e04c3fSmrg
19517ec681f3Smrg   if (device->info.no_hw)
19527ec681f3Smrg      return VK_SUCCESS;
19537ec681f3Smrg
195401e04c3fSmrg   if (anv_device_is_lost(device))
195501e04c3fSmrg      return VK_ERROR_DEVICE_LOST;
195601e04c3fSmrg
195701e04c3fSmrg   uint64_t abs_timeout = anv_get_absolute_timeout(timeout);
195801e04c3fSmrg   if (anv_all_fences_syncobj(fenceCount, pFences)) {
195901e04c3fSmrg      return anv_wait_for_syncobj_fences(device, fenceCount, pFences,
196001e04c3fSmrg                                         waitAll, abs_timeout);
196101e04c3fSmrg   } else if (anv_all_fences_bo(fenceCount, pFences)) {
196201e04c3fSmrg      return anv_wait_for_bo_fences(device, fenceCount, pFences,
196301e04c3fSmrg                                    waitAll, abs_timeout);
196401e04c3fSmrg   } else {
196501e04c3fSmrg      return anv_wait_for_fences(device, fenceCount, pFences,
196601e04c3fSmrg                                 waitAll, abs_timeout);
196701e04c3fSmrg   }
196801e04c3fSmrg}
196901e04c3fSmrg
197001e04c3fSmrgvoid anv_GetPhysicalDeviceExternalFenceProperties(
197101e04c3fSmrg    VkPhysicalDevice                            physicalDevice,
19729f464c52Smaya    const VkPhysicalDeviceExternalFenceInfo*    pExternalFenceInfo,
19739f464c52Smaya    VkExternalFenceProperties*                  pExternalFenceProperties)
197401e04c3fSmrg{
197501e04c3fSmrg   ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
197601e04c3fSmrg
197701e04c3fSmrg   switch (pExternalFenceInfo->handleType) {
197801e04c3fSmrg   case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:
197901e04c3fSmrg   case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT:
198001e04c3fSmrg      if (device->has_syncobj_wait) {
198101e04c3fSmrg         pExternalFenceProperties->exportFromImportedHandleTypes =
198201e04c3fSmrg            VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT |
198301e04c3fSmrg            VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
198401e04c3fSmrg         pExternalFenceProperties->compatibleHandleTypes =
198501e04c3fSmrg            VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT |
198601e04c3fSmrg            VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
198701e04c3fSmrg         pExternalFenceProperties->externalFenceFeatures =
198801e04c3fSmrg            VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT |
198901e04c3fSmrg            VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT;
199001e04c3fSmrg         return;
199101e04c3fSmrg      }
199201e04c3fSmrg      break;
199301e04c3fSmrg
199401e04c3fSmrg   default:
199501e04c3fSmrg      break;
199601e04c3fSmrg   }
199701e04c3fSmrg
199801e04c3fSmrg   pExternalFenceProperties->exportFromImportedHandleTypes = 0;
199901e04c3fSmrg   pExternalFenceProperties->compatibleHandleTypes = 0;
200001e04c3fSmrg   pExternalFenceProperties->externalFenceFeatures = 0;
200101e04c3fSmrg}
200201e04c3fSmrg
200301e04c3fSmrgVkResult anv_ImportFenceFdKHR(
200401e04c3fSmrg    VkDevice                                    _device,
200501e04c3fSmrg    const VkImportFenceFdInfoKHR*               pImportFenceFdInfo)
200601e04c3fSmrg{
200701e04c3fSmrg   ANV_FROM_HANDLE(anv_device, device, _device);
200801e04c3fSmrg   ANV_FROM_HANDLE(anv_fence, fence, pImportFenceFdInfo->fence);
200901e04c3fSmrg   int fd = pImportFenceFdInfo->fd;
201001e04c3fSmrg
201101e04c3fSmrg   assert(pImportFenceFdInfo->sType ==
201201e04c3fSmrg          VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR);
201301e04c3fSmrg
201401e04c3fSmrg   struct anv_fence_impl new_impl = {
201501e04c3fSmrg      .type = ANV_FENCE_TYPE_NONE,
201601e04c3fSmrg   };
201701e04c3fSmrg
201801e04c3fSmrg   switch (pImportFenceFdInfo->handleType) {
201901e04c3fSmrg   case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:
202001e04c3fSmrg      new_impl.type = ANV_FENCE_TYPE_SYNCOBJ;
202101e04c3fSmrg
202201e04c3fSmrg      new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);
202301e04c3fSmrg      if (!new_impl.syncobj)
20247ec681f3Smrg         return vk_error(fence, VK_ERROR_INVALID_EXTERNAL_HANDLE);
202501e04c3fSmrg
202601e04c3fSmrg      break;
202701e04c3fSmrg
20287ec681f3Smrg   case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: {
202901e04c3fSmrg      /* Sync files are a bit tricky.  Because we want to continue using the
203001e04c3fSmrg       * syncobj implementation of WaitForFences, we don't use the sync file
203101e04c3fSmrg       * directly but instead import it into a syncobj.
203201e04c3fSmrg       */
203301e04c3fSmrg      new_impl.type = ANV_FENCE_TYPE_SYNCOBJ;
203401e04c3fSmrg
20357ec681f3Smrg      /* "If handleType is VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, the
20367ec681f3Smrg       *  special value -1 for fd is treated like a valid sync file descriptor
20377ec681f3Smrg       *  referring to an object that has already signaled. The import
20387ec681f3Smrg       *  operation will succeed and the VkFence will have a temporarily
20397ec681f3Smrg       *  imported payload as if a valid file descriptor had been provided."
20407ec681f3Smrg       */
20417ec681f3Smrg      uint32_t create_flags = 0;
20427ec681f3Smrg      if (fd == -1)
20437ec681f3Smrg         create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
20447ec681f3Smrg
20457ec681f3Smrg      new_impl.syncobj = anv_gem_syncobj_create(device, create_flags);
204601e04c3fSmrg      if (!new_impl.syncobj)
20477ec681f3Smrg         return vk_error(fence, VK_ERROR_OUT_OF_HOST_MEMORY);
204801e04c3fSmrg
20497ec681f3Smrg      if (fd != -1 &&
20507ec681f3Smrg          anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) {
205101e04c3fSmrg         anv_gem_syncobj_destroy(device, new_impl.syncobj);
20527ec681f3Smrg         return vk_errorf(fence, VK_ERROR_INVALID_EXTERNAL_HANDLE,
205301e04c3fSmrg                          "syncobj sync file import failed: %m");
205401e04c3fSmrg      }
205501e04c3fSmrg      break;
20567ec681f3Smrg   }
205701e04c3fSmrg
205801e04c3fSmrg   default:
20597ec681f3Smrg      return vk_error(fence, VK_ERROR_INVALID_EXTERNAL_HANDLE);
206001e04c3fSmrg   }
206101e04c3fSmrg
206201e04c3fSmrg   /* From the Vulkan 1.0.53 spec:
206301e04c3fSmrg    *
206401e04c3fSmrg    *    "Importing a fence payload from a file descriptor transfers
206501e04c3fSmrg    *    ownership of the file descriptor from the application to the
206601e04c3fSmrg    *    Vulkan implementation. The application must not perform any
206701e04c3fSmrg    *    operations on the file descriptor after a successful import."
206801e04c3fSmrg    *
206901e04c3fSmrg    * If the import fails, we leave the file descriptor open.
207001e04c3fSmrg    */
20717ec681f3Smrg   if (fd != -1)
20727ec681f3Smrg      close(fd);
207301e04c3fSmrg
207401e04c3fSmrg   if (pImportFenceFdInfo->flags & VK_FENCE_IMPORT_TEMPORARY_BIT) {
207501e04c3fSmrg      anv_fence_impl_cleanup(device, &fence->temporary);
207601e04c3fSmrg      fence->temporary = new_impl;
207701e04c3fSmrg   } else {
207801e04c3fSmrg      anv_fence_impl_cleanup(device, &fence->permanent);
207901e04c3fSmrg      fence->permanent = new_impl;
208001e04c3fSmrg   }
208101e04c3fSmrg
208201e04c3fSmrg   return VK_SUCCESS;
208301e04c3fSmrg}
208401e04c3fSmrg
20857ec681f3Smrg/* The sideband payload of the DRM syncobj was incremented when the
20867ec681f3Smrg * application called vkQueueSubmit(). Here we wait for a fence with the same
20877ec681f3Smrg * value to materialize so that we can exporting (typically as a SyncFD).
20887ec681f3Smrg */
20897ec681f3Smrgstatic VkResult
20907ec681f3Smrgwait_syncobj_materialize(struct anv_device *device,
20917ec681f3Smrg                         uint32_t syncobj,
20927ec681f3Smrg                         int *fd)
20937ec681f3Smrg{
20947ec681f3Smrg   if (!device->has_thread_submit)
20957ec681f3Smrg      return VK_SUCCESS;
20967ec681f3Smrg
20977ec681f3Smrg   uint64_t binary_value = 0;
20987ec681f3Smrg   /* We might need to wait until the fence materializes before we can
20997ec681f3Smrg    * export to a sync FD when we use a thread for submission.
21007ec681f3Smrg    */
21017ec681f3Smrg   if (anv_gem_syncobj_timeline_wait(device, &syncobj, &binary_value, 1,
21027ec681f3Smrg                                     anv_get_absolute_timeout(5ull * NSEC_PER_SEC),
21037ec681f3Smrg                                     true /* wait_all */,
21047ec681f3Smrg                                     true /* wait_materialize */))
21057ec681f3Smrg      return anv_device_set_lost(device, "anv_gem_syncobj_timeline_wait failed: %m");
21067ec681f3Smrg
21077ec681f3Smrg   return VK_SUCCESS;
21087ec681f3Smrg}
21097ec681f3Smrg
211001e04c3fSmrgVkResult anv_GetFenceFdKHR(
211101e04c3fSmrg    VkDevice                                    _device,
211201e04c3fSmrg    const VkFenceGetFdInfoKHR*                  pGetFdInfo,
211301e04c3fSmrg    int*                                        pFd)
211401e04c3fSmrg{
211501e04c3fSmrg   ANV_FROM_HANDLE(anv_device, device, _device);
211601e04c3fSmrg   ANV_FROM_HANDLE(anv_fence, fence, pGetFdInfo->fence);
211701e04c3fSmrg
211801e04c3fSmrg   assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR);
211901e04c3fSmrg
212001e04c3fSmrg   struct anv_fence_impl *impl =
212101e04c3fSmrg      fence->temporary.type != ANV_FENCE_TYPE_NONE ?
212201e04c3fSmrg      &fence->temporary : &fence->permanent;
212301e04c3fSmrg
212401e04c3fSmrg   assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
212501e04c3fSmrg   switch (pGetFdInfo->handleType) {
212601e04c3fSmrg   case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT: {
212701e04c3fSmrg      int fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
212801e04c3fSmrg      if (fd < 0)
21297ec681f3Smrg         return vk_error(fence, VK_ERROR_TOO_MANY_OBJECTS);
213001e04c3fSmrg
213101e04c3fSmrg      *pFd = fd;
213201e04c3fSmrg      break;
213301e04c3fSmrg   }
213401e04c3fSmrg
213501e04c3fSmrg   case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: {
21367ec681f3Smrg      VkResult result = wait_syncobj_materialize(device, impl->syncobj, pFd);
21377ec681f3Smrg      if (result != VK_SUCCESS)
21387ec681f3Smrg         return result;
21397ec681f3Smrg
214001e04c3fSmrg      int fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj);
214101e04c3fSmrg      if (fd < 0)
21427ec681f3Smrg         return vk_error(fence, VK_ERROR_TOO_MANY_OBJECTS);
214301e04c3fSmrg
214401e04c3fSmrg      *pFd = fd;
214501e04c3fSmrg      break;
214601e04c3fSmrg   }
214701e04c3fSmrg
214801e04c3fSmrg   default:
214901e04c3fSmrg      unreachable("Invalid fence export handle type");
215001e04c3fSmrg   }
215101e04c3fSmrg
215201e04c3fSmrg   /* From the Vulkan 1.0.53 spec:
215301e04c3fSmrg    *
215401e04c3fSmrg    *    "Export operations have the same transference as the specified handle
215501e04c3fSmrg    *    type’s import operations. [...] If the fence was using a
215601e04c3fSmrg    *    temporarily imported payload, the fence’s prior permanent payload
215701e04c3fSmrg    *    will be restored.
215801e04c3fSmrg    */
215901e04c3fSmrg   if (impl == &fence->temporary)
216001e04c3fSmrg      anv_fence_impl_cleanup(device, impl);
216101e04c3fSmrg
216201e04c3fSmrg   return VK_SUCCESS;
216301e04c3fSmrg}
216401e04c3fSmrg
216501e04c3fSmrg// Queue semaphore functions
216601e04c3fSmrg
21677ec681f3Smrgstatic VkSemaphoreTypeKHR
21687ec681f3Smrgget_semaphore_type(const void *pNext, uint64_t *initial_value)
21697ec681f3Smrg{
21707ec681f3Smrg   const VkSemaphoreTypeCreateInfoKHR *type_info =
21717ec681f3Smrg      vk_find_struct_const(pNext, SEMAPHORE_TYPE_CREATE_INFO_KHR);
21727ec681f3Smrg
21737ec681f3Smrg   if (!type_info)
21747ec681f3Smrg      return VK_SEMAPHORE_TYPE_BINARY_KHR;
21757ec681f3Smrg
21767ec681f3Smrg   if (initial_value)
21777ec681f3Smrg      *initial_value = type_info->initialValue;
21787ec681f3Smrg   return type_info->semaphoreType;
21797ec681f3Smrg}
21807ec681f3Smrg
21817ec681f3Smrgstatic VkResult
21827ec681f3Smrgbinary_semaphore_create(struct anv_device *device,
21837ec681f3Smrg                        struct anv_semaphore_impl *impl,
21847ec681f3Smrg                        bool exportable)
21857ec681f3Smrg{
21867ec681f3Smrg   impl->type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
21877ec681f3Smrg   impl->syncobj = anv_gem_syncobj_create(device, 0);
21887ec681f3Smrg   if (!impl->syncobj)
21897ec681f3Smrg         return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
21907ec681f3Smrg   return VK_SUCCESS;
21917ec681f3Smrg}
21927ec681f3Smrg
21937ec681f3Smrgstatic VkResult
21947ec681f3Smrgtimeline_semaphore_create(struct anv_device *device,
21957ec681f3Smrg                          struct anv_semaphore_impl *impl,
21967ec681f3Smrg                          uint64_t initial_value)
21977ec681f3Smrg{
21987ec681f3Smrg   if (device->has_thread_submit) {
21997ec681f3Smrg      impl->type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE;
22007ec681f3Smrg      impl->syncobj = anv_gem_syncobj_create(device, 0);
22017ec681f3Smrg      if (!impl->syncobj)
22027ec681f3Smrg         return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
22037ec681f3Smrg      if (initial_value) {
22047ec681f3Smrg         if (anv_gem_syncobj_timeline_signal(device,
22057ec681f3Smrg                                             &impl->syncobj,
22067ec681f3Smrg                                             &initial_value, 1)) {
22077ec681f3Smrg            anv_gem_syncobj_destroy(device, impl->syncobj);
22087ec681f3Smrg            return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
22097ec681f3Smrg         }
22107ec681f3Smrg      }
22117ec681f3Smrg   } else {
22127ec681f3Smrg      impl->type = ANV_SEMAPHORE_TYPE_TIMELINE;
22137ec681f3Smrg      anv_timeline_init(device, &impl->timeline, initial_value);
22147ec681f3Smrg   }
22157ec681f3Smrg
22167ec681f3Smrg   return VK_SUCCESS;
22177ec681f3Smrg}
22187ec681f3Smrg
221901e04c3fSmrgVkResult anv_CreateSemaphore(
222001e04c3fSmrg    VkDevice                                    _device,
222101e04c3fSmrg    const VkSemaphoreCreateInfo*                pCreateInfo,
222201e04c3fSmrg    const VkAllocationCallbacks*                pAllocator,
222301e04c3fSmrg    VkSemaphore*                                pSemaphore)
222401e04c3fSmrg{
222501e04c3fSmrg   ANV_FROM_HANDLE(anv_device, device, _device);
222601e04c3fSmrg   struct anv_semaphore *semaphore;
222701e04c3fSmrg
222801e04c3fSmrg   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO);
222901e04c3fSmrg
22307ec681f3Smrg   uint64_t timeline_value = 0;
22317ec681f3Smrg   VkSemaphoreTypeKHR sem_type = get_semaphore_type(pCreateInfo->pNext, &timeline_value);
22327ec681f3Smrg
22337ec681f3Smrg   semaphore = vk_object_alloc(&device->vk, NULL, sizeof(*semaphore),
22347ec681f3Smrg                               VK_OBJECT_TYPE_SEMAPHORE);
223501e04c3fSmrg   if (semaphore == NULL)
22367ec681f3Smrg      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
223701e04c3fSmrg
22389f464c52Smaya   const VkExportSemaphoreCreateInfo *export =
223901e04c3fSmrg      vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO);
22407ec681f3Smrg   VkExternalSemaphoreHandleTypeFlags handleTypes =
224101e04c3fSmrg      export ? export->handleTypes : 0;
22427ec681f3Smrg   VkResult result;
224301e04c3fSmrg
224401e04c3fSmrg   if (handleTypes == 0) {
22457ec681f3Smrg      if (sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR)
22467ec681f3Smrg         result = binary_semaphore_create(device, &semaphore->permanent, false);
22477ec681f3Smrg      else
22487ec681f3Smrg         result = timeline_semaphore_create(device, &semaphore->permanent, timeline_value);
22497ec681f3Smrg      if (result != VK_SUCCESS) {
22507ec681f3Smrg         vk_object_free(&device->vk, pAllocator, semaphore);
22517ec681f3Smrg         return result;
22527ec681f3Smrg      }
225301e04c3fSmrg   } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) {
225401e04c3fSmrg      assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
22557ec681f3Smrg      if (sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR)
22567ec681f3Smrg         result = binary_semaphore_create(device, &semaphore->permanent, true);
22577ec681f3Smrg      else
22587ec681f3Smrg         result = timeline_semaphore_create(device, &semaphore->permanent, timeline_value);
22597ec681f3Smrg      if (result != VK_SUCCESS) {
22607ec681f3Smrg         vk_object_free(&device->vk, pAllocator, semaphore);
22617ec681f3Smrg         return result;
226201e04c3fSmrg      }
226301e04c3fSmrg   } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) {
226401e04c3fSmrg      assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT);
22657ec681f3Smrg      assert(sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR);
22667ec681f3Smrg      semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
22677ec681f3Smrg      semaphore->permanent.syncobj = anv_gem_syncobj_create(device, 0);
22687ec681f3Smrg      if (!semaphore->permanent.syncobj) {
22697ec681f3Smrg         vk_object_free(&device->vk, pAllocator, semaphore);
22707ec681f3Smrg         return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
22717ec681f3Smrg      }
227201e04c3fSmrg   } else {
227301e04c3fSmrg      assert(!"Unknown handle type");
22747ec681f3Smrg      vk_object_free(&device->vk, pAllocator, semaphore);
22757ec681f3Smrg      return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
227601e04c3fSmrg   }
227701e04c3fSmrg
227801e04c3fSmrg   semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
227901e04c3fSmrg
228001e04c3fSmrg   *pSemaphore = anv_semaphore_to_handle(semaphore);
228101e04c3fSmrg
228201e04c3fSmrg   return VK_SUCCESS;
228301e04c3fSmrg}
228401e04c3fSmrg
228501e04c3fSmrgstatic void
228601e04c3fSmrganv_semaphore_impl_cleanup(struct anv_device *device,
228701e04c3fSmrg                           struct anv_semaphore_impl *impl)
228801e04c3fSmrg{
228901e04c3fSmrg   switch (impl->type) {
229001e04c3fSmrg   case ANV_SEMAPHORE_TYPE_NONE:
229101e04c3fSmrg   case ANV_SEMAPHORE_TYPE_DUMMY:
229201e04c3fSmrg      /* Dummy.  Nothing to do */
229301e04c3fSmrg      break;
229401e04c3fSmrg
22957ec681f3Smrg   case ANV_SEMAPHORE_TYPE_WSI_BO:
22967ec681f3Smrg      anv_device_release_bo(device, impl->bo);
229701e04c3fSmrg      break;
229801e04c3fSmrg
22997ec681f3Smrg   case ANV_SEMAPHORE_TYPE_TIMELINE:
23007ec681f3Smrg      anv_timeline_finish(device, &impl->timeline);
230101e04c3fSmrg      break;
230201e04c3fSmrg
230301e04c3fSmrg   case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
23047ec681f3Smrg   case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE:
230501e04c3fSmrg      anv_gem_syncobj_destroy(device, impl->syncobj);
230601e04c3fSmrg      break;
230701e04c3fSmrg
230801e04c3fSmrg   default:
230901e04c3fSmrg      unreachable("Invalid semaphore type");
231001e04c3fSmrg   }
231101e04c3fSmrg
231201e04c3fSmrg   impl->type = ANV_SEMAPHORE_TYPE_NONE;
231301e04c3fSmrg}
231401e04c3fSmrg
231501e04c3fSmrgvoid
231601e04c3fSmrganv_semaphore_reset_temporary(struct anv_device *device,
231701e04c3fSmrg                              struct anv_semaphore *semaphore)
231801e04c3fSmrg{
231901e04c3fSmrg   if (semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE)
232001e04c3fSmrg      return;
232101e04c3fSmrg
232201e04c3fSmrg   anv_semaphore_impl_cleanup(device, &semaphore->temporary);
232301e04c3fSmrg}
232401e04c3fSmrg
232501e04c3fSmrgvoid anv_DestroySemaphore(
232601e04c3fSmrg    VkDevice                                    _device,
232701e04c3fSmrg    VkSemaphore                                 _semaphore,
232801e04c3fSmrg    const VkAllocationCallbacks*                pAllocator)
232901e04c3fSmrg{
233001e04c3fSmrg   ANV_FROM_HANDLE(anv_device, device, _device);
233101e04c3fSmrg   ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
233201e04c3fSmrg
233301e04c3fSmrg   if (semaphore == NULL)
233401e04c3fSmrg      return;
233501e04c3fSmrg
233601e04c3fSmrg   anv_semaphore_impl_cleanup(device, &semaphore->temporary);
233701e04c3fSmrg   anv_semaphore_impl_cleanup(device, &semaphore->permanent);
233801e04c3fSmrg
23397ec681f3Smrg   vk_object_base_finish(&semaphore->base);
23407ec681f3Smrg   vk_free(&device->vk.alloc, semaphore);
234101e04c3fSmrg}
234201e04c3fSmrg
234301e04c3fSmrgvoid anv_GetPhysicalDeviceExternalSemaphoreProperties(
234401e04c3fSmrg    VkPhysicalDevice                            physicalDevice,
23459f464c52Smaya    const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
23469f464c52Smaya    VkExternalSemaphoreProperties*               pExternalSemaphoreProperties)
234701e04c3fSmrg{
234801e04c3fSmrg   ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
234901e04c3fSmrg
23507ec681f3Smrg   VkSemaphoreTypeKHR sem_type =
23517ec681f3Smrg      get_semaphore_type(pExternalSemaphoreInfo->pNext, NULL);
23527ec681f3Smrg
235301e04c3fSmrg   switch (pExternalSemaphoreInfo->handleType) {
235401e04c3fSmrg   case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
23557ec681f3Smrg      /* Timeline semaphores are not exportable, unless we have threaded
23567ec681f3Smrg       * submission.
23577ec681f3Smrg       */
23587ec681f3Smrg      if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE_KHR && !device->has_thread_submit)
23597ec681f3Smrg         break;
236001e04c3fSmrg      pExternalSemaphoreProperties->exportFromImportedHandleTypes =
236101e04c3fSmrg         VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
236201e04c3fSmrg      pExternalSemaphoreProperties->compatibleHandleTypes =
236301e04c3fSmrg         VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
236401e04c3fSmrg      pExternalSemaphoreProperties->externalSemaphoreFeatures =
236501e04c3fSmrg         VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
236601e04c3fSmrg         VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
236701e04c3fSmrg      return;
236801e04c3fSmrg
236901e04c3fSmrg   case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
23707ec681f3Smrg      if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE_KHR)
23717ec681f3Smrg         break;
23727ec681f3Smrg      if (!device->has_exec_fence)
23737ec681f3Smrg         break;
23747ec681f3Smrg      pExternalSemaphoreProperties->exportFromImportedHandleTypes =
23757ec681f3Smrg         VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
23767ec681f3Smrg      pExternalSemaphoreProperties->compatibleHandleTypes =
23777ec681f3Smrg         VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
23787ec681f3Smrg      pExternalSemaphoreProperties->externalSemaphoreFeatures =
23797ec681f3Smrg         VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
23807ec681f3Smrg         VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
23817ec681f3Smrg      return;
238201e04c3fSmrg
238301e04c3fSmrg   default:
238401e04c3fSmrg      break;
238501e04c3fSmrg   }
238601e04c3fSmrg
238701e04c3fSmrg   pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
238801e04c3fSmrg   pExternalSemaphoreProperties->compatibleHandleTypes = 0;
238901e04c3fSmrg   pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
239001e04c3fSmrg}
239101e04c3fSmrg
239201e04c3fSmrgVkResult anv_ImportSemaphoreFdKHR(
239301e04c3fSmrg    VkDevice                                    _device,
239401e04c3fSmrg    const VkImportSemaphoreFdInfoKHR*           pImportSemaphoreFdInfo)
239501e04c3fSmrg{
239601e04c3fSmrg   ANV_FROM_HANDLE(anv_device, device, _device);
239701e04c3fSmrg   ANV_FROM_HANDLE(anv_semaphore, semaphore, pImportSemaphoreFdInfo->semaphore);
239801e04c3fSmrg   int fd = pImportSemaphoreFdInfo->fd;
239901e04c3fSmrg
240001e04c3fSmrg   struct anv_semaphore_impl new_impl = {
240101e04c3fSmrg      .type = ANV_SEMAPHORE_TYPE_NONE,
240201e04c3fSmrg   };
240301e04c3fSmrg
240401e04c3fSmrg   switch (pImportSemaphoreFdInfo->handleType) {
240501e04c3fSmrg   case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
24067ec681f3Smrg      /* When importing non temporarily, reuse the semaphore's existing
24077ec681f3Smrg       * type. The Linux/DRM implementation allows to interchangeably use
24087ec681f3Smrg       * binary & timeline semaphores and we have no way to differenciate
24097ec681f3Smrg       * them.
24107ec681f3Smrg       */
24117ec681f3Smrg      if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT)
241201e04c3fSmrg         new_impl.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
24137ec681f3Smrg      else
24147ec681f3Smrg         new_impl.type = semaphore->permanent.type;
241501e04c3fSmrg
24167ec681f3Smrg      new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);
24177ec681f3Smrg      if (!new_impl.syncobj)
24187ec681f3Smrg         return vk_error(semaphore, VK_ERROR_INVALID_EXTERNAL_HANDLE);
241901e04c3fSmrg
242001e04c3fSmrg      /* From the Vulkan spec:
242101e04c3fSmrg       *
242201e04c3fSmrg       *    "Importing semaphore state from a file descriptor transfers
242301e04c3fSmrg       *    ownership of the file descriptor from the application to the
242401e04c3fSmrg       *    Vulkan implementation. The application must not perform any
242501e04c3fSmrg       *    operations on the file descriptor after a successful import."
242601e04c3fSmrg       *
242701e04c3fSmrg       * If the import fails, we leave the file descriptor open.
242801e04c3fSmrg       */
242901e04c3fSmrg      close(fd);
243001e04c3fSmrg      break;
243101e04c3fSmrg
24327ec681f3Smrg   case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT: {
24337ec681f3Smrg      uint32_t create_flags = 0;
24347ec681f3Smrg
24357ec681f3Smrg      if (fd == -1)
24367ec681f3Smrg         create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
24377ec681f3Smrg
243801e04c3fSmrg      new_impl = (struct anv_semaphore_impl) {
24397ec681f3Smrg         .type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ,
24407ec681f3Smrg         .syncobj = anv_gem_syncobj_create(device, create_flags),
244101e04c3fSmrg      };
24427ec681f3Smrg
24437ec681f3Smrg      if (!new_impl.syncobj)
24447ec681f3Smrg         return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
24457ec681f3Smrg
24467ec681f3Smrg      if (fd != -1) {
24477ec681f3Smrg         if (anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) {
24487ec681f3Smrg            anv_gem_syncobj_destroy(device, new_impl.syncobj);
24497ec681f3Smrg            return vk_errorf(semaphore, VK_ERROR_INVALID_EXTERNAL_HANDLE,
24507ec681f3Smrg                             "syncobj sync file import failed: %m");
24517ec681f3Smrg         }
24527ec681f3Smrg         /* Ownership of the FD is transfered to Anv. Since we don't need it
24537ec681f3Smrg          * anymore because the associated fence has been put into a syncobj,
24547ec681f3Smrg          * we must close the FD.
24557ec681f3Smrg          */
24567ec681f3Smrg         close(fd);
24577ec681f3Smrg      }
245801e04c3fSmrg      break;
24597ec681f3Smrg   }
246001e04c3fSmrg
246101e04c3fSmrg   default:
24627ec681f3Smrg      return vk_error(semaphore, VK_ERROR_INVALID_EXTERNAL_HANDLE);
246301e04c3fSmrg   }
246401e04c3fSmrg
246501e04c3fSmrg   if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) {
246601e04c3fSmrg      anv_semaphore_impl_cleanup(device, &semaphore->temporary);
246701e04c3fSmrg      semaphore->temporary = new_impl;
246801e04c3fSmrg   } else {
246901e04c3fSmrg      anv_semaphore_impl_cleanup(device, &semaphore->permanent);
247001e04c3fSmrg      semaphore->permanent = new_impl;
247101e04c3fSmrg   }
247201e04c3fSmrg
247301e04c3fSmrg   return VK_SUCCESS;
247401e04c3fSmrg}
247501e04c3fSmrg
247601e04c3fSmrgVkResult anv_GetSemaphoreFdKHR(
247701e04c3fSmrg    VkDevice                                    _device,
247801e04c3fSmrg    const VkSemaphoreGetFdInfoKHR*              pGetFdInfo,
247901e04c3fSmrg    int*                                        pFd)
248001e04c3fSmrg{
248101e04c3fSmrg   ANV_FROM_HANDLE(anv_device, device, _device);
248201e04c3fSmrg   ANV_FROM_HANDLE(anv_semaphore, semaphore, pGetFdInfo->semaphore);
248301e04c3fSmrg   int fd;
248401e04c3fSmrg
248501e04c3fSmrg   assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR);
248601e04c3fSmrg
248701e04c3fSmrg   struct anv_semaphore_impl *impl =
248801e04c3fSmrg      semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
248901e04c3fSmrg      &semaphore->temporary : &semaphore->permanent;
249001e04c3fSmrg
249101e04c3fSmrg   switch (impl->type) {
24927ec681f3Smrg   case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
24937ec681f3Smrg      if (pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) {
24947ec681f3Smrg         VkResult result = wait_syncobj_materialize(device, impl->syncobj, pFd);
24957ec681f3Smrg         if (result != VK_SUCCESS)
24967ec681f3Smrg            return result;
249701e04c3fSmrg
24987ec681f3Smrg         fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj);
24997ec681f3Smrg      } else {
25007ec681f3Smrg         assert(pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
25017ec681f3Smrg         fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
25027ec681f3Smrg      }
25037ec681f3Smrg      if (fd < 0)
25047ec681f3Smrg         return vk_error(device, VK_ERROR_TOO_MANY_OBJECTS);
25057ec681f3Smrg      *pFd = fd;
25067ec681f3Smrg      break;
250701e04c3fSmrg
25087ec681f3Smrg   case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE:
25097ec681f3Smrg      assert(pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
251001e04c3fSmrg      fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
251101e04c3fSmrg      if (fd < 0)
25127ec681f3Smrg         return vk_error(device, VK_ERROR_TOO_MANY_OBJECTS);
251301e04c3fSmrg      *pFd = fd;
251401e04c3fSmrg      break;
251501e04c3fSmrg
251601e04c3fSmrg   default:
25177ec681f3Smrg      return vk_error(semaphore, VK_ERROR_INVALID_EXTERNAL_HANDLE);
251801e04c3fSmrg   }
251901e04c3fSmrg
252001e04c3fSmrg   /* From the Vulkan 1.0.53 spec:
252101e04c3fSmrg    *
252201e04c3fSmrg    *    "Export operations have the same transference as the specified handle
252301e04c3fSmrg    *    type’s import operations. [...] If the semaphore was using a
252401e04c3fSmrg    *    temporarily imported payload, the semaphore’s prior permanent payload
252501e04c3fSmrg    *    will be restored.
252601e04c3fSmrg    */
252701e04c3fSmrg   if (impl == &semaphore->temporary)
252801e04c3fSmrg      anv_semaphore_impl_cleanup(device, impl);
252901e04c3fSmrg
253001e04c3fSmrg   return VK_SUCCESS;
253101e04c3fSmrg}
25327ec681f3Smrg
25337ec681f3SmrgVkResult anv_GetSemaphoreCounterValue(
25347ec681f3Smrg    VkDevice                                    _device,
25357ec681f3Smrg    VkSemaphore                                 _semaphore,
25367ec681f3Smrg    uint64_t*                                   pValue)
25377ec681f3Smrg{
25387ec681f3Smrg   ANV_FROM_HANDLE(anv_device, device, _device);
25397ec681f3Smrg   ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
25407ec681f3Smrg
25417ec681f3Smrg   struct anv_semaphore_impl *impl =
25427ec681f3Smrg      semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
25437ec681f3Smrg      &semaphore->temporary : &semaphore->permanent;
25447ec681f3Smrg
25457ec681f3Smrg   switch (impl->type) {
25467ec681f3Smrg   case ANV_SEMAPHORE_TYPE_TIMELINE: {
25477ec681f3Smrg      pthread_mutex_lock(&device->mutex);
25487ec681f3Smrg      anv_timeline_gc_locked(device, &impl->timeline);
25497ec681f3Smrg      *pValue = impl->timeline.highest_past;
25507ec681f3Smrg      pthread_mutex_unlock(&device->mutex);
25517ec681f3Smrg      return VK_SUCCESS;
25527ec681f3Smrg   }
25537ec681f3Smrg
25547ec681f3Smrg   case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: {
25557ec681f3Smrg      int ret = anv_gem_syncobj_timeline_query(device, &impl->syncobj, pValue, 1);
25567ec681f3Smrg
25577ec681f3Smrg      if (ret != 0)
25587ec681f3Smrg         return anv_device_set_lost(device, "unable to query timeline syncobj");
25597ec681f3Smrg
25607ec681f3Smrg      return VK_SUCCESS;
25617ec681f3Smrg   }
25627ec681f3Smrg
25637ec681f3Smrg   default:
25647ec681f3Smrg      unreachable("Invalid semaphore type");
25657ec681f3Smrg   }
25667ec681f3Smrg}
25677ec681f3Smrg
25687ec681f3Smrgstatic VkResult
25697ec681f3Smrganv_timeline_wait_locked(struct anv_device *device,
25707ec681f3Smrg                         struct anv_timeline *timeline,
25717ec681f3Smrg                         uint64_t serial, uint64_t abs_timeout_ns)
25727ec681f3Smrg{
25737ec681f3Smrg   /* Wait on the queue_submit condition variable until the timeline has a
25747ec681f3Smrg    * time point pending that's at least as high as serial.
25757ec681f3Smrg    */
25767ec681f3Smrg   while (timeline->highest_pending < serial) {
25777ec681f3Smrg      struct timespec abstime = {
25787ec681f3Smrg         .tv_sec = abs_timeout_ns / NSEC_PER_SEC,
25797ec681f3Smrg         .tv_nsec = abs_timeout_ns % NSEC_PER_SEC,
25807ec681f3Smrg      };
25817ec681f3Smrg
25827ec681f3Smrg      UNUSED int ret = pthread_cond_timedwait(&device->queue_submit,
25837ec681f3Smrg                                              &device->mutex, &abstime);
25847ec681f3Smrg      assert(ret != EINVAL);
25857ec681f3Smrg      if (anv_gettime_ns() >= abs_timeout_ns &&
25867ec681f3Smrg          timeline->highest_pending < serial)
25877ec681f3Smrg         return VK_TIMEOUT;
25887ec681f3Smrg   }
25897ec681f3Smrg
25907ec681f3Smrg   while (1) {
25917ec681f3Smrg      VkResult result = anv_timeline_gc_locked(device, timeline);
25927ec681f3Smrg      if (result != VK_SUCCESS)
25937ec681f3Smrg         return result;
25947ec681f3Smrg
25957ec681f3Smrg      if (timeline->highest_past >= serial)
25967ec681f3Smrg         return VK_SUCCESS;
25977ec681f3Smrg
25987ec681f3Smrg      /* If we got here, our earliest time point has a busy BO */
25997ec681f3Smrg      struct anv_timeline_point *point =
26007ec681f3Smrg         list_first_entry(&timeline->points,
26017ec681f3Smrg                          struct anv_timeline_point, link);
26027ec681f3Smrg
26037ec681f3Smrg      /* Drop the lock while we wait. */
26047ec681f3Smrg      point->waiting++;
26057ec681f3Smrg      pthread_mutex_unlock(&device->mutex);
26067ec681f3Smrg
26077ec681f3Smrg      result = anv_device_wait(device, point->bo,
26087ec681f3Smrg                               anv_get_relative_timeout(abs_timeout_ns));
26097ec681f3Smrg
26107ec681f3Smrg      /* Pick the mutex back up */
26117ec681f3Smrg      pthread_mutex_lock(&device->mutex);
26127ec681f3Smrg      point->waiting--;
26137ec681f3Smrg
26147ec681f3Smrg      /* This covers both VK_TIMEOUT and VK_ERROR_DEVICE_LOST */
26157ec681f3Smrg      if (result != VK_SUCCESS)
26167ec681f3Smrg         return result;
26177ec681f3Smrg   }
26187ec681f3Smrg}
26197ec681f3Smrg
26207ec681f3Smrgstatic VkResult
26217ec681f3Smrganv_timelines_wait(struct anv_device *device,
26227ec681f3Smrg                   struct anv_timeline **timelines,
26237ec681f3Smrg                   const uint64_t *serials,
26247ec681f3Smrg                   uint32_t n_timelines,
26257ec681f3Smrg                   bool wait_all,
26267ec681f3Smrg                   uint64_t abs_timeout_ns)
26277ec681f3Smrg{
26287ec681f3Smrg   if (!wait_all && n_timelines > 1) {
26297ec681f3Smrg      pthread_mutex_lock(&device->mutex);
26307ec681f3Smrg
26317ec681f3Smrg      while (1) {
26327ec681f3Smrg         VkResult result;
26337ec681f3Smrg         for (uint32_t i = 0; i < n_timelines; i++) {
26347ec681f3Smrg            result =
26357ec681f3Smrg               anv_timeline_wait_locked(device, timelines[i], serials[i], 0);
26367ec681f3Smrg            if (result != VK_TIMEOUT)
26377ec681f3Smrg               break;
26387ec681f3Smrg         }
26397ec681f3Smrg
26407ec681f3Smrg         if (result != VK_TIMEOUT ||
26417ec681f3Smrg             anv_gettime_ns() >= abs_timeout_ns) {
26427ec681f3Smrg            pthread_mutex_unlock(&device->mutex);
26437ec681f3Smrg            return result;
26447ec681f3Smrg         }
26457ec681f3Smrg
26467ec681f3Smrg         /* If none of them are ready do a short wait so we don't completely
26477ec681f3Smrg          * spin while holding the lock. The 10us is completely arbitrary.
26487ec681f3Smrg          */
26497ec681f3Smrg         uint64_t abs_short_wait_ns =
26507ec681f3Smrg            anv_get_absolute_timeout(
26517ec681f3Smrg               MIN2((anv_gettime_ns() - abs_timeout_ns) / 10, 10 * 1000));
26527ec681f3Smrg         struct timespec abstime = {
26537ec681f3Smrg            .tv_sec = abs_short_wait_ns / NSEC_PER_SEC,
26547ec681f3Smrg            .tv_nsec = abs_short_wait_ns % NSEC_PER_SEC,
26557ec681f3Smrg         };
26567ec681f3Smrg         ASSERTED int ret;
26577ec681f3Smrg         ret = pthread_cond_timedwait(&device->queue_submit,
26587ec681f3Smrg                                      &device->mutex, &abstime);
26597ec681f3Smrg         assert(ret != EINVAL);
26607ec681f3Smrg      }
26617ec681f3Smrg   } else {
26627ec681f3Smrg      VkResult result = VK_SUCCESS;
26637ec681f3Smrg      pthread_mutex_lock(&device->mutex);
26647ec681f3Smrg      for (uint32_t i = 0; i < n_timelines; i++) {
26657ec681f3Smrg         result =
26667ec681f3Smrg            anv_timeline_wait_locked(device, timelines[i],
26677ec681f3Smrg                                     serials[i], abs_timeout_ns);
26687ec681f3Smrg         if (result != VK_SUCCESS)
26697ec681f3Smrg            break;
26707ec681f3Smrg      }
26717ec681f3Smrg      pthread_mutex_unlock(&device->mutex);
26727ec681f3Smrg      return result;
26737ec681f3Smrg   }
26747ec681f3Smrg}
26757ec681f3Smrg
26767ec681f3SmrgVkResult anv_WaitSemaphores(
26777ec681f3Smrg    VkDevice                                    _device,
26787ec681f3Smrg    const VkSemaphoreWaitInfoKHR*               pWaitInfo,
26797ec681f3Smrg    uint64_t                                    timeout)
26807ec681f3Smrg{
26817ec681f3Smrg   ANV_FROM_HANDLE(anv_device, device, _device);
26827ec681f3Smrg   uint32_t *handles;
26837ec681f3Smrg   struct anv_timeline **timelines;
26847ec681f3Smrg
26857ec681f3Smrg   VK_MULTIALLOC(ma);
26867ec681f3Smrg
26877ec681f3Smrg   VK_MULTIALLOC_DECL(&ma, uint64_t, values, pWaitInfo->semaphoreCount);
26887ec681f3Smrg   if (device->has_thread_submit) {
26897ec681f3Smrg      vk_multialloc_add(&ma, &handles, uint32_t, pWaitInfo->semaphoreCount);
26907ec681f3Smrg   } else {
26917ec681f3Smrg      vk_multialloc_add(&ma, &timelines, struct anv_timeline *,
26927ec681f3Smrg                             pWaitInfo->semaphoreCount);
26937ec681f3Smrg   }
26947ec681f3Smrg
26957ec681f3Smrg   if (!vk_multialloc_alloc(&ma, &device->vk.alloc,
26967ec681f3Smrg                            VK_SYSTEM_ALLOCATION_SCOPE_COMMAND))
26977ec681f3Smrg      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
26987ec681f3Smrg
26997ec681f3Smrg   uint32_t handle_count = 0;
27007ec681f3Smrg   for (uint32_t i = 0; i < pWaitInfo->semaphoreCount; i++) {
27017ec681f3Smrg      ANV_FROM_HANDLE(anv_semaphore, semaphore, pWaitInfo->pSemaphores[i]);
27027ec681f3Smrg      struct anv_semaphore_impl *impl =
27037ec681f3Smrg         semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
27047ec681f3Smrg         &semaphore->temporary : &semaphore->permanent;
27057ec681f3Smrg
27067ec681f3Smrg      if (pWaitInfo->pValues[i] == 0)
27077ec681f3Smrg         continue;
27087ec681f3Smrg
27097ec681f3Smrg      if (device->has_thread_submit) {
27107ec681f3Smrg         assert(impl->type == ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE);
27117ec681f3Smrg         handles[handle_count] = impl->syncobj;
27127ec681f3Smrg      } else {
27137ec681f3Smrg         assert(impl->type == ANV_SEMAPHORE_TYPE_TIMELINE);
27147ec681f3Smrg         timelines[handle_count] = &impl->timeline;
27157ec681f3Smrg      }
27167ec681f3Smrg      values[handle_count] = pWaitInfo->pValues[i];
27177ec681f3Smrg      handle_count++;
27187ec681f3Smrg   }
27197ec681f3Smrg
27207ec681f3Smrg   VkResult result = VK_SUCCESS;
27217ec681f3Smrg   if (handle_count > 0) {
27227ec681f3Smrg      if (device->has_thread_submit) {
27237ec681f3Smrg         int ret =
27247ec681f3Smrg            anv_gem_syncobj_timeline_wait(device,
27257ec681f3Smrg                                          handles, values, handle_count,
27267ec681f3Smrg                                          anv_get_absolute_timeout(timeout),
27277ec681f3Smrg                                          !(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT_KHR),
27287ec681f3Smrg                                          false);
27297ec681f3Smrg         if (ret != 0)
27307ec681f3Smrg            result = errno == ETIME ? VK_TIMEOUT :
27317ec681f3Smrg               anv_device_set_lost(device, "unable to wait on timeline syncobj");
27327ec681f3Smrg      } else {
27337ec681f3Smrg         result =
27347ec681f3Smrg            anv_timelines_wait(device, timelines, values, handle_count,
27357ec681f3Smrg                               !(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT_KHR),
27367ec681f3Smrg                               anv_get_absolute_timeout(timeout));
27377ec681f3Smrg      }
27387ec681f3Smrg   }
27397ec681f3Smrg
27407ec681f3Smrg   vk_free(&device->vk.alloc, values);
27417ec681f3Smrg
27427ec681f3Smrg   return result;
27437ec681f3Smrg}
27447ec681f3Smrg
27457ec681f3SmrgVkResult anv_SignalSemaphore(
27467ec681f3Smrg    VkDevice                                    _device,
27477ec681f3Smrg    const VkSemaphoreSignalInfoKHR*             pSignalInfo)
27487ec681f3Smrg{
27497ec681f3Smrg   ANV_FROM_HANDLE(anv_device, device, _device);
27507ec681f3Smrg   ANV_FROM_HANDLE(anv_semaphore, semaphore, pSignalInfo->semaphore);
27517ec681f3Smrg
27527ec681f3Smrg   struct anv_semaphore_impl *impl =
27537ec681f3Smrg      semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
27547ec681f3Smrg      &semaphore->temporary : &semaphore->permanent;
27557ec681f3Smrg
27567ec681f3Smrg   switch (impl->type) {
27577ec681f3Smrg   case ANV_SEMAPHORE_TYPE_TIMELINE: {
27587ec681f3Smrg      pthread_mutex_lock(&device->mutex);
27597ec681f3Smrg
27607ec681f3Smrg      VkResult result = anv_timeline_gc_locked(device, &impl->timeline);
27617ec681f3Smrg
27627ec681f3Smrg      assert(pSignalInfo->value > impl->timeline.highest_pending);
27637ec681f3Smrg
27647ec681f3Smrg      impl->timeline.highest_pending = impl->timeline.highest_past = pSignalInfo->value;
27657ec681f3Smrg
27667ec681f3Smrg      if (result == VK_SUCCESS)
27677ec681f3Smrg         result = anv_device_submit_deferred_locked(device);
27687ec681f3Smrg
27697ec681f3Smrg      pthread_cond_broadcast(&device->queue_submit);
27707ec681f3Smrg      pthread_mutex_unlock(&device->mutex);
27717ec681f3Smrg      return result;
27727ec681f3Smrg   }
27737ec681f3Smrg
27747ec681f3Smrg   case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: {
27757ec681f3Smrg      /* Timeline semaphores are created with a value of 0, so signaling on 0
27767ec681f3Smrg       * is a waste of time.
27777ec681f3Smrg       */
27787ec681f3Smrg      if (pSignalInfo->value == 0)
27797ec681f3Smrg         return VK_SUCCESS;
27807ec681f3Smrg
27817ec681f3Smrg      int ret = anv_gem_syncobj_timeline_signal(device, &impl->syncobj,
27827ec681f3Smrg                                                &pSignalInfo->value, 1);
27837ec681f3Smrg
27847ec681f3Smrg      return ret == 0 ? VK_SUCCESS :
27857ec681f3Smrg         anv_device_set_lost(device, "unable to signal timeline syncobj");
27867ec681f3Smrg   }
27877ec681f3Smrg
27887ec681f3Smrg   default:
27897ec681f3Smrg      unreachable("Invalid semaphore type");
27907ec681f3Smrg   }
27917ec681f3Smrg}
2792