[Mesa-dev] [PATCH 9/9] anv: Implement support for exporting semaphores as FENCE_FD

Jason Ekstrand jason at jlekstrand.net
Tue Feb 28 16:56:47 UTC 2017


---
 src/intel/vulkan/anv_batch_chain.c | 91 ++++++++++++++++++++++++++++++++++++--
 src/intel/vulkan/anv_device.c      | 26 +++++++++++
 src/intel/vulkan/anv_gem.c         | 36 +++++++++++++++
 src/intel/vulkan/anv_private.h     |  9 +++-
 src/intel/vulkan/anv_queue.c       | 68 +++++++++++++++++++++++++---
 5 files changed, 220 insertions(+), 10 deletions(-)

diff --git a/src/intel/vulkan/anv_batch_chain.c b/src/intel/vulkan/anv_batch_chain.c
index 3640588..004594a 100644
--- a/src/intel/vulkan/anv_batch_chain.c
+++ b/src/intel/vulkan/anv_batch_chain.c
@@ -1352,6 +1352,28 @@ setup_execbuf_for_cmd_buffer(struct anv_execbuf *execbuf,
    }
 }
 
+static void
+setup_empty_execbuf(struct anv_execbuf *execbuf, struct anv_device *device)
+{
+   anv_execbuf_add_bo(execbuf, &device->trivial_batch_bo, NULL, 0,
+                      &device->alloc);
+
+   execbuf->execbuf = (struct drm_i915_gem_execbuffer2) {
+      .buffers_ptr = (uintptr_t) execbuf->objects,
+      .buffer_count = execbuf->bo_count,
+      .batch_start_offset = 0,
+      .batch_len = 8, /* GEN8_MI_BATCH_BUFFER_END and NOOP */
+      .cliprects_ptr = 0,
+      .num_cliprects = 0,
+      .DR1 = 0,
+      .DR4 = 0,
+      .flags = I915_EXEC_HANDLE_LUT | I915_EXEC_RENDER |
+               I915_EXEC_CONSTANTS_REL_GENERAL,
+      .rsvd1 = device->context_id,
+      .rsvd2 = 0,
+   };
+}
+
 VkResult
 anv_cmd_buffer_execbuf(struct anv_device *device,
                        struct anv_cmd_buffer *cmd_buffer,
@@ -1363,22 +1385,50 @@ anv_cmd_buffer_execbuf(struct anv_device *device,
    struct anv_execbuf execbuf;
    anv_execbuf_init(&execbuf);
 
+   int in_fence = -1;
    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:
          anv_execbuf_add_bo(&execbuf, &impl->bo, NULL, 0, &device->alloc);
          break;
+      case ANV_SEMAPHORE_TYPE_SYNC_FILE:
+         if (in_fence == -1) {
+            in_fence = impl->fd;
+         } else {
+            int merge = anv_gem_sync_file_merge(device, in_fence, impl->fd);
+            if (merge == -1)
+               return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX);
+
+            close(impl->fd);
+            close(in_fence);
+            in_fence = merge;
+         }
+
+         impl->fd = -1;
       default:
          break;
       }
+
+      /* Waiting on a semaphore with temporary state implicitly resets it back
+       * to the permanent state.
+       */
+      if (semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE) {
+         assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_SYNC_FILE);
+         semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
+      }
    }
 
+   bool need_out_fence = false;
    for (uint32_t i = 0; i < num_out_semaphores; i++) {
       ANV_FROM_HANDLE(anv_semaphore, semaphore, out_semaphores[i]);
+      /* Out fences can't have temporary state because that would imply
+       * that we imported a sync file and are trying to signal it.
+       */
       assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE);
       struct anv_semaphore_impl *impl = &semaphore->permanent;
 
@@ -1387,15 +1437,50 @@ anv_cmd_buffer_execbuf(struct anv_device *device,
          anv_execbuf_add_bo(&execbuf, &impl->bo, NULL, EXEC_OBJECT_WRITE,
                             &device->alloc);
          break;
+
+      case ANV_SEMAPHORE_TYPE_SYNC_FILE:
+         need_out_fence = true;
+         break;
+
       default:
          break;
       }
    }
 
