VkResult result = VK_SUCCESS;
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;
+ struct anv_semaphore_impl *impl =
+ semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
+ &semaphore->temporary : &semaphore->permanent;
switch (impl->type) {
case ANV_SEMAPHORE_TYPE_BO:
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;
+
+ /* 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_semaphore_impl *impl =
+ semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
+ &semaphore->temporary : &semaphore->permanent;
switch (impl->type) {
case ANV_SEMAPHORE_TYPE_BO:
result = anv_device_execbuf(device, &execbuf.execbuf, execbuf.bos);
+ for (uint32_t i = 0; i < num_in_semaphores; i++) {
+ ANV_FROM_HANDLE(anv_semaphore, semaphore, in_semaphores[i]);
+ /* 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."
+ *
+ * This has to happen after the execbuf in case we close any syncobjs in
+ * the process.
+ */
+ anv_semaphore_reset_temporary(device, semaphore);
+ }
+
anv_execbuf_finish(&execbuf, &device->alloc);
return result;
if (semaphore == NULL)
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
- /* 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;
+ const VkExportSemaphoreCreateInfoKHR *export =
+ vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO_KHR);
+ VkExternalSemaphoreHandleTypeFlagsKHR handleTypes =
+ export ? export->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_KHR) {
+ assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR);
+
+ 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));
+ } else {
+ assert(!"Unknown handle type");
+ vk_free2(&device->alloc, pAllocator, semaphore);
+ return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
+ }
+
semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
*pSemaphore = anv_semaphore_to_handle(semaphore);
unreachable("Invalid semaphore type");
}
+void
+anv_semaphore_reset_temporary(struct anv_device *device,
+ struct anv_semaphore *semaphore)
+{
+ if (semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE)
+ return;
+
+ anv_semaphore_impl_cleanup(device, &semaphore->temporary);
+ semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
+}
+
void anv_DestroySemaphore(
VkDevice _device,
VkSemaphore _semaphore,
vk_free2(&device->alloc, pAllocator, semaphore);
}
+
+void anv_GetPhysicalDeviceExternalSemaphorePropertiesKHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalSemaphoreInfoKHR* pExternalSemaphoreInfo,
+ VkExternalSemaphorePropertiesKHR* pExternalSemaphoreProperties)
+{
+ switch (pExternalSemaphoreInfo->handleType) {
+ case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR:
+ pExternalSemaphoreProperties->exportFromImportedHandleTypes =
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+ pExternalSemaphoreProperties->compatibleHandleTypes =
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+ pExternalSemaphoreProperties->externalSemaphoreFeatures =
+ VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR |
+ VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR;
+ break;
+
+ default:
+ pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
+ pExternalSemaphoreProperties->compatibleHandleTypes = 0;
+ pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
+ }
+}
+
+VkResult anv_ImportSemaphoreFdKHR(
+ VkDevice _device,
+ const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo)
+{
+ ANV_FROM_HANDLE(anv_device, device, _device);
+ ANV_FROM_HANDLE(anv_semaphore, semaphore, pImportSemaphoreFdInfo->semaphore);
+ int fd = pImportSemaphoreFdInfo->fd;
+
+ struct anv_semaphore_impl new_impl = {
+ .type = ANV_SEMAPHORE_TYPE_NONE,
+ };
+
+ 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;
+
+ /* 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;
+ }
+
+ default:
+ return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
+ }
+
+ if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR) {
+ anv_semaphore_impl_cleanup(device, &semaphore->temporary);
+ semaphore->temporary = new_impl;
+ } else {
+ anv_semaphore_impl_cleanup(device, &semaphore->permanent);
+ semaphore->permanent = new_impl;
+ }
+
+ return VK_SUCCESS;
+}
+
+VkResult anv_GetSemaphoreFdKHR(
+ VkDevice _device,
+ const VkSemaphoreGetFdInfoKHR* pGetFdInfo,
+ int* pFd)
+{
+ ANV_FROM_HANDLE(anv_device, device, _device);
+ ANV_FROM_HANDLE(anv_semaphore, semaphore, pGetFdInfo->semaphore);
+ VkResult result;
+
+ assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR);
+
+ struct anv_semaphore_impl *impl =
+ semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
+ &semaphore->temporary : &semaphore->permanent;
+
+ switch (impl->type) {
+ case ANV_SEMAPHORE_TYPE_BO:
+ result = anv_bo_cache_export(device, &device->bo_cache, impl->bo, pFd);
+ if (result != VK_SUCCESS)
+ return result;
+ break;
+
+ default:
+ return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
+ }
+
+ /* From the Vulkan 1.0.53 spec:
+ *
+ * "Export operations have the same transference as the specified handle
+ * type’s import operations. [...] If the semaphore was using a
+ * temporarily imported payload, the semaphore’s prior permanent payload
+ * will be restored.
+ */
+ if (impl == &semaphore->temporary)
+ anv_semaphore_impl_cleanup(device, impl);
+
+ return VK_SUCCESS;
+}