[Mesa-dev] [PATCH 09/10] anv: Implement VK_KHR_external_fence
Jason Ekstrand
jason at jlekstrand.net
Tue Aug 8 22:45:34 UTC 2017
---
src/intel/vulkan/anv_batch_chain.c | 19 ++++-
src/intel/vulkan/anv_extensions.py | 5 ++
src/intel/vulkan/anv_queue.c | 142 ++++++++++++++++++++++++++++++++++++-
3 files changed, 161 insertions(+), 5 deletions(-)
diff --git a/src/intel/vulkan/anv_batch_chain.c b/src/intel/vulkan/anv_batch_chain.c
index 15082b5..7d16403 100644
--- a/src/intel/vulkan/anv_batch_chain.c
+++ b/src/intel/vulkan/anv_batch_chain.c
@@ -1545,8 +1545,20 @@ anv_cmd_buffer_execbuf(struct anv_device *device,
}
if (fence) {
- assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
- struct anv_fence_impl *impl = &fence->permanent;
+ /* Under most circumstances, out fences won't be temporary. However,
+ * the spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec:
+ *
+ * "If the import is temporary, the implementation must restore the
+ * semaphore to its prior permanent state after submitting the next
+ * semaphore wait operation."
+ *
+ * The spec says nothing whatsoever about signal operations on
+ * temporarily imported semaphores so it appears they are allowed.
+ * There are also CTS tests that require this to work.
+ */
+ struct anv_fence_impl *impl =
+ fence->temporary.type != ANV_FENCE_TYPE_NONE ?
+ &fence->temporary : &fence->permanent;
switch (impl->type) {
case ANV_FENCE_TYPE_BO:
@@ -1612,6 +1624,9 @@ anv_cmd_buffer_execbuf(struct anv_device *device,
}
if (fence && fence->permanent.type == ANV_FENCE_TYPE_BO) {
+ /* BO fences can't be shared, so they can't be temporary. */
+ assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
+
/* Once the execbuf has returned, we need to set the fence state to
* SUBMITTED. We can't do this before calling execbuf because
* anv_GetFenceStatus does take the global device lock before checking
diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py
index 3252e0f..6b3d72e 100644
--- a/src/intel/vulkan/anv_extensions.py
+++ b/src/intel/vulkan/anv_extensions.py
@@ -47,6 +47,11 @@ class Extension:
EXTENSIONS = [
Extension('VK_KHR_dedicated_allocation', 1, True),
Extension('VK_KHR_descriptor_update_template', 1, True),
+ Extension('VK_KHR_external_fence', 1,
+ 'device->has_syncobj_wait'),
+ Extension('VK_KHR_external_fence_capabilities', 1, True),
+ Extension('VK_KHR_external_fence_fd', 1,
+ 'device->has_syncobj_wait'),
Extension('VK_KHR_external_memory', 1, True),
Extension('VK_KHR_external_memory_capabilities', 1, True),
Extension('VK_KHR_external_memory_fd', 1, True),
diff --git a/src/intel/vulkan/anv_queue.c b/src/intel/vulkan/anv_queue.c
index 8e45bb2..ebd62ca 100644
--- a/src/intel/vulkan/anv_queue.c
+++ b/src/intel/vulkan/anv_queue.c
@@ -345,7 +345,18 @@ VkResult anv_ResetFences(
for (uint32_t i = 0; i < fenceCount; i++) {
ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
- assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
+ /* From the Vulkan 1.0.53 spec:
+ *
+ * "If any member of pFences currently has its payload imported with
+ * temporary permanence, that fence’s prior permanent payload is
+ * first restored. The remaining operations described therefore
+ * operate on the restored payload.
+ */
+ if (fence->temporary.type != ANV_FENCE_TYPE_NONE) {
+ anv_fence_impl_cleanup(device, &fence->temporary);
+ fence->temporary.type = ANV_FENCE_TYPE_NONE;
+ }
+
struct anv_fence_impl *impl = &fence->permanent;
switch (impl->type) {
@@ -375,11 +386,14 @@ VkResult anv_GetFenceStatus(
if (unlikely(device->lost))
return VK_ERROR_DEVICE_LOST;
- assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
- struct anv_fence_impl *impl = &fence->permanent;
+ struct anv_fence_impl *impl =
+ fence->temporary.type != ANV_FENCE_TYPE_NONE ?
+ &fence->temporary : &fence->permanent;
switch (impl->type) {
case ANV_FENCE_TYPE_BO:
+ /* BO fences don't support import/export */
+ assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
switch (impl->bo.state) {
case ANV_BO_FENCE_STATE_RESET:
/* If it hasn't even been sent off to the GPU yet, it's not ready */
@@ -661,6 +675,128 @@ VkResult anv_WaitForFences(
}
}
+void anv_GetPhysicalDeviceExternalFencePropertiesKHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalFenceInfoKHR* pExternalFenceInfo,
+ VkExternalFencePropertiesKHR* pExternalFenceProperties)
+{
+ ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
+
+ switch (pExternalFenceInfo->handleType) {
+ case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR:
+ if (device->has_syncobj_wait) {
+ pExternalFenceProperties->exportFromImportedHandleTypes =
+ VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+ pExternalFenceProperties->compatibleHandleTypes =
+ VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+ pExternalFenceProperties->externalFenceFeatures =
+ VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR |
+ VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR;
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ pExternalFenceProperties->exportFromImportedHandleTypes = 0;
+ pExternalFenceProperties->compatibleHandleTypes = 0;
+ pExternalFenceProperties->externalFenceFeatures = 0;
+}
+
+VkResult anv_ImportFenceFdKHR(
+ VkDevice _device,
+ const VkImportFenceFdInfoKHR* pImportFenceFdInfo)
+{
+ ANV_FROM_HANDLE(anv_device, device, _device);
+ ANV_FROM_HANDLE(anv_fence, fence, pImportFenceFdInfo->fence);
+ int fd = pImportFenceFdInfo->fd;
+
+ assert(pImportFenceFdInfo->sType ==
+ VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR);
+
+ struct anv_fence_impl new_impl = {
+ .type = ANV_FENCE_TYPE_NONE,
+ };
+
+ switch (pImportFenceFdInfo->handleType) {
+ case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR:
+ new_impl.type = ANV_FENCE_TYPE_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 1.0.53 spec:
+ *
+ * "Importing a fence payload 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(fd);
+ break;
+
+ default:
+ return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
+ }
+
+ if (pImportFenceFdInfo->flags & VK_FENCE_IMPORT_TEMPORARY_BIT_KHR) {
+ anv_fence_impl_cleanup(device, &fence->temporary);
+ fence->temporary = new_impl;
+ } else {
+ anv_fence_impl_cleanup(device, &fence->permanent);
+ fence->permanent = new_impl;
+ }
+
+ return VK_SUCCESS;
+}
+
+VkResult anv_GetFenceFdKHR(
+ VkDevice _device,
+ const VkFenceGetFdInfoKHR* pGetFdInfo,
+ int* pFd)
+{
+ ANV_FROM_HANDLE(anv_device, device, _device);
+ ANV_FROM_HANDLE(anv_fence, fence, pGetFdInfo->fence);
+
+ assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR);
+
+ struct anv_fence_impl *impl =
+ fence->temporary.type != ANV_FENCE_TYPE_NONE ?
+ &fence->temporary : &fence->permanent;
+
+ assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
+ switch (pGetFdInfo->handleType) {
+ case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR: {
+ int 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:
+ unreachable("Invalid fence export handle type");
+ }
+
+ /* From the Vulkan 1.0.53 spec:
+ *
+ * "Export operations have the same transference as the specified handle
+ * type’s import operations. [...] If the fence was using a
+ * temporarily imported payload, the fence’s prior permanent payload
+ * will be restored.
+ */
+ if (impl == &fence->temporary)
+ anv_fence_impl_cleanup(device, impl);
+
+ return VK_SUCCESS;
+}
+
// Queue semaphore functions
VkResult anv_CreateSemaphore(
--
2.5.0.400.gff86faf
More information about the mesa-dev
mailing list