From 4201cc2dd3aaa4b6c15c52037b3a6413274082ec Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 15 Feb 2017 17:25:46 -0800 Subject: [PATCH] anv: Implement VK_KHX_external_semaphore_fd 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. Reviewed-by: Chad Versace --- 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 e73140b..23dff90 100644 --- a/src/intel/vulkan/anv_device.c +++ b/src/intel/vulkan/anv_device.c @@ -379,6 +379,10 @@ static const VkExtensionProperties device_extensions[] = { .specVersion = 1, }, { + .extensionName = VK_KHX_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, + .specVersion = 1, + }, + { .extensionName = VK_KHX_MULTIVIEW_EXTENSION_NAME, .specVersion = 1, }, diff --git a/src/intel/vulkan/anv_entrypoints_gen.py b/src/intel/vulkan/anv_entrypoints_gen.py index cebbad0..a21228c 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', 'VK_KHX_multiview', ] diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h index 7fc732f..21d0ac2 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..fac979a 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 +#include +#include + #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,24 @@ 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 */ + return; + + case ANV_SEMAPHORE_TYPE_BO: + anv_bo_cache_release(device, &device->bo_cache, impl->bo); + return; + } + + unreachable("Invalid semaphore type"); +} + void anv_DestroySemaphore( VkDevice _device, VkSemaphore _semaphore, @@ -539,6 +596,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 +608,74 @@ void anv_GetPhysicalDeviceExternalSemaphorePropertiesKHX( VkExternalSemaphorePropertiesKHX* pExternalSemaphoreProperties) { switch (pExternalSemaphoreInfo->handleType) { + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHX: + pExternalSemaphoreProperties->exportFromImportedHandleTypes = + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHX; + 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.7.4