<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Aug 24, 2017 at 10:39 AM, Jason Ekstrand <span dir="ltr"><<a href="mailto:jason@jlekstrand.net" target="_blank">jason@jlekstrand.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><div class="h5">On Thu, Aug 24, 2017 at 10:20 AM, Lionel Landwerlin <span dir="ltr"><<a href="mailto:lionel.g.landwerlin@intel.com" target="_blank">lionel.g.landwerlin@intel.com</a><wbr>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="m_-5540633037926366307HOEnZb"><div class="m_-5540633037926366307h5">On 08/08/17 23:45, Jason Ekstrand wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
In order to implement VK_KHR_external_fence, we need to back our fences<br>
with something that's shareable.  Since the kernel wait interface for<br>
sync objects already supports waiting for multiple fences in one go, it<br>
makes anv_WaitForFences much simpler if we only have one type of fence.<br>
---<br>
  src/intel/vulkan/anv_batch_cha<wbr>in.c |   8 +++<br>
  src/intel/vulkan/anv_device.c      |   2 +<br>
  src/intel/vulkan/anv_private.h<wbr>     |   4 ++<br>
  src/intel/vulkan/anv_queue.c       | 132 ++++++++++++++++++++++++++++++<wbr>++++---<br>
  4 files changed, 136 insertions(+), 10 deletions(-)<br>
<br>
diff --git a/src/intel/vulkan/anv_batch_c<wbr>hain.c b/src/intel/vulkan/anv_batch_c<wbr>hain.c<br>
index 5d876e4..15082b5 100644<br>
--- a/src/intel/vulkan/anv_batch_c<wbr>hain.c<br>
+++ b/src/intel/vulkan/anv_batch_c<wbr>hain.c<br>
@@ -1556,6 +1556,14 @@ anv_cmd_buffer_execbuf(struct anv_device *device,<br>
              return result;<br>
           break;<br>
  +      case ANV_FENCE_TYPE_SYNCOBJ:<br>
+         result = anv_execbuf_add_syncobj(&execb<wbr>uf, impl->syncobj,<br>
+                                          I915_EXEC_FENCE_SIGNAL,<br>
+                                          &device->alloc);<br>
+         if (result != VK_SUCCESS)<br>
+            return result;<br>
+         break;<br>
+<br>
        default:<br>
           unreachable("Invalid fence type");<br>
        }<br>
diff --git a/src/intel/vulkan/anv_device.<wbr>c b/src/intel/vulkan/anv_device.<wbr>c<br>
index a6d5215..2e0fa19 100644<br>
--- a/src/intel/vulkan/anv_device.<wbr>c<br>
+++ b/src/intel/vulkan/anv_device.<wbr>c<br>
@@ -339,6 +339,8 @@ anv_physical_device_init(struc<wbr>t anv_physical_device *device,<br>
     device->has_exec_async = anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_ASYNC);<br>
     device->has_exec_fence = anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_FENCE);<br>
     device->has_syncobj = anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_FENCE_ARRA<wbr>Y);<br>
+   device->has_syncobj_wait = device->has_syncobj &&<br>
+                              anv_gem_supports_syncobj_wait(<wbr>fd);<br>
       bool swizzled = anv_gem_get_bit6_swizzle(fd, I915_TILING_X);<br>
  diff --git a/src/intel/vulkan/anv_private<wbr>.h b/src/intel/vulkan/anv_private<wbr>.h<br>
index 2f89d3f..430652d 100644<br>
--- a/src/intel/vulkan/anv_private<wbr>.h<br>
+++ b/src/intel/vulkan/anv_private<wbr>.h<br>
@@ -654,6 +654,7 @@ struct anv_physical_device {<br>
      bool                                        has_exec_async;<br>
      bool                                        has_exec_fence;<br>
      bool                                        has_syncobj;<br>
+    bool                                        has_syncobj_wait;<br>
        uint32_t                                    eu_total;<br>
      uint32_t                                    subslice_total;<br>
@@ -1755,6 +1756,9 @@ struct anv_fence_impl {<br>
           struct anv_bo bo;<br>
           enum anv_bo_fence_state state;<br>
        } bo;<br>
+<br>
+      /** DRM syncobj handle for syncobj-based fences */<br>
+      uint32_t syncobj;<br>
     };<br>
  };<br>
  diff --git a/src/intel/vulkan/anv_queue.c b/src/intel/vulkan/anv_queue.c<br>
