[Mesa-dev] [PATCH 16/21] anv: Implement VK_KHX_external_semaphore_fd

Jason Ekstrand jason at jlekstrand.net
Wed May 3 16:34:15 UTC 2017


On Tue, May 2, 2017 at 5:15 PM, Chad Versace <chadversary at chromium.org>
wrote:

> On Fri 14 Apr 2017, Jason Ekstrand wrote:
> > This implementation allocates a 4k BO for each semaphore that can be
> > exported using OPAQUE_FD and uses the kernel's already-existing
> > synchronization mechanism on BOs.
> > ---
> >  src/intel/vulkan/anv_batch_chain.c      |  53 ++++++++++--
> >  src/intel/vulkan/anv_device.c           |   4 +
> >  src/intel/vulkan/anv_entrypoints_gen.py |   1 +
> >  src/intel/vulkan/anv_private.h          |  16 +++-
> >  src/intel/vulkan/anv_queue.c            | 141
> ++++++++++++++++++++++++++++++--
> >  5 files changed, 199 insertions(+), 16 deletions(-)
>
> [snip]
>
> > @@ -513,14 +533,33 @@ VkResult anv_CreateSemaphore(
> >      VkExternalSemaphoreHandleTypeFlagsKHX handleTypes =
> >        export ? export->handleTypes : 0;
> >
> > -   /* External semaphores are not yet supported */
> > -   assert(handleTypes == 0);
> > +   if (handleTypes == 0) {
> > +      /* The DRM execbuffer ioctl always execute in-oder so long as you
> stay
> > +       * on the same ring.  Since we don't expose the blit engine as a
> DMA
> > +       * queue, a dummy no-op semaphore is a perfectly valid
> implementation.
> > +       */
> > +      semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DUMMY;
> > +   } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHX)
> {
> > +      assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_
> TYPE_OPAQUE_FD_BIT_KHX);
> > +
> > +      semaphore->permanent.type = ANV_SEMAPHORE_TYPE_BO;
> > +      VkResult result = anv_bo_cache_alloc(device, &device->bo_cache,
> > +                                           4096, &semaphore->
> permanent.bo);
> > +      if (result != VK_SUCCESS) {
> > +         vk_free2(&device->alloc, pAllocator, semaphore);
> > +         return result;
> > +      }
> > +
> > +      /* If we're going to use this as a fence, we need to *not* have
> the
> > +       * EXEC_OBJECT_ASYNC bit set.
> > +       */
> > +      semaphore->permanent.bo->flags &= ~EXEC_OBJECT_ASYNC;
> > +   } else {
> > +      assert(!"Unknown handle type");
> > +      vk_free2(&device->alloc, pAllocator, semaphore);
> > +      return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX);
>
> The Vulkan 1.0.49 spec does not list
> VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX as a possible error code for
> vkCreateSemaphore. The reason is that
> VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX indicates that an external handle
> does not match the expected handle type. Since vkCreateSemaphore has no
> parameter that's an external handle, it can't return the error.
> VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX only makes sense for functions that
> import a handle or query the properties of a handle.
>
> This 'else' branch is capturing invalid application usage the API. Since
> invalid usages leads to undefined behavior, we could claim that Mesa's
> undefined behavior is to return a helpful error code. But...
>
> I much prefer disastrous undefined behavior here instead of helpful
> undefined behavior. If we return VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX,
> then appsy may accidentally rely on our out-of-spec behavior. It would
> be better to just abort() or, like anvil does in most cases, silently
> ignore the invalid case and continue blindly ahead.
>

They do get disastrous behavior in debug builds because of the assert.  In
release builds, however, I'm not sure what I think.  I don't know that I
like the idea of silently continuing because it would most likely give them
a perfectly "valid" dummy semaphore and they would get an error much later
when they try to export from it.  We could abort().  I don't know.  I
really don't think apps will rely on that error.


