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 | 16 +++- src/intel/vulkan/anv_queue.c | 132 ++++++++++++++++++++++++++++++-- 5 files changed, 182 insertions(+), 15 deletions(-)
diff --git a/src/intel/vulkan/anv_batch_chain.c b/src/intel/vulkan/anv_batch_chain.c index c55938a..3f6b767 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 e9d919d..e393596 100644 --- a/src/intel/vulkan/anv_device.c +++ b/src/intel/vulkan/anv_device.c @@ -331,6 +331,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 c463eff..8945f04 100644 --- a/src/intel/vulkan/anv_entrypoints_gen.py +++ b/src/intel/vulkan/anv_entrypoints_gen.py @@ -44,6 +44,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 291a3e2..5a9aeab 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -1409,7 +1409,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); @@ -1498,11 +1502,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 fe640eb..be88c6e 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,29 @@ 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, + &device->alloc); + 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 +518,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_bo_cache_release(device, &device->bo_cache, impl->bo, &device->alloc); + break; + + default: + unreachable("Invalid semaphore type"); + } +} + void anv_DestroySemaphore( VkDevice _device, VkSemaphore _semaphore, @@ -494,6 +548,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); } @@ -503,9 +560,68 @@ 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: { + struct anv_bo *bo; + VkResult result = anv_bo_cache_import(device, &device->bo_cache, + pImportSemaphoreFdInfo->fd, 4096, + &bo, &device->alloc); + if (result != VK_SUCCESS) + return result; + + 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.5.0.400.gff86faf _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev