[Mesa-dev] [PATCH 7/9] anv: Implement VK_KHX_external_semaphore_fd
Jason Ekstrand
jason at jlekstrand.net
Tue Feb 28 16:56:45 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 | 44 ++++++++--
src/intel/vulkan/anv_device.c | 4 +
src/intel/vulkan/anv_entrypoints_gen.py | 1 +
src/intel/vulkan/anv_private.h | 11 ++-
src/intel/vulkan/anv_queue.c | 142 ++++++++++++++++++++++++++++++--
5 files changed, 187 insertions(+), 15 deletions(-)
diff --git a/src/intel/vulkan/anv_batch_chain.c b/src/intel/vulkan/anv_batch_chain.c
index c55938a..3640588 100644
--- a/src/intel/vulkan/anv_batch_chain.c
+++ b/src/intel/vulkan/anv_batch_chain.c
@@ -955,6 +955,7 @@ static VkResult
anv_execbuf_add_bo(struct anv_execbuf *exec,
struct anv_bo *bo,
struct anv_reloc_list *relocs,
+ uint32_t flags,
const VkAllocationCallbacks *alloc)
{
struct drm_i915_gem_exec_object2 *obj = NULL;
@@ -1009,7 +1010,7 @@ anv_execbuf_add_bo(struct anv_execbuf *exec,
obj->relocs_ptr = 0;
obj->alignment = 0;
obj->offset = bo->offset;
- obj->flags = bo->is_winsys_bo ? EXEC_OBJECT_WRITE : 0;
+ obj->flags = flags | (bo->is_winsys_bo ? EXEC_OBJECT_WRITE : 0);
obj->rsvd1 = 0;
obj->rsvd2 = 0;
}
@@ -1025,7 +1026,7 @@ 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, flags, alloc);
}
}
@@ -1233,7 +1234,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);
- 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);
/* First, we walk over all of the bos we've seen and add them and their
@@ -1244,7 +1245,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);
- anv_execbuf_add_bo(execbuf, &(*bbo)->bo, &(*bbo)->relocs,
+ anv_execbuf_add_bo(execbuf, &(*bbo)->bo, &(*bbo)->relocs, 0,
&cmd_buffer->device->alloc);
}
@@ -1353,11 +1354,44 @@ 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);
+ 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:
+ anv_execbuf_add_bo(&execbuf, &impl->bo, NULL, 0, &device->alloc);
+ 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:
+ anv_execbuf_add_bo(&execbuf, &impl->bo, NULL, EXEC_OBJECT_WRITE,
+ &device->alloc);
+ break;
+ default:
+ break;
+ }
+ }
+
setup_execbuf_for_cmd_buffer(&execbuf, cmd_buffer);
VkResult result = anv_device_execbuf(device, &execbuf.execbuf, execbuf.bos);
diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
index 6f7c15e..323e17a 100644
--- a/src/intel/vulkan/anv_device.c
+++ b/src/intel/vulkan/anv_device.c
@@ -323,6 +323,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 10aad2d..a30f704 100644
--- a/src/intel/vulkan/anv_entrypoints_gen.py
+++ b/src/intel/vulkan/anv_entrypoints_gen.py
@@ -42,6 +42,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 a2e077a..8763cbb 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -1278,7 +1278,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);
@@ -1367,11 +1371,14 @@ 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;
+
+ struct anv_bo bo;
};
struct anv_semaphore {
diff --git a/src/intel/vulkan/anv_queue.c b/src/intel/vulkan/anv_queue.c
index e5efbe3..656ab1a 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"
@@ -157,7 +161,23 @@ VkResult anv_QueueSubmit(
pSubmits[i].pCommandBuffers[j]);
assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY);
- 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;
}
@@ -468,14 +488,27 @@ 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, even between
+ * different rings. As such, 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_init_new(&semaphore->permanent.bo, device, 4096);
+ if (result != VK_SUCCESS) {
+ vk_free2(&device->alloc, pAllocator, semaphore);
+ return result;
+ }
+ } 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);
@@ -483,6 +516,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_gem_close(device, impl->bo.gem_handle);
+ break;
+
+ default:
+ unreachable("Invalid semaphore type");
+ }
+}
+
void anv_DestroySemaphore(
VkDevice _device,
VkSemaphore _semaphore,
@@ -491,6 +543,9 @@ void anv_DestroySemaphore(
ANV_FROM_HANDLE(anv_device, device, _device);
ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
+ anv_semaphore_impl_cleanup(device, &semaphore->temporary);
+ anv_semaphore_impl_cleanup(device, &semaphore->permanent);
+
vk_free2(&device->alloc, pAllocator, semaphore);
}
@@ -500,9 +555,80 @@ 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: {
+ uint32_t gem_handle =
+ anv_gem_fd_to_handle(device, pImportSemaphoreFdInfo->fd);
+ if (!gem_handle)
+ return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX);
+
+ /* 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_BO;
+ anv_bo_init(&semaphore->permanent.bo, gem_handle, 4096);
+ 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);
+
+ int fd = -1;
+ switch (semaphore->permanent.type) {
+ case ANV_SEMAPHORE_TYPE_BO:
+ fd = anv_gem_handle_to_fd(device, semaphore->permanent.bo.gem_handle);
+ if (fd < 0)
+ return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
+ break;
+
+ default:
+ return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX);
+ }
+
+ *pFd = fd;
+
+ return VK_SUCCESS;
+}
--
2.5.0.400.gff86faf
More information about the mesa-dev
mailing list