Sfoglia il codice sorgente

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
Matias N. Goldberg 2 anni fa
parent
commit
0b09fdd96c
1 ha cambiato i file con 22 aggiunte e 14 eliminazioni
  1. 22 14
      drivers/vulkan/vulkan_context.cpp

+ 22 - 14
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;
 }