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

Jason Ekstrand jason at jlekstrand.net
Fri Apr 14 17:38:03 UTC 2017


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(-)

diff --git a/src/intel/vulkan/anv_batch_chain.c b/src/intel/vulkan/anv_batch_chain.c
index 136f273..0529f22 100644
--- a/src/intel/vulkan/anv_batch_chain.c
+++ b/src/intel/vulkan/anv_batch_chain.c
@@ -982,6 +982,7 @@ static VkResult
 anv_execbuf_add_bo(struct anv_execbuf *exec,
                    struct anv_bo *bo,
                    struct anv_reloc_list *relocs,
+                   uint32_t extra_flags,
                    const VkAllocationCallbacks *alloc)
 {
    struct drm_i915_gem_exec_object2 *obj = NULL;
@@ -1036,7 +1037,7 @@ anv_execbuf_add_bo(struct anv_execbuf *exec,
       obj->relocs_ptr = 0;
       obj->alignment = 0;
       obj->offset = bo->offset;
-      obj->flags = bo->flags;
+      obj->flags = bo->flags | extra_flags;
       obj->rsvd1 = 0;
       obj->rsvd2 = 0;
    }
@@ -1052,7 +1053,8 @@ anv_execbuf_add_bo(struct anv_execbuf *exec,
       for (size_t i = 0; i < relocs->num_relocs; i++) {
          /* A quick sanity check on relocations */
          assert(relocs->relocs[i].offset < bo->size);
-         anv_execbuf_add_bo(exec, relocs->reloc_bos[i], NULL, alloc);
+         anv_execbuf_add_bo(exec, relocs->reloc_bos[i], NULL,
+                            extra_flags, alloc);
       }
    }
 
@@ -1261,7 +1263,7 @@ setup_execbuf_for_cmd_buffer(struct anv_execbuf *execbuf,
    adjust_relocations_from_state_pool(ss_pool, &cmd_buffer->surface_relocs,
                                       cmd_buffer->last_ss_pool_center);
    VkResult result =
-      anv_execbuf_add_bo(execbuf, &ss_pool->bo, &cmd_buffer->surface_relocs,
+      anv_execbuf_add_bo(execbuf, &ss_pool->bo, &cmd_buffer->surface_relocs, 0,
                          &cmd_buffer->device->alloc);
    if (result != VK_SUCCESS)
       return result;
@@ -1274,7 +1276,7 @@ setup_execbuf_for_cmd_buffer(struct anv_execbuf *execbuf,
       adjust_relocations_to_state_pool(ss_pool, &(*bbo)->bo, &(*bbo)->relocs,
                                        cmd_buffer->last_ss_pool_center);
 
-      result = anv_execbuf_add_bo(execbuf, &(*bbo)->bo, &(*bbo)->relocs,
+      result = anv_execbuf_add_bo(execbuf, &(*bbo)->bo, &(*bbo)->relocs, 0,
                                   &cmd_buffer->device->alloc);
       if (result != VK_SUCCESS)
          return result;
@@ -1387,12 +1389,51 @@ setup_execbuf_for_cmd_buffer(struct anv_execbuf *execbuf,
 
 VkResult
 anv_cmd_buffer_execbuf(struct anv_device *device,
-                       struct anv_cmd_buffer *cmd_buffer)
+                       struct anv_cmd_buffer *cmd_buffer,
+                       const VkSemaphore *in_semaphores,
+                       uint32_t num_in_semaphores,
+                       const VkSemaphore *out_semaphores,
+                       uint32_t num_out_semaphores)
 {
    struct anv_execbuf execbuf;
    anv_execbuf_init(&execbuf);
 
-   VkResult result = setup_execbuf_for_cmd_buffer(&execbuf, cmd_buffer);
+   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;
+
+      switch (impl->type) {
+      case ANV_SEMAPHORE_TYPE_BO:
+         result = anv_execbuf_add_bo(&execbuf, impl->bo, NULL,
+                                     0, &device->alloc);
+         if (result != VK_SUCCESS)
+            return result;
+         break;
+      default:
+         break;
+      }
+   }
+
+   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;
+
+      switch (impl->type) {
+      case ANV_SEMAPHORE_TYPE_BO:
+         result = anv_execbuf_add_bo(&execbuf, impl->bo, NULL,
+                                     EXEC_OBJECT_WRITE, &device->alloc);
+         if (result != VK_SUCCESS)
+            return result;
+         break;
+      default:
+         break;
+      }
+   }
+
+   result = setup_execbuf_for_cmd_buffer(&execbuf, cmd_buffer);
    if (result != VK_SUCCESS)
       return result;
 
diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
index b85cd40..f6e77ab 100644
--- a/src/intel/vulkan/anv_device.c
+++ b/src/intel/vulkan/anv_device.c
@@ -378,6 +378,10 @@ static const VkExtensionProperties device_extensions[] = {
       .extensionName = VK_KHX_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
       .specVersion = 1,
    },
+   {
+      .extensionName = VK_KHX_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
+      .specVersion = 1,
+   },
 };
 
 static void *
diff --git a/src/intel/vulkan/anv_entrypoints_gen.py b/src/intel/vulkan/anv_entrypoints_gen.py
index cfa9d68..728e10f 100644
--- a/src/intel/vulkan/anv_entrypoints_gen.py
+++ b/src/intel/vulkan/anv_entrypoints_gen.py
@@ -50,6 +50,7 @@ SUPPORTED_EXTENSIONS = [
     'VK_KHX_external_memory_fd',
     'VK_KHX_external_semaphore',
     'VK_KHX_external_semaphore_capabilities',
+    'VK_KHX_external_semaphore_fd',
 ]
 
 # We generate a static hash table for entry point lookup
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
index 5cbb0c5..4a59cac 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -1618,7 +1618,11 @@ void anv_cmd_buffer_add_secondary(struct anv_cmd_buffer *primary,
                                   struct anv_cmd_buffer *secondary);
 void anv_cmd_buffer_prepare_execbuf(struct anv_cmd_buffer *cmd_buffer);
 VkResult anv_cmd_buffer_execbuf(struct anv_device *device,
-                                struct anv_cmd_buffer *cmd_buffer);
+                                struct anv_cmd_buffer *cmd_buffer,
+                                const VkSemaphore *in_semaphores,
+                                uint32_t num_in_semaphores,
+                                const VkSemaphore *out_semaphores,
+                                uint32_t num_out_semaphores);
 
 VkResult anv_cmd_buffer_reset(struct anv_cmd_buffer *cmd_buffer);
 
@@ -1708,11 +1712,19 @@ struct anv_event {
 
 enum anv_semaphore_type {
    ANV_SEMAPHORE_TYPE_NONE = 0,
-   ANV_SEMAPHORE_TYPE_DUMMY
+   ANV_SEMAPHORE_TYPE_DUMMY,
+   ANV_SEMAPHORE_TYPE_BO,
 };
 
 struct anv_semaphore_impl {
    enum anv_semaphore_type type;
+
+   /* A BO representing this semaphore when type == ANV_SEMAPHORE_TYPE_BO.
+    * This BO will be added to the object list on any execbuf2 calls for
+    * which this semaphore is used as a wait or signal fence.  When used as
+    * a signal fence, the EXEC_OBJECT_WRITE flag will be set.
+    */
+   struct anv_bo *bo;
 };
 
 struct anv_semaphore {
diff --git a/src/intel/vulkan/anv_queue.c b/src/intel/vulkan/anv_queue.c
index 64c5900..980fd2d 100644
--- a/src/intel/vulkan/anv_queue.c
+++ b/src/intel/vulkan/anv_queue.c
@@ -25,6 +25,10 @@
  * This file implements VkQueue, VkFence, and VkSemaphore
  */
 
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/eventfd.h>
+
 #include "anv_private.h"
 #include "util/vk_util.h"
 
@@ -161,7 +165,23 @@ VkResult anv_QueueSubmit(
          assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY);
          assert(!anv_batch_has_error(&cmd_buffer->batch));
 
-         result = anv_cmd_buffer_execbuf(device, cmd_buffer);
+         const VkSemaphore *in_semaphores = NULL, *out_semaphores = NULL;
+         uint32_t num_in_semaphores = 0, num_out_semaphores = 0;
+         if (j == 0) {
+            /* Only the first batch gets the in semaphores */
+            in_semaphores = pSubmits[i].pWaitSemaphores;
+            num_in_semaphores = pSubmits[i].waitSemaphoreCount;
+         }
+
+         if (j == pSubmits[i].commandBufferCount - 1) {
+            /* Only the last batch gets the out semaphores */
+            out_semaphores = pSubmits[i].pSignalSemaphores;
+            num_out_semaphores = pSubmits[i].signalSemaphoreCount;
+         }
+
+         result = anv_cmd_buffer_execbuf(device, cmd_buffer,
+                                         in_semaphores, num_in_semaphores,
+                                         out_semaphores, num_out_semaphores);
          if (result != VK_SUCCESS)
             goto out;
       }
@@ -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 DRM execbuffer ioctl always execute in-oder, even between
-    * different rings. As such, a dummy no-op semaphore is a perfectly
-    * valid implementation.
-    */
-   semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DUMMY;
    semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
 
    *pSemaphore = anv_semaphore_to_handle(semaphore);
@@ -528,6 +567,25 @@ VkResult anv_CreateSemaphore(
    return VK_SUCCESS;
 }
 
+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");
+   }
+}
+
 void anv_DestroySemaphore(
     VkDevice                                    _device,
     VkSemaphore                                 _semaphore,
@@ -539,6 +597,9 @@ void anv_DestroySemaphore(
    if (semaphore == NULL)
       return;
 
+   anv_semaphore_impl_cleanup(device, &semaphore->temporary);
+   anv_semaphore_impl_cleanup(device, &semaphore->permanent);
+
    vk_free2(&device->alloc, pAllocator, semaphore);
 }
 
@@ -548,9 +609,73 @@ void anv_GetPhysicalDeviceExternalSemaphorePropertiesKHX(
     VkExternalSemaphorePropertiesKHX*           pExternalSemaphoreProperties)
 {
    switch (pExternalSemaphoreInfo->handleType) {
+   case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHX:
+      pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
+      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);
+   }
+}
+
+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);
+   }
+
+   return VK_SUCCESS;
+}
-- 
2.5.0.400.gff86faf



More information about the mesa-dev mailing list