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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev