anv: Use DRM sync objects for external semaphores when available
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR:
|
||||
if (device->instance->physicalDevice.has_syncobj) {
|
||||
new_impl.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
|
||||
|
||||
VkResult result = anv_bo_cache_import(device, &device->bo_cache,
|
||||
fd, 4096, &new_impl.bo);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);
|
||||
if (!new_impl.syncobj)
|
||||
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
|
||||
|
||||
/* 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));
|
||||
/* 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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user