[Mesa-dev] [RFC] anv: Use DRM sync objects for external semaphores when available

Chris Wilson chris at chris-wilson.co.uk
Wed Apr 12 20:36:38 UTC 2017


On Wed, Apr 12, 2017 at 11:12:31AM -0700, Jason Ekstrand wrote:
> This patch is based on the work that's already been on the list for some
> time to implement VK_KHX_external_semaphore.  The difference here is that
> this patch makes us able to use the new DRM syncobj API cooked up by Dave
> Airlie.  This patch seems to work ok assuming a Kernel API I cooked up that
> has yet to get any review and very hackish kernel patch on top of Dave's
> stuff.  Mostly, I'm sending it to the list so that people can get an idea
> of what the implementation looks like so that we can get the ball rolling
> on getting the final kernel API in place.
> 
> Cc: Chad Versace <chadversary at chromium.org>
> Cc: Dave Airlie <airlied at redhat.com>
> Cc: Daniel Vetter <daniel.vetter at ffwll.ch>
> Cc: Chris Wilson <chris at chris-wilson.co.uk>
> 
> ---
>  src/intel/vulkan/anv_batch_chain.c | 72 +++++++++++++++++++++++++++++++++++
>  src/intel/vulkan/anv_device.c      |  3 ++
>  src/intel/vulkan/anv_private.h     |  8 ++++
>  src/intel/vulkan/anv_queue.c       | 77 ++++++++++++++++++++++++++++++--------
>  4 files changed, 144 insertions(+), 16 deletions(-)
> 
> diff --git a/src/intel/vulkan/anv_batch_chain.c b/src/intel/vulkan/anv_batch_chain.c
> index 0a86ae5..46c4078 100644
> --- a/src/intel/vulkan/anv_batch_chain.c
> +++ b/src/intel/vulkan/anv_batch_chain.c
> @@ -953,6 +953,21 @@ anv_cmd_buffer_add_secondary(struct anv_cmd_buffer *primary,
>                           &secondary->surface_relocs, 0);
>  }
>  
> +struct drm_i915_gem_exec_fence {
> +	/**
> +	 * User's handle for a dma-fence to wait on or signal.
> +	 */
> +	__u32 handle;
> +
> +	__u32 rsvd1;
> +
> +#define I915_EXEC_FENCE_WAIT            (1<<0)
> +#define I915_EXEC_FENCE_SIGNAL          (1<<1)
> +	__u64 flags;

u32 handle;
u32 flags;

Whether or not to leave u64 rsvd[]? But we can just as easily override
the semaphore array with new abi.

> +};
> +
> +#define I915_EXEC_FENCE_ARRAY   (1<<18)
> +
>  struct anv_execbuf {
>     struct drm_i915_gem_execbuffer2           execbuf;
>  
> @@ -962,6 +977,10 @@ struct anv_execbuf {
>  
>     /* Allocated length of the 'objects' and 'bos' arrays */
>     uint32_t                                  array_length;
> +
> +   uint32_t                                  fence_count;
> +   uint32_t                                  fence_array_length;
> +   struct drm_i915_gem_exec_fence *          fences;
>  };
>  
>  static void
> @@ -976,6 +995,7 @@ anv_execbuf_finish(struct anv_execbuf *exec,
>  {
>     vk_free(alloc, exec->objects);
>     vk_free(alloc, exec->bos);
> +   vk_free(alloc, exec->fences);
>  }
>  
>  static VkResult
> @@ -1040,6 +1060,9 @@ anv_execbuf_add_bo(struct anv_execbuf *exec,
>        obj->flags = flags | (bo->is_winsys_bo ? EXEC_OBJECT_WRITE : 0);
>        obj->rsvd1 = 0;
>        obj->rsvd2 = 0;

/* Vk provides explicit synchronisation primitives to the user, so
 * disable GEM's implicit synchronisation.
 *
 * Except for two cases:
 *
 *  (a) window system buffers are shared with an independent renderer,
 *      but we may not be sharing explicit fences and so rely on implicit
 *      synchronisation between ourselves;
 *
 *  (b) we build some explicit synchronisation primitives using writable
 *      bo i.e. exposing GEM's implicit synchronsiation as a first
 *      class Vk object.
 */

Something like that?

> +      if (!(obj->flags & EXEC_OBJECT_WRITE))
> +         obj->flags |= EXEC_OBJECT_ASYNC;
>     }
>  
>     if (relocs != NULL && obj->relocation_count == 0) {
> @@ -1060,6 +1083,33 @@ anv_execbuf_add_bo(struct anv_execbuf *exec,
>     return VK_SUCCESS;
>  }
>  
> +static VkResult
> +anv_execbuf_add_syncobj(struct anv_execbuf *exec,
> +                        uint32_t handle,
> +                        uint32_t flags,
> +                        const VkAllocationCallbacks *alloc)
> +{
> +   if (exec->fence_count >= exec->fence_array_length) {
> +      uint32_t new_len = MAX2(exec->fence_array_length * 2, 64);
> +
> +      struct drm_i915_gem_exec_fence *new_fences =
> +         vk_realloc(alloc, exec->fences, new_len * sizeof(*new_fences),
> +                    8, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
> +      if (new_fences == NULL)
> +         return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
> +
> +      exec->fences = new_fences;
> +      exec->fence_array_length = new_len;
> +   }
> +
> +   exec->fences[exec->fence_count] = (struct drm_i915_gem_exec_fence) {
> +      .handle = handle,
> +      .flags = flags,
> +   };
> +
> +   return VK_SUCCESS;
> +}
> +
>  static void
>  anv_cmd_buffer_process_relocs(struct anv_cmd_buffer *cmd_buffer,
>                                struct anv_reloc_list *list)
> @@ -1444,6 +1494,14 @@ anv_cmd_buffer_execbuf(struct anv_device *device,
>           impl->fd = -1;
>           break;
>  
> +      case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
> +         result = anv_execbuf_add_syncobj(&execbuf, impl->syncobj,
> +                                          I915_EXEC_FENCE_WAIT,
> +                                          &device->alloc);
> +         if (result != VK_SUCCESS)
> +            return result;
> +         break;
> +
>        default:
>           break;
>        }
> @@ -1478,6 +1536,14 @@ anv_cmd_buffer_execbuf(struct anv_device *device,
>           need_out_fence = true;
>           break;
>  
> +      case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
> +         result = anv_execbuf_add_syncobj(&execbuf, impl->syncobj,
> +                                          I915_EXEC_FENCE_SIGNAL,
> +                                          &device->alloc);
> +         if (result != VK_SUCCESS)
> +            return result;
> +         break;
> +
>        default:
>           break;
>        }
> @@ -1491,6 +1557,12 @@ anv_cmd_buffer_execbuf(struct anv_device *device,
>        setup_empty_execbuf(&execbuf, device);
>     }
>  
> +   if (execbuf.fence_count > 0) {
> +      execbuf.execbuf.flags |= I915_EXEC_FENCE_ARRAY;
> +      execbuf.execbuf.num_cliprects = execbuf.fence_count;
> +      execbuf.execbuf.cliprects_ptr = (uintptr_t) execbuf.fences;
> +   }

That looks very neat.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre


More information about the mesa-dev mailing list