[Mesa-dev] [PATCH 08/10] anv: Use DRM sync objects to back fences whenever possible

Lionel Landwerlin lionel.g.landwerlin at intel.com
Thu Aug 24 17:20:22 UTC 2017


On 08/08/17 23:45, Jason Ekstrand wrote:
> In order to implement VK_KHR_external_fence, we need to back our fences
> with something that's shareable.  Since the kernel wait interface for
> sync objects already supports waiting for multiple fences in one go, it
> makes anv_WaitForFences much simpler if we only have one type of fence.
> ---
>   src/intel/vulkan/anv_batch_chain.c |   8 +++
>   src/intel/vulkan/anv_device.c      |   2 +
>   src/intel/vulkan/anv_private.h     |   4 ++
>   src/intel/vulkan/anv_queue.c       | 132 ++++++++++++++++++++++++++++++++++---
>   4 files changed, 136 insertions(+), 10 deletions(-)
>
> diff --git a/src/intel/vulkan/anv_batch_chain.c b/src/intel/vulkan/anv_batch_chain.c
> index 5d876e4..15082b5 100644
> --- a/src/intel/vulkan/anv_batch_chain.c
> +++ b/src/intel/vulkan/anv_batch_chain.c
> @@ -1556,6 +1556,14 @@ anv_cmd_buffer_execbuf(struct anv_device *device,
>               return result;
>            break;
>   
> +      case ANV_FENCE_TYPE_SYNCOBJ:
> +         result = anv_execbuf_add_syncobj(&execbuf, impl->syncobj,
> +                                          I915_EXEC_FENCE_SIGNAL,
> +                                          &device->alloc);
> +         if (result != VK_SUCCESS)
> +            return result;
> +         break;
> +
>         default:
>            unreachable("Invalid fence type");
>         }
> diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
> index a6d5215..2e0fa19 100644
> --- a/src/intel/vulkan/anv_device.c
> +++ b/src/intel/vulkan/anv_device.c
> @@ -339,6 +339,8 @@ anv_physical_device_init(struct anv_physical_device *device,
>      device->has_exec_async = anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_ASYNC);
>      device->has_exec_fence = anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_FENCE);
>      device->has_syncobj = anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_FENCE_ARRAY);
> +   device->has_syncobj_wait = device->has_syncobj &&
> +                              anv_gem_supports_syncobj_wait(fd);
>   
>      bool swizzled = anv_gem_get_bit6_swizzle(fd, I915_TILING_X);
>   
> diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
> index 2f89d3f..430652d 100644
> --- a/src/intel/vulkan/anv_private.h
> +++ b/src/intel/vulkan/anv_private.h
> @@ -654,6 +654,7 @@ struct anv_physical_device {
>       bool                                        has_exec_async;
>       bool                                        has_exec_fence;
>       bool                                        has_syncobj;
> +    bool                                        has_syncobj_wait;
>   
>       uint32_t                                    eu_total;
>       uint32_t                                    subslice_total;
> @@ -1755,6 +1756,9 @@ struct anv_fence_impl {
>            struct anv_bo bo;
>            enum anv_bo_fence_state state;
>         } bo;
> +
> +      /** DRM syncobj handle for syncobj-based fences */
> +      uint32_t syncobj;
>      };
>   };
>   
> diff --git a/src/intel/vulkan/anv_queue.c b/src/intel/vulkan/anv_queue.c
> index 7348e15..8e45bb2 100644
> --- a/src/intel/vulkan/anv_queue.c
> +++ b/src/intel/vulkan/anv_queue.c
> @@ -271,17 +271,25 @@ VkResult anv_CreateFence(
>      if (fence == NULL)
>         return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
>   
> -   fence->permanent.type = ANV_FENCE_TYPE_BO;
> +   if (device->instance->physicalDevice.has_syncobj_wait) {
> +      fence->permanent.type = ANV_FENCE_TYPE_SYNCOBJ;
>   
> -   VkResult result = anv_bo_pool_alloc(&device->batch_bo_pool,
> -                                       &fence->permanent.bo.bo, 4096);
> -   if (result != VK_SUCCESS)
> -      return result;
> -
> -   if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
> -      fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED;
> +      fence->permanent.syncobj = anv_gem_syncobj_create(device);
> +      if (!fence->permanent.syncobj)
> +         return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);

Don't you need to do something when the fence is created with the 
signaled bit with drm syncobj?
I didn't see anything in the spec that would make this illegal so I 
assume we have to handle it.

>      } else {
> -      fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET;
> +      fence->permanent.type = ANV_FENCE_TYPE_BO;
> +
> +      VkResult result = anv_bo_pool_alloc(&device->batch_bo_pool,
> +                                          &fence->permanent.bo.bo, 4096);
> +      if (result != VK_SUCCESS)
> +         return result;
> +
> +      if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
> +         fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED;
> +      } else {
> +         fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET;
> +      }
>      }
>   
>      *pFence = anv_fence_to_handle(fence);
> @@ -301,6 +309,10 @@ anv_fence_impl_cleanup(struct anv_device *device,
>      case ANV_FENCE_TYPE_BO:
>         anv_bo_pool_free(&device->batch_bo_pool, &impl->bo.bo);
>         return;
> +
> +   case ANV_FENCE_TYPE_SYNCOBJ:
> +      anv_gem_syncobj_destroy(device, impl->syncobj);
> +      return;
>      }
>   
>      unreachable("Invalid fence type");
> @@ -328,6 +340,8 @@ VkResult anv_ResetFences(
>       uint32_t                                    fenceCount,
>       const VkFence*                              pFences)
>   {
> +   ANV_FROM_HANDLE(anv_device, device, _device);
> +
>      for (uint32_t i = 0; i < fenceCount; i++) {
>         ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
>   
> @@ -339,6 +353,10 @@ VkResult anv_ResetFences(
>            impl->bo.state = ANV_BO_FENCE_STATE_RESET;
>            break;
>   
> +      case ANV_FENCE_TYPE_SYNCOBJ:
> +         anv_gem_syncobj_reset(device, impl->syncobj);
> +         break;
> +
>         default:
>            unreachable("Invalid fence type");
>         }
> @@ -384,6 +402,22 @@ VkResult anv_GetFenceStatus(
>            unreachable("Invalid fence status");
>         }
>   
> +   case ANV_FENCE_TYPE_SYNCOBJ: {
> +      int ret = anv_gem_syncobj_wait(device, &impl->syncobj, 1, 0, true);
> +      if (ret == -1) {
> +         if (errno == ETIME) {
> +            return VK_NOT_READY;
> +         } else {
> +            /* We don't know the real error. */
> +            device->lost = true;
> +            return vk_errorf(VK_ERROR_DEVICE_LOST,
> +                             "drm_syncobj_wait failed: %m");
> +         }
> +      } else {
> +         return VK_SUCCESS;
> +      }
> +   }
> +
>      default:
>         unreachable("Invalid fence type");
>      }
> @@ -392,6 +426,78 @@ VkResult anv_GetFenceStatus(
>   #define NSEC_PER_SEC 1000000000
>   #define INT_TYPE_MAX(type) ((1ull << (sizeof(type) * 8 - 1)) - 1)
>   
> +static uint64_t
> +gettime_ns(void)
> +{
> +   struct timespec current;
> +   clock_gettime(CLOCK_MONOTONIC, &current);
> +   return (uint64_t)current.tv_sec * NSEC_PER_SEC + current.tv_nsec;
> +}
> +
> +static VkResult
> +anv_wait_for_syncobj_fences(struct anv_device *device,
> +                            uint32_t fenceCount,
> +                            const VkFence *pFences,
> +                            bool waitAll,
> +                            uint64_t _timeout)
> +{
> +   uint32_t *syncobjs = vk_zalloc(&device->alloc,
> +                                  sizeof(*syncobjs) * fenceCount, 8,
> +                                  VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
> +   if (!syncobjs)
> +      return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
> +
> +   for (uint32_t i = 0; i < fenceCount; i++) {
> +      ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
> +      assert(fence->permanent.type == ANV_FENCE_TYPE_SYNCOBJ);
> +
> +      struct anv_fence_impl *impl =
> +         fence->temporary.type != ANV_FENCE_TYPE_NONE ?
> +         &fence->temporary : &fence->permanent;
> +
> +      assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
> +      syncobjs[i] = impl->syncobj;
> +   }
> +
> +   int64_t abs_timeout_ns = 0;
> +   if (_timeout > 0) {
> +      uint64_t current_ns = gettime_ns();
> +
> +      /* Add but saturate to INT32_MAX */
> +      if (current_ns + _timeout < current_ns)
> +         abs_timeout_ns = INT64_MAX;
> +      else if (current_ns + _timeout > INT64_MAX)
> +         abs_timeout_ns = INT64_MAX;
> +      else
> +         abs_timeout_ns = current_ns + _timeout;
> +   }
> +
> +   /* The gem_syncobj_wait ioctl may return early due to an inherent
> +    * limitation in the way it computes timeouts.  Loop until we've actually
> +    * passed the timeout.
> +    */
> +   int ret;
> +   do {
> +      ret = anv_gem_syncobj_wait(device, syncobjs, fenceCount,
> +                                 abs_timeout_ns, waitAll);
> +   } while (ret == -1 && errno == ETIME && gettime_ns() < abs_timeout_ns);
> +
> +   vk_free(&device->alloc, syncobjs);
> +
> +   if (ret == -1) {
> +      if (errno == ETIME) {
> +         return VK_TIMEOUT;
> +      } else {
> +         /* We don't know the real error. */
> +         device->lost = true;
> +         return vk_errorf(VK_ERROR_DEVICE_LOST,
> +                          "drm_syncobj_wait failed: %m");
> +      }
> +   } else {
> +      return VK_SUCCESS;
> +   }
> +}
> +
>   static VkResult
>   anv_wait_for_bo_fences(struct anv_device *device,
>                          uint32_t fenceCount,
> @@ -546,7 +652,13 @@ VkResult anv_WaitForFences(
>      if (unlikely(device->lost))
>         return VK_ERROR_DEVICE_LOST;
>   
> -   return anv_wait_for_bo_fences(device, fenceCount, pFences, waitAll, timeout);
> +   if (device->instance->physicalDevice.has_syncobj_wait) {
> +      return anv_wait_for_syncobj_fences(device, fenceCount, pFences,
> +                                         waitAll, timeout);
> +   } else {
> +      return anv_wait_for_bo_fences(device, fenceCount, pFences,
> +                                    waitAll, timeout);
> +   }
>   }
>   
>   // Queue semaphore functions




More information about the mesa-dev mailing list