summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Ekstrand <[email protected]>2017-08-08 12:25:38 -0700
committerJason Ekstrand <[email protected]>2017-08-28 19:33:43 -0700
commit49c59c88eb725cba113ea51307ba66223e411e9a (patch)
treeea184ae29a596e94dfeb01c6595777b305ad39c2
parent5f372d93a9088afdbd97c0668f9684f369bc33a2 (diff)
anv: Implement VK_KHR_external_fence
Reviewed-by: Lionel Landwerlin <[email protected]>
-rw-r--r--src/intel/vulkan/anv_batch_chain.c19
-rw-r--r--src/intel/vulkan/anv_extensions.py5
-rw-r--r--src/intel/vulkan/anv_queue.c142
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 52c45104b22..4f5137c2ecf 100644
--- a/src/intel/vulkan/anv_batch_chain.c
+++ b/src/intel/vulkan/anv_batch_chain.c
@@ -1549,8 +1549,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:
@@ -1617,6 +1629,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 3252e0fc567..6b3d72e4b4c 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 1c0de527fca..a954f65f1d7 100644
--- a/src/intel/vulkan/anv_queue.c
+++ b/src/intel/vulkan/anv_queue.c
@@ -349,7 +349,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) {
@@ -379,11 +390,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 */
@@ -665,6 +679,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(