index 7348e15..8e45bb2 100644<br>
--- a/src/intel/vulkan/anv_queue.c<br>
+++ b/src/intel/vulkan/anv_queue.c<br>
@@ -271,17 +271,25 @@ VkResult anv_CreateFence(<br>
     if (fence == NULL)<br>
        return vk_error(VK_ERROR_OUT_OF_HOST_<wbr>MEMORY);<br>
  -   fence->permanent.type = ANV_FENCE_TYPE_BO;<br>
+   if (device->instance->physicalDev<wbr>ice.has_syncobj_wait) {<br>
+      fence->permanent.type = ANV_FENCE_TYPE_SYNCOBJ;<br>
  -   VkResult result = anv_bo_pool_alloc(&device->bat<wbr>ch_bo_pool,<br>
-                                       &fence-><a href="http://permanent.bo.bo" rel="noreferrer" target="_blank">permanent.bo.bo</a>, 4096);<br>
-   if (result != VK_SUCCESS)<br>
-      return result;<br>
-<br>
-   if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {<br>
-      fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED;<br>
+      fence->permanent.syncobj = anv_gem_syncobj_create(device)<wbr>;<br>
+      if (!fence->permanent.syncobj)<br>
+         return vk_error(VK_ERROR_OUT_OF_HOST_<wbr>MEMORY);<br>
</blockquote>
<br></div></div>
Don't you need to do something when the fence is created with the signaled bit with drm syncobj?<br>
I didn't see anything in the spec that would make this illegal so I assume we have to handle it.<br>
</blockquote><div><br></div></div></div><div>Hrm... Yes, I think we do.  Unfortunately, that's going to require additional kernel API. :(  Thanks for catching that, I'll work on it today.</div></div></div></div></blockquote><div><br></div><div>Correction:  This won't require more kernel API.  I can fire off a dummy execbuf to trigger the fence in the create function.  It's just going to require more kernel API to do cleanly.</div><div><br></div><div>--Jason<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class="HOEnZb"><font color="#888888"><div><br></div><div>--Jason<br></div></font></span><div><div class="h5"><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="m_-5540633037926366307HOEnZb"><div class="m_-5540633037926366307h5"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
     } else {<br>
-      fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET;<br>
+      fence->permanent.type = ANV_FENCE_TYPE_BO;<br>
+<br>
+      VkResult result = anv_bo_pool_alloc(&device->bat<wbr>ch_bo_pool,<br>
+                                          &fence-><a href="http://permanent.bo.bo" rel="noreferrer" target="_blank">permanent.bo.bo</a>, 4096);<br>
+      if (result != VK_SUCCESS)<br>
+         return result;<br>
+<br>
+      if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {<br>
+         fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED;<br>
+      } else {<br>
+         fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET;<br>
+      }<br>
     }<br>
       *pFence = anv_fence_to_handle(fence);<br>
@@ -301,6 +309,10 @@ anv_fence_impl_cleanup(struct anv_device *device,<br>
     case ANV_FENCE_TYPE_BO:<br>
        anv_bo_pool_free(&device->batc<wbr>h_bo_pool, &impl-><a href="http://bo.bo" rel="noreferrer" target="_blank">bo.bo</a>);<br>
        return;<br>
+<br>
+   case ANV_FENCE_TYPE_SYNCOBJ:<br>
+      anv_gem_syncobj_destroy(device<wbr>, impl->syncobj);<br>
+      return;<br>
     }<br>
       unreachable("Invalid fence type");<br>
@@ -328,6 +340,8 @@ VkResult anv_ResetFences(<br>
      uint32_t                                    fenceCount,<br>
      const VkFence*                              pFences)<br>
  {<br>
+   ANV_FROM_HANDLE(anv_device, device, _device);<br>
+<br>
     for (uint32_t i = 0; i < fenceCount; i++) {<br>
        ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);<br>
  @@ -339,6 +353,10 @@ VkResult anv_ResetFences(<br>
           impl->bo.state = ANV_BO_FENCE_STATE_RESET;<br>
           break;<br>
  +      case ANV_FENCE_TYPE_SYNCOBJ:<br>
+         anv_gem_syncobj_reset(device, impl->syncobj);<br>
+         break;<br>
+<br>
        default:<br>
           unreachable("Invalid fence type");<br>
        }<br>
@@ -384,6 +402,22 @@ VkResult anv_GetFenceStatus(<br>
           unreachable("Invalid fence status");<br>
        }<br>
  +   case ANV_FENCE_TYPE_SYNCOBJ: {<br>
+      int ret = anv_gem_syncobj_wait(device, &impl->syncobj, 1, 0, true);<br>
+      if (ret == -1) {<br>
+         if (errno == ETIME) {<br>
+            return VK_NOT_READY;<br>
+         } else {<br>
+            /* We don't know the real error. */<br>
+            device->lost = true;<br>
+            return vk_errorf(VK_ERROR_DEVICE_LOST<wbr>,<br>
+                             "drm_syncobj_wait failed: %m");<br>
+         }<br>
+      } else {<br>
+         return VK_SUCCESS;<br>
+      }<br>
+   }<br>
+<br>
     default:<br>
        unreachable("Invalid fence type");<br>
     }<br>
@@ -392,6 +426,78 @@ VkResult anv_GetFenceStatus(<br>
  #define NSEC_PER_SEC 1000000000<br>
  #define INT_TYPE_MAX(type) ((1ull << (sizeof(type) * 8 - 1)) - 1)<br>
  +static uint64_t<br>
+gettime_ns(void)<br>
+{<br>
+   struct timespec current;<br>
+   clock_gettime(CLOCK_MONOTONIC<wbr>, &current);<br>
+   return (uint64_t)current.tv_sec * NSEC_PER_SEC + current.tv_nsec;<br>
+}<br>
+<br>
+static VkResult<br>
+anv_wait_for_syncobj_fences(s<wbr>truct anv_device *device,<br>
+                            uint32_t fenceCount,<br>
+                            const VkFence *pFences,<br>
+                            bool waitAll,<br>
+                            uint64_t _timeout)<br>
+{<br>
+   uint32_t *syncobjs = vk_zalloc(&device->alloc,<br>
+                                  sizeof(*syncobjs) * fenceCount, 8,<br>
+                                  VK_SYSTEM_ALLOCATION_SCOPE_COM<wbr>MAND);<br>
+   if (!syncobjs)<br>
+      return vk_error(VK_ERROR_OUT_OF_HOST_<wbr>MEMORY);<br>
+<br>
+   for (uint32_t i = 0; i < fenceCount; i++) {<br>
+      ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);<br>
+      assert(fence->permanent.type == ANV_FENCE_TYPE_SYNCOBJ);<br>
+<br>
+      struct anv_fence_impl *impl =<br>
+         fence->temporary.type != ANV_FENCE_TYPE_NONE ?<br>
+         &fence->temporary : &fence->permanent;<br>
+<br>
+      assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);<br>
+      syncobjs[i] = impl->syncobj;<br>
+   }<br>
+<br>
+   int64_t abs_timeout_ns = 0;<br>
+   if (_timeout > 0) {<br>
+      uint64_t current_ns = gettime_ns();<br>
+<br>
+      /* Add but saturate to INT32_MAX */<br>
+      if (current_ns + _timeout < current_ns)<br>
+         abs_timeout_ns = INT64_MAX;<br>
+      else if (current_ns + _timeout > INT64_MAX)<br>
+         abs_timeout_ns = INT64_MAX;<br>
+      else<br>
+         abs_timeout_ns = current_ns + _timeout;<br>
+   }<br>
+<br>
+   /* The gem_syncobj_wait ioctl may return early due to an inherent<br>
+    * limitation in the way it computes timeouts.  Loop until we've actually<br>
+    * passed the timeout.<br>
+    */<br>
+   int ret;<br>
+   do {<br>
+      ret = anv_gem_syncobj_wait(device, syncobjs, fenceCount,<br>
+                                 abs_timeout_ns, waitAll);<br>
+   } while (ret == -1 && errno == ETIME && gettime_ns() < abs_timeout_ns);<br>
+<br>
+   vk_free(&device->alloc, syncobjs);<br>
+<br>
+   if (ret == -1) {<br>
+      if (errno == ETIME) {<br>
+         return VK_TIMEOUT;<br>
+      } else {<br>
+         /* We don't know the real error. */<br>
+         device->lost = true;<br>
+         return vk_errorf(VK_ERROR_DEVICE_LOST<wbr>,<br>
+                          "drm_syncobj_wait failed: %m");<br>
+      }<br>
+   } else {<br>
+      return VK_SUCCESS;<br>
+   }<br>
+}<br>
+<br>
  static VkResult<br>
  anv_wait_for_bo_fences(struct anv_device *device,<br>
                         uint32_t fenceCount,<br>
@@ -546,7 +652,13 @@ VkResult anv_WaitForFences(<br>
     if (unlikely(device->lost))<br>
        return VK_ERROR_DEVICE_LOST;<br>
  -   return anv_wait_for_bo_fences(device, fenceCount, pFences, waitAll, timeout);<br>
+   if (device->instance->physicalDev<wbr>ice.has_syncobj_wait) {<br>
+      return anv_wait_for_syncobj_fences(de<wbr>vice, fenceCount, pFences,<br>
+                                         waitAll, timeout);<br>
+   } else {<br>
+      return anv_wait_for_bo_fences(device, fenceCount, pFences,<br>
+                                    waitAll, timeout);<br>
+   }<br>
  }<br>
    // Queue semaphore functions<br>
</blockquote>
<br>
<br>
</div></div></blockquote></div></div></div><br></div></div>
</blockquote></div><br></div></div>