-   setup_execbuf_for_cmd_buffer(&execbuf, cmd_buffer);
+   if (cmd_buffer) {
+      setup_execbuf_for_cmd_buffer(&execbuf, cmd_buffer);
+   } else {
+      setup_empty_execbuf(&execbuf, device);
+   }
+
+   if (in_fence != -1) {
+      execbuf.execbuf.flags |= I915_EXEC_FENCE_IN;
+      execbuf.execbuf.rsvd2 |= (uint32_t)in_fence;
+   }
+
+   if (need_out_fence)
+      execbuf.execbuf.flags |= I915_EXEC_FENCE_OUT;
 
    VkResult result = anv_device_execbuf(device, &execbuf.execbuf, execbuf.bos);
 
+   if (need_out_fence) {
+      int out_fence = execbuf.execbuf.rsvd2 >> 32;
+      for (uint32_t i = 0; i < num_out_semaphores; i++) {
+         ANV_FROM_HANDLE(anv_semaphore, semaphore, out_semaphores[i]);
+         /* Out fences can't have temporary state because that would imply
+          * that we imported a sync file and are trying to signal it.
+          */
+         assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE);
+         struct anv_semaphore_impl *impl = &semaphore->permanent;
+
+         if (impl->type == ANV_SEMAPHORE_TYPE_SYNC_FILE) {
+            assert(impl->fd == -1);
+            impl->fd = dup(out_fence);
+         }
+      }
+      close(out_fence);
+   }
+
    anv_execbuf_finish(&execbuf, &device->alloc);
 
    return result;
diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
index 323e17a..5ac3c5d 100644
--- a/src/intel/vulkan/anv_device.c
+++ b/src/intel/vulkan/anv_device.c
@@ -190,6 +190,8 @@ anv_physical_device_init(struct anv_physical_device *device,
       goto fail;
    }
 
+   device->has_exec_fence = anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_FENCE);
+
    bool swizzled = anv_gem_get_bit6_swizzle(fd, I915_TILING_X);
 
    /* GENs prior to 8 do not support EU/Subslice info */
@@ -969,6 +971,26 @@ anv_device_init_border_colors(struct anv_device *device)
                                                     border_colors);
 }
 
