diff --git a/attachments/17_swap_chain_recreation.cpp b/attachments/17_swap_chain_recreation.cpp index fcd6df65..6e7c1338 100644 --- a/attachments/17_swap_chain_recreation.cpp +++ b/attachments/17_swap_chain_recreation.cpp @@ -135,11 +135,15 @@ class HelloTriangleApplication { int width = 0, height = 0; glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); diff --git a/attachments/19_vertex_buffer.cpp b/attachments/19_vertex_buffer.cpp index 77721ad6..e8cc7a9d 100644 --- a/attachments/19_vertex_buffer.cpp +++ b/attachments/19_vertex_buffer.cpp @@ -163,11 +163,15 @@ class HelloTriangleApplication { int width = 0, height = 0; glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); diff --git a/attachments/20_staging_buffer.cpp b/attachments/20_staging_buffer.cpp index 64980f7f..67f5f424 100644 --- a/attachments/20_staging_buffer.cpp +++ b/attachments/20_staging_buffer.cpp @@ -163,11 +163,15 @@ class HelloTriangleApplication { int width = 0, height = 0; glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); diff --git a/attachments/21_index_buffer.cpp b/attachments/21_index_buffer.cpp index 957b735a..3228e1a0 100644 --- a/attachments/21_index_buffer.cpp +++ b/attachments/21_index_buffer.cpp @@ -170,11 +170,15 @@ class HelloTriangleApplication { int width = 0, height = 0; glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); diff --git a/attachments/22_descriptor_layout.cpp b/attachments/22_descriptor_layout.cpp index 83355311..dce69912 100644 --- a/attachments/22_descriptor_layout.cpp +++ b/attachments/22_descriptor_layout.cpp @@ -188,11 +188,15 @@ class HelloTriangleApplication { int width = 0, height = 0; glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); diff --git a/attachments/23_descriptor_sets.cpp b/attachments/23_descriptor_sets.cpp index 881abc5c..d288162e 100644 --- a/attachments/23_descriptor_sets.cpp +++ b/attachments/23_descriptor_sets.cpp @@ -193,11 +193,15 @@ class HelloTriangleApplication { int width = 0, height = 0; glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); diff --git a/attachments/24_texture_image.cpp b/attachments/24_texture_image.cpp index b8d61315..491830a9 100644 --- a/attachments/24_texture_image.cpp +++ b/attachments/24_texture_image.cpp @@ -200,11 +200,15 @@ class HelloTriangleApplication { int width = 0, height = 0; glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); diff --git a/attachments/25_sampler.cpp b/attachments/25_sampler.cpp index 0608f172..24478f6e 100644 --- a/attachments/25_sampler.cpp +++ b/attachments/25_sampler.cpp @@ -204,11 +204,15 @@ class HelloTriangleApplication { int width = 0, height = 0; glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); diff --git a/attachments/26_texture_mapping.cpp b/attachments/26_texture_mapping.cpp index 26811191..e2ee2bfc 100644 --- a/attachments/26_texture_mapping.cpp +++ b/attachments/26_texture_mapping.cpp @@ -205,11 +205,15 @@ class HelloTriangleApplication { int width = 0, height = 0; glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); diff --git a/attachments/27_depth_buffering.cpp b/attachments/27_depth_buffering.cpp index dfb24250..a80d4bf7 100644 --- a/attachments/27_depth_buffering.cpp +++ b/attachments/27_depth_buffering.cpp @@ -219,11 +219,15 @@ class HelloTriangleApplication void recreateSwapChain() { int width = 0, height = 0; - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); diff --git a/attachments/28_model_loading.cpp b/attachments/28_model_loading.cpp index fe4ada52..776222c2 100644 --- a/attachments/28_model_loading.cpp +++ b/attachments/28_model_loading.cpp @@ -226,11 +226,15 @@ class HelloTriangleApplication void recreateSwapChain() { int width = 0, height = 0; - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); diff --git a/attachments/29_mipmapping.cpp b/attachments/29_mipmapping.cpp index d80a73cb..cb57bb3c 100644 --- a/attachments/29_mipmapping.cpp +++ b/attachments/29_mipmapping.cpp @@ -227,11 +227,15 @@ class HelloTriangleApplication void recreateSwapChain() { int width = 0, height = 0; - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); diff --git a/attachments/30_multisampling.cpp b/attachments/30_multisampling.cpp index 9a312fa2..c9740ca5 100644 --- a/attachments/30_multisampling.cpp +++ b/attachments/30_multisampling.cpp @@ -233,11 +233,15 @@ class HelloTriangleApplication void recreateSwapChain() { int width = 0, height = 0; - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); diff --git a/attachments/31_compute_shader.cpp b/attachments/31_compute_shader.cpp index 67ffe943..6c7a3dac 100644 --- a/attachments/31_compute_shader.cpp +++ b/attachments/31_compute_shader.cpp @@ -203,11 +203,15 @@ class ComputeShaderApplication { int width = 0, height = 0; glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); diff --git a/attachments/32_ecosystem_utilities.cpp b/attachments/32_ecosystem_utilities.cpp index a0a4c2d2..c955c513 100644 --- a/attachments/32_ecosystem_utilities.cpp +++ b/attachments/32_ecosystem_utilities.cpp @@ -262,11 +262,15 @@ class HelloTriangleApplication { int width = 0, height = 0; glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); diff --git a/attachments/33_vulkan_profiles.cpp b/attachments/33_vulkan_profiles.cpp index 4b1268e5..6478379c 100644 --- a/attachments/33_vulkan_profiles.cpp +++ b/attachments/33_vulkan_profiles.cpp @@ -263,11 +263,15 @@ class HelloTriangleApplication { int width = 0, height = 0; glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); diff --git a/attachments/34_android.cpp b/attachments/34_android.cpp index c32c6361..1ed97270 100644 --- a/attachments/34_android.cpp +++ b/attachments/34_android.cpp @@ -1389,11 +1389,15 @@ class HelloTriangleApplication if (window) { glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } } #endif // Wait for device to finish operations diff --git a/attachments/35_gltf_ktx.cpp b/attachments/35_gltf_ktx.cpp index 777010f4..710dd583 100644 --- a/attachments/35_gltf_ktx.cpp +++ b/attachments/35_gltf_ktx.cpp @@ -404,11 +404,15 @@ class VulkanApplication #if PLATFORM_DESKTOP int width = 0, height = 0; glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } #endif device.waitIdle(); diff --git a/attachments/36_multiple_objects.cpp b/attachments/36_multiple_objects.cpp index 9afc9003..7333ece7 100644 --- a/attachments/36_multiple_objects.cpp +++ b/attachments/36_multiple_objects.cpp @@ -477,11 +477,15 @@ class VulkanApplication #if PLATFORM_DESKTOP int width = 0, height = 0; glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } #endif device.waitIdle(); diff --git a/attachments/37_multithreading.cpp b/attachments/37_multithreading.cpp index aa443369..e396bb2c 100644 --- a/attachments/37_multithreading.cpp +++ b/attachments/37_multithreading.cpp @@ -499,11 +499,15 @@ class MultithreadedApplication { int width = 0, height = 0; glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); cleanupSwapChain(); diff --git a/attachments/38_ray_tracing.cpp b/attachments/38_ray_tracing.cpp index e0843931..47969865 100644 --- a/attachments/38_ray_tracing.cpp +++ b/attachments/38_ray_tracing.cpp @@ -310,11 +310,15 @@ class VulkanRaytracingApplication { int width = 0, height = 0; glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) + { + return; + } device.waitIdle(); diff --git a/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc b/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc index 3a942cdc..a440277d 100644 --- a/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc +++ b/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc @@ -112,20 +112,6 @@ Therefore, we should immediately recreate the swap chain and try again in the ne You could also decide to do that if the swap chain is suboptimal, but I've chosen to proceed anyway in that case because we've already acquired an image. Both `vk::Result::eSuccess` and `vk::Result::eSuboptimalKHR` are considered "success" return codes. -[,c++] ----- -result = queue.presentKHR(presentInfoKHR); -if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR)) -{ - recreateSwapChain(); -} -else -{ - // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. - assert(result == vk::Result::eSuccess); -} ----- - The `vk::raii::Queue::presentKHR` function returns the same values with the same meaning. In this case, we will also recreate the swap chain if it is suboptimal, because we want the best possible result. @@ -150,11 +136,23 @@ else == Fixing a deadlock -If we try to run the code now, it is possible to encounter a deadlock. -Debugging the code, we find that the application reaches `vk::raii::Device::waitForFences` but never continues past it. -This is because when `vk::raii::SwapchainKHR::acquireNextImage` returns `vk::Result::eErrorOutOfDateKHR`, we recreate the swapchain and then return from `drawFrame`. -But before that happens, the current frame's fence was waited upon and reset. -Since we return immediately, no work is submitted for execution and the fence will never be signaled, causing `vk::raii::Device::waitForFences` to halt forever. +Recall from the xref:03_Drawing/03_Frames_in_flight.adoc[previous chapter] that the beginning of `drawFrame` waits for and then immediately resets the current frame's fence: + +[,c++] +---- +auto fenceResult = device.waitForFences(*inFlightFences[frameIndex], vk::True, UINT64_MAX); +if (fenceResult != vk::Result::eSuccess) +{ + throw std::runtime_error("failed to wait for fence!"); +} + +device.resetFences(*inFlightFences[frameIndex]); +---- + +If we keep that structure and try to run the code now that `drawFrame` can return early from the acquire-image step above, it is possible to encounter a deadlock. +Debugging the code, we find that the application reaches `vk::raii::Device::waitForFences` on some later frame but never continues past it. +This is because when `vk::raii::SwapchainKHR::acquireNextImage` returns `vk::Result::eErrorOutOfDateKHR`, we recreate the swapchain and then return from `drawFrame` - but the current frame's fence was already reset just above, before we knew whether we'd actually submit any work. +Since we return immediately, no work is submitted for execution and the fence will never be signaled, causing `vk::raii::Device::waitForFences` to halt forever the next time we wait on that same fence object. There is a simple fix thankfully. Delay resetting the fence until after we know for sure, we will be submitting work with it. @@ -270,10 +268,13 @@ In this tutorial we will handle that by pausing until the window is in the foreg void recreateSwapChain() { int width = 0, height = 0; glfwGetFramebufferSize(window, &width, &height); - while (width == 0 || height == 0) { + while ((width == 0 || height == 0) && !glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &width, &height); glfwWaitEvents(); } + if (glfwWindowShouldClose(window)) { + return; + } device.waitIdle(); @@ -282,6 +283,7 @@ void recreateSwapChain() { ---- The initial call to `glfwGetFramebufferSize` handles the case where the size is already correct and `glfwWaitEvents` would have nothing to wait on. +The `glfwWindowShouldClose` check handles the case where the window is closed while still minimized - without it, the loop would spin forever waiting for a frame buffer size that will never become nonzero again. Congratulations, you've now finished your very first well-behaved Vulkan program! In the xref:04_Vertex_buffers/00_Vertex_input_description.adoc[next chapter] we're going to get rid of the hardcoded vertices in the vertex shader and actually use a vertex buffer.