[Mesa-dev] [PATCH v2 1/9] anv: Add a basic implementation of VK_KHX_external_semaphore

Jason Ekstrand jason at jlekstrand.net
Fri Aug 4 01:25:20 UTC 2017


This patch adds an implementation based on DRM BOs.  We don't actually
advertise the extension yet because we want to add a couple more paths
first.
---
 src/intel/vulkan/anv_batch_chain.c |  31 +++++++-
 src/intel/vulkan/anv_extensions.py |   3 +
 src/intel/vulkan/anv_private.h     |   3 +
 src/intel/vulkan/anv_queue.c       | 154 +++++++++++++++++++++++++++++++++++--
 4 files changed, 184 insertions(+), 7 deletions(-)

diff --git a/src/intel/vulkan/anv_batch_chain.c b/src/intel/vulkan/anv_batch_chain.c
index ad76dc1..94e7a7d 100644
--- a/src/intel/vulkan/anv_batch_chain.c
+++ b/src/intel/vulkan/anv_batch_chain.c
@@ -1419,8 +1419,21 @@ anv_cmd_buffer_execbuf(struct anv_device *device,
 
    for (uint32_t i = 0; i < num_out_semaphores; i++) {
       ANV_FROM_HANDLE(anv_semaphore, semaphore, out_semaphores[i]);
-      assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE);
-      struct anv_semaphore_impl *impl = &semaphore->permanent;
+
+      /* Under most circumstances, out fences won't be temporary.  However,
+       * the spec does allow it for opaque_fd.  From the Vulkan 1.0.53 spec:
+       *
+       *    "If the import is temporary, the implementation must restore the
+       *    semaphore to its prior permanent state after submitting the next
+       *    semaphore wait operation."
+       *
+       * The spec says nothing whatsoever about signal operations on
+       * temporarily imported semaphores so it appears they are allowed.
+       * There are also CTS tests that require this to work.
+       */
+      struct anv_semaphore_impl *impl =
+         semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
+         &semaphore->temporary : &semaphore->permanent;
 
       switch (impl->type) {
       case ANV_SEMAPHORE_TYPE_BO:
@@ -1440,6 +1453,20 @@ anv_cmd_buffer_execbuf(struct anv_device *device,
 
    result = anv_device_execbuf(device, &execbuf.execbuf, execbuf.bos);
 
+   for (uint32_t i = 0; i < num_in_semaphores; i++) {
+      ANV_FROM_HANDLE(anv_semaphore, semaphore, in_semaphores[i]);
+      /* From the Vulkan 1.0.53 spec:
+       *
+       *    "If the import is temporary, the implementation must restore the
+       *    semaphore to its prior permanent state after submitting the next
+       *    semaphore wait operation."
+       *
+       * This has to happen after the execbuf in case we close any syncobjs in
+       * the process.
+       */
+      anv_semaphore_reset_temporary(device, semaphore);
+   }
+
    anv_execbuf_finish(&execbuf, &device->alloc);
 
    return result;
diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py
index ae22249..00186bc 100644
--- a/src/intel/vulkan/anv_extensions.py
+++ b/src/intel/vulkan/anv_extensions.py
@@ -50,6 +50,9 @@ EXTENSIONS = [
     Extension('VK_KHR_external_memory',                   1, True),
     Extension('VK_KHR_external_memory_capabilities',      1, True),
     Extension('VK_KHR_external_memory_fd',                1, True),
+    Extension('VK_KHR_external_semaphore',                1, False),
+    Extension('VK_KHR_external_semaphore_capabilities',   1, False),
+    Extension('VK_KHR_external_semaphore_fd',             1, False),
     Extension('VK_KHR_get_memory_requirements2',          1, True),
     Extension('VK_KHR_get_physical_device_properties2',   1, True),
     Extension('VK_KHR_get_surface_capabilities2',         1, True),
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
index c364491..b599db3 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -1765,6 +1765,9 @@ struct anv_semaphore {
    struct anv_semaphore_impl temporary;
 };
 
+void anv_semaphore_reset_temporary(struct anv_device *device,
+                                   struct anv_semaphore *semaphore);
+
 struct anv_shader_module {
    unsigned char                                sha1[20];
    uint32_t                                     size;
diff --git a/src/intel/vulkan/anv_queue.c b/src/intel/vulkan/anv_queue.c
index 2c10e9d..446c3de 100644
--- a/src/intel/vulkan/anv_queue.c
+++ b/src/intel/vulkan/anv_queue.c
@@ -528,11 +528,38 @@ VkResult anv_CreateSemaphore(
    if (semaphore == NULL)
       return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
 
-   /* 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;
+   const VkExportSemaphoreCreateInfoKHR *export =
+      vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO_KHR);
+    VkExternalSemaphoreHandleTypeFlagsKHR handleTypes =
+      export ? export->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_KHR) {
+      assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR);
+
+      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.
+       */
+      assert(!(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_KHR);
+   }
+
    semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
 
    *pSemaphore = anv_semaphore_to_handle(semaphore);
@@ -558,6 +585,17 @@ anv_semaphore_impl_cleanup(struct anv_device *device,
    unreachable("Invalid semaphore type");
 }
 
+void
+anv_semaphore_reset_temporary(struct anv_device *device,
+                              struct anv_semaphore *semaphore)
+{
+   if (semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE)
+      return;
+
+   anv_semaphore_impl_cleanup(device, &semaphore->temporary);
+   semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
+}
+
 void anv_DestroySemaphore(
     VkDevice                                    _device,
     VkSemaphore                                 _semaphore,
@@ -574,3 +612,109 @@ void anv_DestroySemaphore(
 
    vk_free2(&device->alloc, pAllocator, semaphore);
 }
+
+void anv_GetPhysicalDeviceExternalSemaphorePropertiesKHR(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceExternalSemaphoreInfoKHR* pExternalSemaphoreInfo,
+    VkExternalSemaphorePropertiesKHR*           pExternalSemaphoreProperties)
+{
+   switch (pExternalSemaphoreInfo->handleType) {
+   case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR:
+      pExternalSemaphoreProperties->exportFromImportedHandleTypes =
+         VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+      pExternalSemaphoreProperties->compatibleHandleTypes =
+         VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+      pExternalSemaphoreProperties->externalSemaphoreFeatures =
+         VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR |
+         VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR;
+      break;
+
+   default:
+      pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
+      pExternalSemaphoreProperties->compatibleHandleTypes = 0;
+      pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
+   }
+}
+
+VkResult anv_ImportSemaphoreFdKHR(
+    VkDevice                                    _device,
+    const VkImportSemaphoreFdInfoKHR*           pImportSemaphoreFdInfo)
+{
+   ANV_FROM_HANDLE(anv_device, device, _device);
+   ANV_FROM_HANDLE(anv_semaphore, semaphore, pImportSemaphoreFdInfo->semaphore);
+
+   struct anv_semaphore_impl new_impl = {
+      .type = ANV_SEMAPHORE_TYPE_NONE,
+   };
+
+   switch (pImportSemaphoreFdInfo->handleType) {
+   case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR: {
+      new_impl.type = ANV_SEMAPHORE_TYPE_BO;
+
+      VkResult result = anv_bo_cache_import(device, &device->bo_cache,
+                                            pImportSemaphoreFdInfo->fd, 4096,
+                                            &new_impl.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.
+       */
+      assert(!(new_impl.bo->flags & EXEC_OBJECT_ASYNC));
+
+      break;
+   }
+
+   default:
+      return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
+   }
+
+   if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR) {
+      anv_semaphore_impl_cleanup(device, &semaphore->temporary);
+      semaphore->temporary = new_impl;
+   } else {
+      anv_semaphore_impl_cleanup(device, &semaphore->permanent);
+      semaphore->permanent = new_impl;
+   }
+
+   return VK_SUCCESS;
+}
+
+VkResult anv_GetSemaphoreFdKHR(
+    VkDevice                                    _device,
+    const VkSemaphoreGetFdInfoKHR*              pGetFdInfo,
+    int*                                        pFd)
+{
+   ANV_FROM_HANDLE(anv_device, device, _device);
+   ANV_FROM_HANDLE(anv_semaphore, semaphore, pGetFdInfo->semaphore);
+   VkResult result;
+
+   assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR);
+
+   struct anv_semaphore_impl *impl =
+      semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
+      &semaphore->temporary : &semaphore->permanent;
+
+   switch (impl->type) {
+   case ANV_SEMAPHORE_TYPE_BO:
+      result = anv_bo_cache_export(device, &device->bo_cache, impl->bo, pFd);
+      if (result != VK_SUCCESS)
+         return result;
+      break;
+
+   default:
+      return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
+   }
+
+   /* From the Vulkan 1.0.53 spec:
+    *
+    *    "Export operations have the same transference as the specified handle
+    *    type’s import operations. [...] If the semaphore was using a
+    *    temporarily imported payload, the semaphore’s prior permanent payload
+    *    will be restored.
+    */
+   if (impl == &semaphore->temporary)
+      anv_semaphore_impl_cleanup(device, impl);
+
+   return VK_SUCCESS;
+}
-- 
2.5.0.400.gff86faf



More information about the mesa-dev mailing list