From 3c4c263dc734ec75f72d36b1d0d1a9cd41310112 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Sat, 9 Sep 2023 17:10:44 -0700 Subject: [PATCH] vulkan/android: improve vkQueueSignalReleaseImageANDROID There're two issues with the current implementation: 1. Wait semaphores are implicitly required to be SYNC_FD exportable 2. As a queue command that can further record cmds against the wsi image, it currently doesn't account for pending cmds in the queue beyond the wait semaphores. This change fixes both by doing a queue submission in the call with a SYNC_FD external signal semaphore. However, due to Android wsi not exposing swapchain to icd, we have to cache the signal semaphore in the queue, otherwise would have to create/destroy in each present. Signed-off-by: Yiwei Zhang Reviewed-by: Chia-I Wu Part-of: --- src/vulkan/runtime/vk_android.c | 79 ++++++++++++++++++--------------- src/vulkan/runtime/vk_queue.c | 8 ++++ src/vulkan/runtime/vk_queue.h | 18 ++++++++ 3 files changed, 69 insertions(+), 36 deletions(-) diff --git a/src/vulkan/runtime/vk_android.c b/src/vulkan/runtime/vk_android.c index 2bf97760241..677e278404f 100644 --- a/src/vulkan/runtime/vk_android.c +++ b/src/vulkan/runtime/vk_android.c @@ -301,6 +301,24 @@ vk_common_AcquireImageANDROID(VkDevice _device, return result; } +static VkResult +vk_anb_semaphore_init_once(struct vk_queue *queue, struct vk_device *device) +{ + if (queue->anb_semaphore != VK_NULL_HANDLE) + return VK_SUCCESS; + + const VkExportSemaphoreCreateInfo export_info = { + .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO, + .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, + }; + const VkSemaphoreCreateInfo create_info = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext = &export_info, + }; + return device->dispatch_table.CreateSemaphore(vk_device_to_handle(device), + &create_info, NULL, + &queue->anb_semaphore); +} VKAPI_ATTR VkResult VKAPI_CALL vk_common_QueueSignalReleaseImageANDROID(VkQueue _queue, @@ -313,43 +331,32 @@ vk_common_QueueSignalReleaseImageANDROID(VkQueue _queue, struct vk_device *device = queue->base.device; VkResult result = VK_SUCCESS; - if (waitSemaphoreCount == 0) { - if (pNativeFenceFd) - *pNativeFenceFd = -1; - return VK_SUCCESS; - } + STACK_ARRAY(VkPipelineStageFlags, stage_flags, MAX2(1, waitSemaphoreCount)); + for (uint32_t i = 0; i < MAX2(1, waitSemaphoreCount); i++) + stage_flags[i] = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; - int fd = -1; + result = vk_anb_semaphore_init_once(queue, device); + if (result != VK_SUCCESS) + return result; - for (uint32_t i = 0; i < waitSemaphoreCount; ++i) { - const VkSemaphoreGetFdInfoKHR get_fd = { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR, - .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, - .semaphore = pWaitSemaphores[i], - }; - int tmp_fd; - result = device->dispatch_table.GetSemaphoreFdKHR(vk_device_to_handle(device), - &get_fd, &tmp_fd); - if (result != VK_SUCCESS) { - if (fd >= 0) - close(fd); - return result; - } + const VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .waitSemaphoreCount = waitSemaphoreCount, + .pWaitSemaphores = pWaitSemaphores, + .pWaitDstStageMask = stage_flags, + .signalSemaphoreCount = 1, + .pSignalSemaphores = &queue->anb_semaphore, + }; + result = device->dispatch_table.QueueSubmit(_queue, 1, &submit_info, + VK_NULL_HANDLE); + if (result != VK_SUCCESS) + return result; - if (fd < 0) { - fd = tmp_fd; - } else if (tmp_fd >= 0) { - sync_accumulate("vulkan", &fd, tmp_fd); - close(tmp_fd); - } - } - - if (pNativeFenceFd) { - *pNativeFenceFd = fd; - } else if (fd >= 0) { - close(fd); - /* We still need to do the exports, to reset the semaphores, but - * otherwise we don't wait on them. */ - } - return VK_SUCCESS; + const VkSemaphoreGetFdInfoKHR get_fd = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR, + .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, + .semaphore = queue->anb_semaphore, + }; + return device->dispatch_table.GetSemaphoreFdKHR(vk_device_to_handle(device), + &get_fd, pNativeFenceFd); } diff --git a/src/vulkan/runtime/vk_queue.c b/src/vulkan/runtime/vk_queue.c index a315c6f5431..9e38299ed05 100644 --- a/src/vulkan/runtime/vk_queue.c +++ b/src/vulkan/runtime/vk_queue.c @@ -1124,6 +1124,14 @@ vk_queue_finish(struct vk_queue *queue) vk_queue_submit_destroy(queue, submit); } +#ifdef ANDROID + if (queue->anb_semaphore != VK_NULL_HANDLE) { + struct vk_device *device = queue->base.device; + device->dispatch_table.DestroySemaphore(vk_device_to_handle(device), + queue->anb_semaphore, NULL); + } +#endif + cnd_destroy(&queue->submit.pop); cnd_destroy(&queue->submit.push); mtx_destroy(&queue->submit.mutex); diff --git a/src/vulkan/runtime/vk_queue.h b/src/vulkan/runtime/vk_queue.h index 0e2f34c3bd5..1308632bcc4 100644 --- a/src/vulkan/runtime/vk_queue.h +++ b/src/vulkan/runtime/vk_queue.h @@ -145,6 +145,24 @@ struct vk_queue { */ struct util_dynarray labels; bool region_begin; + +#ifdef ANDROID + /** SYNC_FD signal semaphore for vkQueueSignalReleaseImageANDROID + * + * VK_ANDROID_native_buffer enforces explicit fencing on the present api + * boundary. To avoid assuming all waitSemaphores exportable to sync file + * and to capture pending cmds in the queue, we do a simple submission and + * signal a SYNC_FD handle type external sempahore for native fence export. + * + * This plays the same role as wsi_swapchain::dma_buf_semaphore for WSI. + * The VK_ANDROID_native_buffer spec hides the swapchain object from the + * icd, so we have to cache the semaphore in common vk_queue. + * + * This also makes it easier to add additional cmds to prepare the wsi + * image for implementations requiring such (e.g. for layout transition). + */ + VkSemaphore anb_semaphore; +#endif }; VK_DEFINE_HANDLE_CASTS(vk_queue, base, VkQueue, VK_OBJECT_TYPE_QUEUE)