<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Tue, May 2, 2017 at 5:15 PM, Chad Versace <span dir="ltr"><<a href="mailto:chadversary@chromium.org" target="_blank">chadversary@chromium.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On Fri 14 Apr 2017, Jason Ekstrand wrote:<br>
> This implementation allocates a 4k BO for each semaphore that can be<br>
> exported using OPAQUE_FD and uses the kernel's already-existing<br>
> synchronization mechanism on BOs.<br>
> ---<br>
>  src/intel/vulkan/anv_batch_<wbr>chain.c      |  53 ++++++++++--<br>
>  src/intel/vulkan/anv_device.c           |   4 +<br>
>  src/intel/vulkan/anv_<wbr>entrypoints_gen.py |   1 +<br>
>  src/intel/vulkan/anv_private.h          |  16 +++-<br>
>  src/intel/vulkan/anv_queue.c            | 141 ++++++++++++++++++++++++++++++<wbr>--<br>
>  5 files changed, 199 insertions(+), 16 deletions(-)<br>
<br>
</span>[snip]<br>
<div><div class="h5"><br>
> @@ -513,14 +533,33 @@ VkResult anv_CreateSemaphore(<br>
>      VkExternalSemaphoreHandleTypeF<wbr>lagsKHX handleTypes =<br>
>        export ? export->handleTypes : 0;<br>
><br>
> -   /* External semaphores are not yet supported */<br>
> -   assert(handleTypes == 0);<br>
> +   if (handleTypes == 0) {<br>
> +      /* The DRM execbuffer ioctl always execute in-oder so long as you stay<br>
> +       * on the same ring.  Since we don't expose the blit engine as a DMA<br>
> +       * queue, a dummy no-op semaphore is a perfectly valid implementation.<br>
> +       */<br>
> +      semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DUMMY;<br>
> +   } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_<wbr>TYPE_OPAQUE_FD_BIT_KHX) {<br>
> +      assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_<wbr>TYPE_OPAQUE_FD_BIT_KHX);<br>
> +<br>
> +      semaphore->permanent.type = ANV_SEMAPHORE_TYPE_BO;<br>
> +      VkResult result = anv_bo_cache_alloc(device, &device->bo_cache,<br>
> +                                           4096, &semaphore-><a href="http://permanent.bo" rel="noreferrer" target="_blank">permanent.bo</a>);<br>
> +      if (result != VK_SUCCESS) {<br>
> +         vk_free2(&device->alloc, pAllocator, semaphore);<br>
> +         return result;<br>
> +      }<br>
> +<br>
> +      /* If we're going to use this as a fence, we need to *not* have the<br>
> +       * EXEC_OBJECT_ASYNC bit set.<br>
> +       */<br>
> +      semaphore->permanent.bo->flags &= ~EXEC_OBJECT_ASYNC;<br>
> +   } else {<br>
> +      assert(!"Unknown handle type");<br>
> +      vk_free2(&device->alloc, pAllocator, semaphore);<br>
> +      return vk_error(VK_ERROR_INVALID_<wbr>EXTERNAL_HANDLE_KHX);<br>
<br>
</div></div>The Vulkan 1.0.49 spec does not list<br>
VK_ERROR_INVALID_EXTERNAL_<wbr>HANDLE_KHX as a possible error code for<br>
vkCreateSemaphore. The reason is that<br>
VK_ERROR_INVALID_EXTERNAL_<wbr>HANDLE_KHX indicates that an external handle<br>
does not match the expected handle type. Since vkCreateSemaphore has no<br>
parameter that's an external handle, it can't return the error.<br>
VK_ERROR_INVALID_EXTERNAL_<wbr>HANDLE_KHX only makes sense for functions that<br>
import a handle or query the properties of a handle.<br>
<br>
This 'else' branch is capturing invalid application usage the API. Since<br>
invalid usages leads to undefined behavior, we could claim that Mesa's<br>
undefined behavior is to return a helpful error code. But...<br>
<br>
I much prefer disastrous undefined behavior here instead of helpful<br>
undefined behavior. If we return VK_ERROR_INVALID_EXTERNAL_<wbr>HANDLE_KHX,<br>
then appsy may accidentally rely on our out-of-spec behavior. It would<br>
be better to just abort() or, like anvil does in most cases, silently<br>
ignore the invalid case and continue blindly ahead.<br></blockquote><div><br></div><div>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.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
[snip]<br>
<span class=""><br>
> +static void<br>
> +anv_semaphore_impl_cleanup(<wbr>struct anv_device *device,<br>
> +                           struct anv_semaphore_impl *impl)<br>
> +{<br>
> +   switch (impl->type) {<br>
> +   case ANV_SEMAPHORE_TYPE_NONE:<br>
> +   case ANV_SEMAPHORE_TYPE_DUMMY:<br>
> +      /* Dummy.  Nothing to do */<br>
> +      break;<br>
> +<br>
> +   case ANV_SEMAPHORE_TYPE_BO:<br>
> +      anv_bo_cache_release(device, &device->bo_cache, impl->bo);<br>
> +      break;<br>
> +<br>
> +   default:<br>
> +      unreachable("Invalid semaphore type");<br>
> +   }<br>
<br>
</span>This switch statement is a good candidate for exhaustive switch warnings<br>
(-Wswitch).  But we don't get the warnings unless the default is dropped<br>
and the unreachable is moved to after the switch statement.<br></blockquote><div><br></div><div>Sure, I can do that.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +}<br>
<br>
[snip]<br>
<span class=""><br>
><br>
> @@ -548,9 +609,73 @@ void anv_<wbr>GetPhysicalDeviceExternalSemap<wbr>horePropertiesKHX(<br>
>      VkExternalSemaphorePropertiesK<wbr>HX*           pExternalSemaphoreProperties)<br>
>  {<br>
>     switch (pExternalSemaphoreInfo-><wbr>handleType) {<br>
> +   case VK_EXTERNAL_SEMAPHORE_HANDLE_<wbr>TYPE_OPAQUE_FD_BIT_KHX:<br>
> +      pExternalSemaphoreProperties-><wbr>exportFromImportedHandleTypes = 0;<br>
<br>
</span>I expected exportFromImportedHandleTypes to be<br>
VK_EXTERNAL_SEMAPHORE_HANDLE_<wbr>TYPE_OPAQUE_FD_BIT_KHX.  Why is it 0?<br>
I admit I don't fully understand the VK_KHX_external_semaphore spec. (To<br>
be fair, I doubt anyone fully understands it).<br><div><div class="h5"></div></div></blockquote><div><br></div><div>I didn't figure there was any reason to allow re-export but there's no harm in it for OPAQUE_FD.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5">
> +      pExternalSemaphoreProperties-><wbr>compatibleHandleTypes =<br>
> +         VK_EXTERNAL_SEMAPHORE_HANDLE_<wbr>TYPE_OPAQUE_FD_BIT_KHX;<br>
> +      pExternalSemaphoreProperties-><wbr>externalSemaphoreFeatures =<br>
> +         VK_EXTERNAL_SEMAPHORE_FEATURE_<wbr>EXPORTABLE_BIT_KHX |<br>
> +         VK_EXTERNAL_SEMAPHORE_FEATURE_<wbr>IMPORTABLE_BIT_KHX;<br>
> +      break;<br>
> +<br>
>     default:<br>
>        pExternalSemaphoreProperties-><wbr>exportFromImportedHandleTypes = 0;<br>
>        pExternalSemaphoreProperties-><wbr>compatibleHandleTypes = 0;<br>
>        pExternalSemaphoreProperties-><wbr>externalSemaphoreFeatures = 0;<br>
>     }<br>
>  }<br>
> +<br>
> +VkResult anv_ImportSemaphoreFdKHX(<br>
> +    VkDevice                                    _device,<br>
> +    const VkImportSemaphoreFdInfoKHX*           pImportSemaphoreFdInfo)<br>
> +{<br>
> +   ANV_FROM_HANDLE(anv_device, device, _device);<br>
> +   ANV_FROM_HANDLE(anv_semaphore, semaphore, pImportSemaphoreFdInfo-><wbr>semaphore);<br>
> +<br>
> +   switch (pImportSemaphoreFdInfo-><wbr>handleType) {<br>
> +   case VK_EXTERNAL_SEMAPHORE_HANDLE_<wbr>TYPE_OPAQUE_FD_BIT_KHX: {<br>
> +      struct anv_bo *bo;<br>
> +      VkResult result = anv_bo_cache_import(device, &device->bo_cache,<br>
> +                                            pImportSemaphoreFdInfo->fd, 4096,<br>
> +                                            &bo);<br>
> +      if (result != VK_SUCCESS)<br>
> +         return result;<br>
> +<br>
> +      /* If we're going to use this as a fence, we need to *not* have the<br>
> +       * EXEC_OBJECT_ASYNC bit set.<br>
> +       */<br>
> +      bo->flags &= ~EXEC_OBJECT_ASYNC;<br>
> +<br>
> +      anv_semaphore_impl_cleanup(<wbr>device, &semaphore->permanent);<br>
> +<br>
> +      semaphore->permanent.type = ANV_SEMAPHORE_TYPE_BO;<br>
> +      semaphore-><a href="http://permanent.bo" rel="noreferrer" target="_blank">permanent.bo</a> = bo;<br>
> +<br>
> +      return VK_SUCCESS;<br>
> +   }<br>
> +<br>
> +   default:<br>
> +      return vk_error(VK_ERROR_INVALID_<wbr>EXTERNAL_HANDLE_KHX);<br>
<br>
</div></div>Yep. VK_ERROR_INVALID_EXTERNAL_<wbr>HANDLE_KHX is required here.<br>
<span class=""><br>
> +   }<br>
> +}<br>
<br>
> +<br>
> +VkResult anv_GetSemaphoreFdKHX(<br>
> +    VkDevice                                    _device,<br>
> +    VkSemaphore                                 _semaphore,<br>
> +    VkExternalSemaphoreHandleTypeF<wbr>lagBitsKHX    handleType,<br>
> +    int*                                        pFd)<br>
> +{<br>
> +   ANV_FROM_HANDLE(anv_device, device, _device);<br>
> +   ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);<br>
> +<br>
> +   switch (semaphore->permanent.type) {<br>
> +   case ANV_SEMAPHORE_TYPE_BO:<br>
> +      return anv_bo_cache_export(device, &device->bo_cache,<br>
> +                                 semaphore-><a href="http://permanent.bo" rel="noreferrer" target="_blank">permanent.bo</a>, pFd);<br>
> +<br>
> +   default:<br>
> +      return vk_error(VK_ERROR_INVALID_<wbr>EXTERNAL_HANDLE_KHX);<br>
<br>
</span>Like vkCreateSemaphore, for the same reasons,<br>
VK_ERROR_INVALID_EXTERNAL_<wbr>HANDLE_KHX is not a valid error code for<br>
vkGetSemaphoreFdKHX. And like vkCreateSemaphore, I think disastrous<br>
undefined behavior here is better than helpful undefined behavior.<br></blockquote><div><br></div><div>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!)<br><br></div><div>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.<br></div><div><br></div><div>--Jason <br></div></div></div></div>