[Mesa-dev] [RFC 21/21] anv: Use DRM sync objects for external semaphores when available
Jason Ekstrand
jason at jlekstrand.net
Fri Apr 14 17:38:08 UTC 2017
---
src/intel/vulkan/anv_batch_chain.c | 69 ++++++++++++++++++++++++++++
src/intel/vulkan/anv_device.c | 2 +
src/intel/vulkan/anv_private.h | 8 ++++
src/intel/vulkan/anv_queue.c | 93 ++++++++++++++++++++++++++++----------
4 files changed, 148 insertions(+), 24 deletions(-)
diff --git a/src/intel/vulkan/anv_batch_chain.c b/src/intel/vulkan/anv_batch_chain.c
index ec37c81..0f118c8 100644
--- a/src/intel/vulkan/anv_batch_chain.c
+++ b/src/intel/vulkan/anv_batch_chain.c
@@ -953,6 +953,19 @@ anv_cmd_buffer_add_secondary(struct anv_cmd_buffer *primary,
&secondary->surface_relocs, 0);
}
+struct drm_i915_gem_exec_fence {
+ /**
+ * User's handle for a dma-fence to wait on or signal.
+ */
+ __u32 handle;
+
+#define I915_EXEC_FENCE_WAIT (1<<0)
+#define I915_EXEC_FENCE_SIGNAL (1<<1)
+ __u32 flags;
+};
+
+#define I915_EXEC_FENCE_ARRAY (1<<19)
+
struct anv_execbuf {
struct drm_i915_gem_execbuffer2 execbuf;
@@ -962,6 +975,10 @@ struct anv_execbuf {
/* Allocated length of the 'objects' and 'bos' arrays */
uint32_t array_length;
+
+ uint32_t fence_count;
+ uint32_t fence_array_length;
+ struct drm_i915_gem_exec_fence * fences;
};
static void
@@ -976,6 +993,7 @@ anv_execbuf_finish(struct anv_execbuf *exec,
{
vk_free(alloc, exec->objects);
vk_free(alloc, exec->bos);
+ vk_free(alloc, exec->fences);
}
static VkResult
@@ -1061,6 +1079,35 @@ anv_execbuf_add_bo(struct anv_execbuf *exec,
return VK_SUCCESS;
}
+static VkResult
+anv_execbuf_add_syncobj(struct anv_execbuf *exec,
+ uint32_t handle,
+ uint32_t flags,
+ const VkAllocationCallbacks *alloc)
+{
+ if (exec->fence_count >= exec->fence_array_length) {
+ uint32_t new_len = MAX2(exec->fence_array_length * 2, 64);
+
+ struct drm_i915_gem_exec_fence *new_fences =
+ vk_realloc(alloc, exec->fences, new_len * sizeof(*new_fences),
+ 8, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+ if (new_fences == NULL)
+ return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ exec->fences = new_fences;
+ exec->fence_array_length = new_len;
+ }
+
+ exec->fences[exec->fence_count] = (struct drm_i915_gem_exec_fence) {
+ .handle = handle,
+ .flags = flags,
+ };
+
+ exec->fence_count++;
+
+ return VK_SUCCESS;
+}
+
static void
anv_cmd_buffer_process_relocs(struct anv_cmd_buffer *cmd_buffer,
struct anv_reloc_list *list)
@@ -1447,6 +1494,14 @@ anv_cmd_buffer_execbuf(struct anv_device *device,
impl->fd = -1;
break;
+ case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
+ result = anv_execbuf_add_syncobj(&execbuf, impl->syncobj,
+ I915_EXEC_FENCE_WAIT,
+ &device->alloc);
+ if (result != VK_SUCCESS)
+ return result;
+ break;
+
default:
break;
}
@@ -1481,6 +1536,14 @@ anv_cmd_buffer_execbuf(struct anv_device *device,
need_out_fence = true;
break;
+ case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
+ result = anv_execbuf_add_syncobj(&execbuf, impl->syncobj,
+ I915_EXEC_FENCE_SIGNAL,
+ &device->alloc);
+ if (result != VK_SUCCESS)
+ return result;
+ break;
+
default:
break;
}
@@ -1494,6 +1557,12 @@ anv_cmd_buffer_execbuf(struct anv_device *device,
setup_empty_execbuf(&execbuf, device);
}
+ if (execbuf.fence_count > 0) {
+ execbuf.execbuf.flags |= I915_EXEC_FENCE_ARRAY;
+ execbuf.execbuf.num_cliprects = execbuf.fence_count;
+ execbuf.execbuf.cliprects_ptr = (uintptr_t) execbuf.fences;
+ }
+
if (in_fence != -1) {
execbuf.execbuf.flags |= I915_EXEC_FENCE_IN;
execbuf.execbuf.rsvd2 |= (uint32_t)in_fence;
diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
index f853905..13d01d1 100644
--- a/src/intel/vulkan/anv_device.c
+++ b/src/intel/vulkan/anv_device.c
@@ -233,6 +233,8 @@ anv_physical_device_init(struct anv_physical_device *device,
device->has_exec_async = anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_ASYNC);
device->has_exec_fence = anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_FENCE);
+ device->has_syncobj =
+ anv_gem_get_param(fd, 47 /* I915_PARAM_HAS_EXEC_FENCE_ARRAY */);
bool swizzled = anv_gem_get_bit6_swizzle(fd, I915_TILING_X);
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
index d1406ab..0731e89 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -648,6 +648,7 @@ struct anv_physical_device {
int cmd_parser_version;
bool has_exec_async;
bool has_exec_fence;
+ bool has_syncobj;
uint32_t eu_total;
uint32_t subslice_total;
@@ -1724,6 +1725,7 @@ enum anv_semaphore_type {
ANV_SEMAPHORE_TYPE_DUMMY,
ANV_SEMAPHORE_TYPE_BO,
ANV_SEMAPHORE_TYPE_SYNC_FILE,
+ ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ,
};
struct anv_semaphore_impl {
@@ -1742,6 +1744,12 @@ struct anv_semaphore_impl {
* created or because it has been used for a wait, fd will be -1.
*/
int fd;
+
+ /* Sync object handle when type == AKV_SEMAPHORE_TYPE_DRM_SYNCOBJ.
+ * Unlike GEM BOs, DRM sync objects aren't deduplicated by the kernel on
+ * import so we don't need to bother with a userspace cache.
+ */
+ uint32_t syncobj;
};
};
diff --git a/src/intel/vulkan/anv_queue.c b/src/intel/vulkan/anv_queue.c
index e7c8ef5..c7c527f 100644
--- a/src/intel/vulkan/anv_queue.c
+++ b/src/intel/vulkan/anv_queue.c
@@ -558,19 +558,28 @@ VkResult anv_CreateSemaphore(
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);
+ if (device->instance->physicalDevice.has_syncobj) {
+ semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
+ semaphore->permanent.syncobj = anv_gem_syncobj_create(device);
+ if (!semaphore->permanent.syncobj) {
+ vk_free2(&device->alloc, pAllocator, semaphore);
+ return vk_errorf(VK_ERROR_TOO_MANY_OBJECTS,
+ "drm_syncobj_create failed: %m");
+ }
+ } else {
+ 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;
+ }
- 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;
}
-
- /* 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 if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX) {
assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX);
@@ -607,6 +616,10 @@ anv_semaphore_impl_cleanup(struct anv_device *device,
close(impl->fd);
break;
+ case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
+ anv_gem_syncobj_close(device, impl->syncobj);
+ break;
+
default:
unreachable("Invalid semaphore type");
}
@@ -676,22 +689,45 @@ VkResult anv_ImportSemaphoreFdKHX(
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 (device->instance->physicalDevice.has_syncobj) {
+ uint32_t handle =
+ anv_gem_syncobj_fd_to_handle(device, pImportSemaphoreFdInfo->fd);
+ if (!handle) {
+ return vk_errorf(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX,
+ "drm_syncobj_fd_to_handle failed: %m");
+ }
- /* 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;
+ /* From the Vulkan spec:
+ *
+ * "Importing semaphore state from a file descriptor transfers
+ * ownership of the file descriptor from the application to the
+ * Vulkan implementation. The application must not perform any
+ * operations on the file descriptor after a successful import."
+ *
+ * If the import fails, we leave the file descriptor open.
+ */
+ close(pImportSemaphoreFdInfo->fd);
- anv_semaphore_impl_cleanup(device, &semaphore->permanent);
+ semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
+ semaphore->permanent.syncobj = handle;
+ } else {
+ struct anv_bo *bo;
+ VkResult result = anv_bo_cache_import(device, &device->bo_cache,
+ pImportSemaphoreFdInfo->fd, 4096,
+ &bo);
+ if (result != VK_SUCCESS)
+ return result;
- semaphore->permanent.type = ANV_SEMAPHORE_TYPE_BO;
- semaphore->permanent.bo = bo;
+ /* 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;
}
@@ -717,6 +753,7 @@ VkResult anv_GetSemaphoreFdKHX(
{
ANV_FROM_HANDLE(anv_device, device, _device);
ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
+ int fd;
switch (semaphore->permanent.type) {
case ANV_SEMAPHORE_TYPE_BO:
@@ -740,6 +777,14 @@ VkResult anv_GetSemaphoreFdKHX(
semaphore->permanent.fd = -1;
return VK_SUCCESS;
+ case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
+ fd = anv_gem_syncobj_handle_to_fd(device, semaphore->permanent.syncobj);
+ if (fd < 0)
+ return vk_errorf(VK_ERROR_TOO_MANY_OBJECTS,
+ "drm_syncobj_handle_to_fd failed: %m");
+ *pFd = fd;
+ return VK_SUCCESS;
+
default:
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX);
}
--
2.5.0.400.gff86faf
More information about the mesa-dev
mailing list