+static void
+anv_device_init_trivial_batch(struct anv_device *device)
+{
+   anv_bo_init_new(&device->trivial_batch_bo, device, 4096);
+   void *map = anv_gem_mmap(device, device->trivial_batch_bo.gem_handle,
+                            0, 4096, 0);
+
+   struct anv_batch batch;
+   batch.start = batch.next = map;
+   batch.end = map + 4096;
+
+   anv_batch_emit(&batch, GEN7_MI_BATCH_BUFFER_END, bbe);
+   anv_batch_emit(&batch, GEN7_MI_NOOP, noop);
+
+   if (!device->info.has_llc)
+      anv_clflush_range(map, batch.next - map);
+
+   anv_gem_munmap(map, device->trivial_batch_bo.size);
+}
+
 VkResult anv_CreateDevice(
     VkPhysicalDevice                            physicalDevice,
     const VkDeviceCreateInfo*                   pCreateInfo,
@@ -1061,6 +1083,8 @@ VkResult anv_CreateDevice(
 
    anv_bo_init_new(&device->workaround_bo, device, 1024);
 
+   anv_device_init_trivial_batch(device);
+
    anv_scratch_pool_init(device, &device->scratch_pool);
 
    anv_queue_init(device, &device->queue);
@@ -1124,6 +1148,8 @@ void anv_DestroyDevice(
    anv_gem_munmap(device->workaround_bo.map, device->workaround_bo.size);
    anv_gem_close(device, device->workaround_bo.gem_handle);
 
+   anv_gem_close(device, device->trivial_batch_bo.gem_handle);
+
    anv_state_pool_finish(&device->surface_state_pool);
    anv_block_pool_finish(&device->surface_state_block_pool);
    anv_state_pool_finish(&device->instruction_state_pool);
diff --git a/src/intel/vulkan/anv_gem.c b/src/intel/vulkan/anv_gem.c
index d8beab1..a26ea7c 100644
--- a/src/intel/vulkan/anv_gem.c
+++ b/src/intel/vulkan/anv_gem.c
@@ -22,6 +22,7 @@
  */
 
 #include <sys/ioctl.h>
+#include <sys/types.h>
 #include <sys/mman.h>
 #include <string.h>
 #include <errno.h>
@@ -332,3 +333,38 @@ anv_gem_fd_to_handle(struct anv_device *device, int fd)
 
    return args.handle;
 }
+
+#ifndef SYNC_IOC_MAGIC
+/* duplicated from linux/sync_file.h to avoid build-time depnedency
+ * on new (v4.7) kernel headers.  Once distro's are mostly using
+ * something newer than v4.7 drop this and #include <linux/sync_file.h>
+ * instead.
+ */
+struct sync_merge_data {
+   char  name[32];
+   __s32 fd2;
+   __s32 fence;
+   __u32 flags;
+   __u32 pad;
+};
+
+#define SYNC_IOC_MAGIC '>'
+#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data)
+#endif
+
+int
+anv_gem_sync_file_merge(struct anv_device *device, int fd1, int fd2)
+{
+   const char name[] = "anv merge fence";
+   struct sync_merge_data args = {
+      .fd2 = fd2,
+      .fence = -1,
+   };
+   memcpy(args.name, name, sizeof(name));
+
+   int ret = anv_ioctl(device->fd, SYNC_IOC_MERGE, &args);
+   if (ret == -1)
+      return -1;
+
+   return args.fence;
+}
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
index 8763cbb..5c374d8 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -526,6 +526,7 @@ struct anv_physical_device {
     struct brw_compiler *                       compiler;
     struct isl_device                           isl_dev;
     int                                         cmd_parser_version;
+    bool                                        has_exec_fence;
 
     uint32_t                                    eu_total;
     uint32_t                                    subslice_total;
@@ -610,6 +611,7 @@ struct anv_device {
     struct anv_state_pool                       surface_state_pool;
 
     struct anv_bo                               workaround_bo;
+    struct anv_bo                               trivial_batch_bo;
 
     struct anv_pipeline_cache                   blorp_shader_cache;
     struct blorp_context                        blorp;
@@ -663,6 +665,7 @@ uint32_t anv_gem_fd_to_handle(struct anv_device *device, int fd);
 int anv_gem_set_caching(struct anv_device *device, uint32_t gem_handle, uint32_t caching);
 int anv_gem_set_domain(struct anv_device *device, uint32_t gem_handle,
                        uint32_t read_domains, uint32_t write_domain);
+int anv_gem_sync_file_merge(struct anv_device *device, int fd1, int fd2);
 
 VkResult anv_bo_init_new(struct anv_bo *bo, struct anv_device *device, uint64_t size);
 
@@ -1373,12 +1376,16 @@ enum anv_semaphore_type {
    ANV_SEMAPHORE_TYPE_NONE = 0,
    ANV_SEMAPHORE_TYPE_DUMMY,
    ANV_SEMAPHORE_TYPE_BO,
+   ANV_SEMAPHORE_TYPE_SYNC_FILE,
 };
 
 struct anv_semaphore_impl {
    enum anv_semaphore_type type;
 
-   struct anv_bo bo;
+   union {
+      struct anv_bo bo;
+      int fd;
+   };
 };
 
 struct anv_semaphore {
diff --git a/src/intel/vulkan/anv_queue.c b/src/intel/vulkan/anv_queue.c
index 656ab1a..6bd1435 100644
--- a/src/intel/vulkan/anv_queue.c
+++ b/src/intel/vulkan/anv_queue.c
@@ -156,6 +156,23 @@ VkResult anv_QueueSubmit(
    pthread_mutex_lock(&device->mutex);
 
    for (uint32_t i = 0; i < submitCount; i++) {
+      if (pSubmits[i].commandBufferCount == 0) {
+         /* If we don't have any command buffers, we need to submit a dummy
+          * batch to give GEM something to wait on.  We could, potentially,
+          * come up with something more efficient but this shouldn't be a
+          * common case.
+          */
+         result = anv_cmd_buffer_execbuf(device, NULL,
+                                         pSubmits[i].pWaitSemaphores,
+                                         pSubmits[i].waitSemaphoreCount,
+                                         pSubmits[i].pSignalSemaphores,
+                                         pSubmits[i].signalSemaphoreCount);
+         if (result != VK_SUCCESS)
+            goto out;
+
+         continue;
+      }
+
       for (uint32_t j = 0; j < pSubmits[i].commandBufferCount; j++) {
          ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer,
                          pSubmits[i].pCommandBuffers[j]);
@@ -503,6 +520,11 @@ VkResult anv_CreateSemaphore(
          vk_free2(&device->alloc, pAllocator, semaphore);
          return result;
       }
+   } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX) {
+      assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX);
+
+      semaphore->permanent.type = ANV_SEMAPHORE_TYPE_SYNC_FILE;
+      semaphore->permanent.fd = -1;
    } else {
       assert(!"Unknown handle type");
       vk_free2(&device->alloc, pAllocator, semaphore);
@@ -530,6 +552,10 @@ anv_semaphore_impl_cleanup(struct anv_device *device,
       anv_gem_close(device, impl->bo.gem_handle);
       break;
 
+   case ANV_SEMAPHORE_TYPE_SYNC_FILE:
+      close(impl->fd);
+      break;
+
    default:
       unreachable("Invalid semaphore type");
    }
@@ -554,6 +580,8 @@ void anv_GetPhysicalDeviceExternalSemaphorePropertiesKHX(
     const VkPhysicalDeviceExternalSemaphoreInfoKHX* pExternalSemaphoreInfo,
     VkExternalSemaphorePropertiesKHX*           pExternalSemaphoreProperties)
 {
+   ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
+
    switch (pExternalSemaphoreInfo->handleType) {
    case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHX:
       pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
@@ -562,13 +590,27 @@ void anv_GetPhysicalDeviceExternalSemaphorePropertiesKHX(
       pExternalSemaphoreProperties->externalSemaphoreFeatures =
          VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHX |
          VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHX;
+      return;
+
+   case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX:
+      if (device->has_exec_fence) {
+         pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
+         pExternalSemaphoreProperties->compatibleHandleTypes =
+            VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX;
+         pExternalSemaphoreProperties->externalSemaphoreFeatures =
+            VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHX |
+            VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHX;
+         return;
+      }
       break;
 
    default:
-      pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
-      pExternalSemaphoreProperties->compatibleHandleTypes = 0;
-      pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
+      break;
    }
+
+   pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
+   pExternalSemaphoreProperties->compatibleHandleTypes = 0;
+   pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
 }
 
 VkResult anv_ImportSemaphoreFdKHX(
@@ -596,12 +638,21 @@ VkResult anv_ImportSemaphoreFdKHX(
        */
       close(pImportSemaphoreFdInfo->fd);
 
-      anv_semaphore_impl_cleanup(device, &semaphore->permanent);
-      semaphore->permanent.type = ANV_SEMAPHORE_TYPE_BO;
-      anv_bo_init(&semaphore->permanent.bo, gem_handle, 4096);
+      if (semaphore->permanent.type != ANV_SEMAPHORE_TYPE_BO ||
+          semaphore->permanent.bo.gem_handle != gem_handle) {
+         anv_semaphore_impl_cleanup(device, &semaphore->permanent);
+         semaphore->permanent.type = ANV_SEMAPHORE_TYPE_BO;
+         anv_bo_init(&semaphore->permanent.bo, gem_handle, 4096);
+      }
       return VK_SUCCESS;
    }
 
+   case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX:
+      anv_semaphore_impl_cleanup(device, &semaphore->temporary);
+      semaphore->temporary.type = ANV_SEMAPHORE_TYPE_SYNC_FILE;
+      semaphore->temporary.fd = pImportSemaphoreFdInfo->fd;
+      return VK_SUCCESS;
+
    default:
       return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX);
    }
@@ -624,6 +675,11 @@ VkResult anv_GetSemaphoreFdKHX(
          return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
       break;
 
+   case ANV_SEMAPHORE_TYPE_SYNC_FILE:
+      fd = semaphore->permanent.fd;
+      semaphore->permanent.fd = -1;
+      break;
+
    default:
       return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX);
    }
-- 
2.5.0.400.gff86faf



More information about the mesa-dev mailing list