From 0b09fdd96cd515ecddee3fe59fcff5a6d509f545 Mon Sep 17 00:00:00 2001 From: "Matias N. Goldberg" Date: Sat, 12 Aug 2023 20:32:28 -0300 Subject: [PATCH] Fix validation error when resizing window Sometimes when resizing the window we may get the following validation error: ERROR: VALIDATION - Message Id Number: -370888023 | Message Id Name: VUID-vkAcquireNextImageKHR-semaphore-01286 Validation Error: [ VUID-vkAcquireNextImageKHR-semaphore-01286 ] Object 0: handle = 0xdcc8fd0000000012, type = VK_OBJECT_TYPE_SEMAPHORE; | MessageID = 0xe9e4b2a9 | vkAcquireNextImageKHR: Semaphore must not be currently signaled or in a wait state. The Vulkan spec states: If semaphore is not VK_NULL_HANDLE it must be unsignaled (https://vulkan.lunarg.com/doc/view/1.2.198.1/linux/1.2-extensions/vkspec.html#VUID-vkAcquireNextImageKHR-semaphore-01286) In VulkanContext::prepare_buffers the problem was that vkAcquireNextImageKHR returned VK_SUBOPTIMAL_KHR but it already signaled the semaphore (because it is possible to continue normally with a VK_SUBOPTIMAL_KHR result). Then we recreate the swapchain and reuse the w->image_acquired_semaphores[frame_index] which is in an inconsistent state. Fixed by recreating the semamphores along the swapchain. Fix #80570 --- drivers/vulkan/vulkan_context.cpp | 36 +++++++++++++++++++------------ 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp index c167caeb7cf..89a56bae037 100644 --- a/drivers/vulkan/vulkan_context.cpp +++ b/drivers/vulkan/vulkan_context.cpp @@ -1700,17 +1700,6 @@ Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, Display Error err = _update_swap_chain(&window); ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); - VkSemaphoreCreateInfo semaphoreCreateInfo = { - /*sType*/ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - /*pNext*/ nullptr, - /*flags*/ 0, - }; - - for (uint32_t i = 0; i < FRAME_LAG; i++) { - VkResult vkerr = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &window.image_acquired_semaphores[i]); - ERR_FAIL_COND_V(vkerr, ERR_CANT_CREATE); - } - windows[p_window_id] = window; return OK; } @@ -1760,9 +1749,6 @@ VkFramebuffer VulkanContext::window_get_framebuffer(DisplayServer::WindowID p_wi void VulkanContext::window_destroy(DisplayServer::WindowID p_window_id) { ERR_FAIL_COND(!windows.has(p_window_id)); _clean_up_swap_chain(&windows[p_window_id]); - for (uint32_t i = 0; i < FRAME_LAG; i++) { - vkDestroySemaphore(device, windows[p_window_id].image_acquired_semaphores[i], nullptr); - } vkDestroySurfaceKHR(inst, windows[p_window_id].surface, nullptr); windows.erase(p_window_id); @@ -1792,6 +1778,17 @@ Error VulkanContext::_clean_up_swap_chain(Window *window) { if (separate_present_queue) { vkDestroyCommandPool(device, window->present_cmd_pool, nullptr); } + + for (uint32_t i = 0; i < FRAME_LAG; i++) { + // Destroy the semaphores now (we'll re-create it later if we have to). + // We must do this because the semaphore cannot be reused if it's in a signaled state + // (which happens if vkAcquireNextImageKHR returned VK_ERROR_OUT_OF_DATE_KHR or VK_SUBOPTIMAL_KHR) + // The only way to reset it would be to present the swapchain... the one we just destroyed. + // And the API has no way to "unsignal" the semaphore. + vkDestroySemaphore(device, window->image_acquired_semaphores[i], nullptr); + window->image_acquired_semaphores[i] = 0; + } + return OK; } @@ -2175,6 +2172,17 @@ Error VulkanContext::_update_swap_chain(Window *window) { // Reset current buffer. window->current_buffer = 0; + VkSemaphoreCreateInfo semaphoreCreateInfo = { + /*sType*/ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + /*pNext*/ nullptr, + /*flags*/ 0, + }; + + for (uint32_t i = 0; i < FRAME_LAG; i++) { + VkResult vkerr = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &window->image_acquired_semaphores[i]); + ERR_FAIL_COND_V(vkerr, ERR_CANT_CREATE); + } + return OK; }