anv: Add a basic implementation of VK_KHX_external_semaphore
authorJason Ekstrand <jason.ekstrand@intel.com>
Thu, 13 Jul 2017 22:14:31 +0000 (15:14 -0700)
committerJason Ekstrand <jason.ekstrand@intel.com>
Wed, 16 Aug 2017 02:08:26 +0000 (19:08 -0700)
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.

Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
src/intel/vulkan/anv_batch_chain.c
src/intel/vulkan/anv_extensions.py
src/intel/vulkan/anv_private.h
src/intel/vulkan/anv_queue.c

index ad76dc1fc0fee28a32e9cac18515150cc93e15a4..52ecfe890275e195248ff9b1cfe58030088e5e6d 100644 (file)
@@ -1402,8 +1402,9 @@ anv_cmd_buffer_execbuf(struct anv_device *device,
    VkResult result = VK_SUCCESS;
    for (uint32_t i = 0; i < num_in_semaphores; i++) {
       ANV_FROM_HANDLE(anv_semaphore, semaphore, in_semaphores[i]);
-      assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE);
-      struct anv_semaphore_impl *impl = &semaphore->permanent;
+      struct anv_semaphore_impl *impl =
+         semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
+         &semaphore->temporary : &semaphore->permanent;
 
       switch (impl->type) {
       case ANV_SEMAPHORE_TYPE_BO:
@@ -1419,8 +1420,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 +1454,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;
index ae222491b95aae356af13d08ae19159a2d06ecc8..00186bc2c665fb3e91bf14d11b551fe9c6a7110a 100644 (file)
@@ -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),
index c36449143280e1bab2a77f1d85ffdefe5fa2f364..b599db3b8016ec343c5e19bf3c489dacf99a4827 100644 (file)
@@ -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;
index 2c10e9d2f69604c24e68d57fea2af4e0cd4d5463..9a0789ca32264a02a360e89cc1943bc321f92f0d 100644 (file)
@@ -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);
+   int fd = pImportSemaphoreFdInfo->fd;
+
+   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,
+                                            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;
+}