> [snip]
>
> > +static void
> > +anv_semaphore_impl_cleanup(struct anv_device *device,
> > +                           struct anv_semaphore_impl *impl)
> > +{
> > +   switch (impl->type) {
> > +   case ANV_SEMAPHORE_TYPE_NONE:
> > +   case ANV_SEMAPHORE_TYPE_DUMMY:
> > +      /* Dummy.  Nothing to do */
> > +      break;
> > +
> > +   case ANV_SEMAPHORE_TYPE_BO:
> > +      anv_bo_cache_release(device, &device->bo_cache, impl->bo);
> > +      break;
> > +
> > +   default:
> > +      unreachable("Invalid semaphore type");
> > +   }
>
> This switch statement is a good candidate for exhaustive switch warnings
> (-Wswitch).  But we don't get the warnings unless the default is dropped
> and the unreachable is moved to after the switch statement.
>

Sure, I can do that.


> > +}
>
> [snip]
>
> >
> > @@ -548,9 +609,73 @@ void anv_GetPhysicalDeviceExternalSemap
> horePropertiesKHX(
> >      VkExternalSemaphorePropertiesKHX*
>  pExternalSemaphoreProperties)
> >  {
> >     switch (pExternalSemaphoreInfo->handleType) {
> > +   case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHX:
> > +      pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
>
> I expected exportFromImportedHandleTypes to be
> VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHX.  Why is it 0?
> I admit I don't fully understand the VK_KHX_external_semaphore spec. (To
> be fair, I doubt anyone fully understands it).
>

I didn't figure there was any reason to allow re-export but there's no harm
in it for OPAQUE_FD.


> > +      pExternalSemaphoreProperties->compatibleHandleTypes =
> > +         VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHX;
> > +      pExternalSemaphoreProperties->externalSemaphoreFeatures =
> > +         VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHX |
> > +         VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHX;
> > +      break;
> > +
> >     default:
> >        pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
> >        pExternalSemaphoreProperties->compatibleHandleTypes = 0;
> >        pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
> >     }
> >  }
> > +
> > +VkResult anv_ImportSemaphoreFdKHX(
> > +    VkDevice                                    _device,
> > +    const VkImportSemaphoreFdInfoKHX*           pImportSemaphoreFdInfo)
> > +{
> > +   ANV_FROM_HANDLE(anv_device, device, _device);
> > +   ANV_FROM_HANDLE(anv_semaphore, semaphore, pImportSemaphoreFdInfo->
> semaphore);
> > +
> > +   switch (pImportSemaphoreFdInfo->handleType) {
> > +   case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHX: {
> > +      struct anv_bo *bo;
> > +      VkResult result = anv_bo_cache_import(device, &device->bo_cache,
> > +                                            pImportSemaphoreFdInfo->fd,
> 4096,
> > +                                            &bo);
> > +      if (result != VK_SUCCESS)
> > +         return result;
> > +
> > +      /* If we're going to use this as a fence, we need to *not* have
> the
> > +       * EXEC_OBJECT_ASYNC bit set.
> > +       */
> > +      bo->flags &= ~EXEC_OBJECT_ASYNC;
> > +
> > +      anv_semaphore_impl_cleanup(device, &semaphore->permanent);
> > +
> > +      semaphore->permanent.type = ANV_SEMAPHORE_TYPE_BO;
> > +      semaphore->permanent.bo = bo;
> > +
> > +      return VK_SUCCESS;
> > +   }
> > +
> > +   default:
> > +      return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX);
>
> Yep. VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX is required here.
>
> > +   }
> > +}
>
> > +
> > +VkResult anv_GetSemaphoreFdKHX(
> > +    VkDevice                                    _device,
> > +    VkSemaphore                                 _semaphore,
> > +    VkExternalSemaphoreHandleTypeFlagBitsKHX    handleType,
> > +    int*                                        pFd)
> > +{
> > +   ANV_FROM_HANDLE(anv_device, device, _device);
> > +   ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
> > +
> > +   switch (semaphore->permanent.type) {
> > +   case ANV_SEMAPHORE_TYPE_BO:
> > +      return anv_bo_cache_export(device, &device->bo_cache,
> > +                                 semaphore->permanent.bo, pFd);
> > +
> > +   default:
> > +      return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX);
>
> Like vkCreateSemaphore, for the same reasons,
> VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX is not a valid error code for
> vkGetSemaphoreFdKHX. And like vkCreateSemaphore, I think disastrous
> undefined behavior here is better than helpful undefined behavior.
>

Hrm... Maybe?  We could abort(). What I don't want to do is just get rid of
the case and silently return a random return value (which may be VK_SUCCES!)

As a side-note, I'm beginning to come to the conclusion that we may want to
make the undefined behavior in the driver a bit more contained.  While our
driver shouldn't be robust against API misuse, I would like it to be
deterministic and try to crash early rather than just corrupting something
and maybe crashing later in a weird way.

--Jason
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20170503/24fd9a7c/attachment.html>


More information about the mesa-dev mailing list