From 55bce22d8d98342ce071b7286ce07f31430f772a Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 10 Apr 2017 18:36:42 -0700 Subject: [PATCH] anv: Use DRM sync objects for external semaphores when available Reviewed-by: Lionel Landwerlin --- src/intel/vulkan/anv_batch_chain.c | 59 +++++++++++++++++++++ src/intel/vulkan/anv_device.c | 1 + src/intel/vulkan/anv_private.h | 8 +++ src/intel/vulkan/anv_queue.c | 83 +++++++++++++++++++++--------- 4 files changed, 128 insertions(+), 23 deletions(-) diff --git a/src/intel/vulkan/anv_batch_chain.c b/src/intel/vulkan/anv_batch_chain.c index 3c2f6f3e6b1..0078cc5142e 100644 --- a/src/intel/vulkan/anv_batch_chain.c +++ b/src/intel/vulkan/anv_batch_chain.c @@ -957,6 +957,11 @@ 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; + struct anv_syncobj ** syncobjs; }; static void @@ -971,6 +976,8 @@ anv_execbuf_finish(struct anv_execbuf *exec, { vk_free(alloc, exec->objects); vk_free(alloc, exec->bos); + vk_free(alloc, exec->fences); + vk_free(alloc, exec->syncobjs); } static VkResult @@ -1061,6 +1068,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) +{ + assert(flags != 0); + + if (exec->fence_count >= exec->fence_array_length) { + uint32_t new_len = MAX2(exec->fence_array_length * 2, 64); + + exec->fences = vk_realloc(alloc, exec->fences, + new_len * sizeof(*exec->fences), + 8, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (exec->fences == NULL) + return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); + + 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) @@ -1448,6 +1484,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; } @@ -1484,6 +1528,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; } @@ -1497,6 +1549,13 @@ anv_cmd_buffer_execbuf(struct anv_device *device, setup_empty_execbuf(&execbuf, device); } + if (execbuf.fence_count > 0) { + assert(device->instance->physicalDevice.has_syncobj); + 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 3c5f78c9993..a6d5215ab8d 100644 --- a/src/intel/vulkan/anv_device.c +++ b/src/intel/vulkan/anv_device.c @@ -338,6 +338,7 @@ 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, 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 b451fa509a6..de7463797a4 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -653,6 +653,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; @@ -1742,6 +1743,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 { @@ -1760,6 +1762,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 1f270280eca..0a40ebc2e60 100644 --- a/src/intel/vulkan/anv_queue.c +++ b/src/intel/vulkan/anv_queue.c @@ -558,19 +558,27 @@ VkResult anv_CreateSemaphore( semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DUMMY; } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR) { assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR); + 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_error(VK_ERROR_OUT_OF_HOST_MEMORY); + } + } 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. + */ + assert(!(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. - */ - assert(!(semaphore->permanent.bo->flags & EXEC_OBJECT_ASYNC)); } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR) { assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR); @@ -606,6 +614,10 @@ anv_semaphore_impl_cleanup(struct anv_device *device, case ANV_SEMAPHORE_TYPE_SYNC_FILE: close(impl->fd); return; + + case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: + anv_gem_syncobj_destroy(device, impl->syncobj); + return; } unreachable("Invalid semaphore type"); @@ -691,21 +703,38 @@ VkResult anv_ImportSemaphoreFdKHR( }; switch (pImportSemaphoreFdInfo->handleType) { - case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR: { - new_impl.type = ANV_SEMAPHORE_TYPE_BO; - - VkResult result = anv_bo_cache_import(device, &device->bo_cache, - fd, 4096, &new_impl.bo); - if (result != VK_SUCCESS) - return result; + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR: + if (device->instance->physicalDevice.has_syncobj) { + new_impl.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ; + + new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd); + if (!new_impl.syncobj) + return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR); + + /* 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); + } else { + new_impl.type = ANV_SEMAPHORE_TYPE_BO; - /* If we're going to use this as a fence, we need to *not* have the - * EXEC_OBJECT_ASYNC bit set. - */ - assert(!(new_impl.bo->flags & EXEC_OBJECT_ASYNC)); + VkResult result = anv_bo_cache_import(device, &device->bo_cache, + fd, 4096, &new_impl.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. + */ + assert(!(new_impl.bo->flags & EXEC_OBJECT_ASYNC)); + } break; - } case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR: new_impl = (struct anv_semaphore_impl) { @@ -740,6 +769,7 @@ VkResult anv_GetSemaphoreFdKHR( ANV_FROM_HANDLE(anv_device, device, _device); ANV_FROM_HANDLE(anv_semaphore, semaphore, pGetFdInfo->semaphore); VkResult result; + int fd; assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR); @@ -782,6 +812,13 @@ VkResult anv_GetSemaphoreFdKHR( impl->fd = -1; return VK_SUCCESS; + case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: + fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj); + if (fd < 0) + return vk_error(VK_ERROR_TOO_MANY_OBJECTS); + *pFd = fd; + break; + default: return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR); } -- 2.30.2