From 5d60291fb00820a6611519365676cfd6a24e57a7 Mon Sep 17 00:00:00 2001 From: asuessenbach Date: Mon, 8 Dec 2025 13:53:57 +0100 Subject: [PATCH 1/3] Correctly handle vk::Result::eOutOfDate from vk::raii::SwapchainKHR::acquireNextImage and vk::raii::Queue::presentKHR --- attachments/17_swap_chain_recreation.cpp | 45 ++++++++++-------------- attachments/CMakeLists.txt | 5 ++- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/attachments/17_swap_chain_recreation.cpp b/attachments/17_swap_chain_recreation.cpp index a1ada280..d35a488b 100644 --- a/attachments/17_swap_chain_recreation.cpp +++ b/attachments/17_swap_chain_recreation.cpp @@ -513,13 +513,18 @@ class HelloTriangleApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } @@ -537,35 +542,23 @@ class HelloTriangleApplication .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/CMakeLists.txt b/attachments/CMakeLists.txt index 113fe20b..1261ca30 100644 --- a/attachments/CMakeLists.txt +++ b/attachments/CMakeLists.txt @@ -14,7 +14,7 @@ endif() find_package (glfw3 REQUIRED) find_package (glm REQUIRED) -find_package (Vulkan REQUIRED) +find_package (Vulkan 1.4.335 REQUIRED) # Require Vulkan SDK version 1.4.335 or higher find_package (tinyobjloader REQUIRED) find_package (tinygltf REQUIRED) find_package (KTX REQUIRED) @@ -139,6 +139,9 @@ function (add_chapter CHAPTER_NAME) target_compile_definitions(${CHAPTER_NAME} PRIVATE USE_CPP20_MODULES=1) endif() + # Define VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS to treat VK_ERROR_OUT_OF_DATE_KHR as a success code + target_compile_definitions(${CHAPTER_NAME} PRIVATE "VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS" ) + if(WIN32) if(${CMAKE_GENERATOR} MATCHES "Visual Studio.*") set_target_properties(${CHAPTER_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/${CHAPTER_NAME}") From c57e29c4ae54dc1c68c274e381779400f59e6ce4 Mon Sep 17 00:00:00 2001 From: asuessenbach Date: Thu, 18 Dec 2025 10:36:29 +0100 Subject: [PATCH 2/3] Carry changes to all other chapters. --- attachments/18_vertex_input.cpp | 47 ++++++++----------- attachments/19_vertex_buffer.cpp | 45 ++++++++---------- attachments/20_staging_buffer.cpp | 45 ++++++++---------- attachments/21_index_buffer.cpp | 45 ++++++++---------- attachments/22_descriptor_layout.cpp | 45 ++++++++---------- attachments/23_descriptor_sets.cpp | 45 ++++++++---------- attachments/24_texture_image.cpp | 45 ++++++++---------- attachments/25_sampler.cpp | 45 ++++++++---------- attachments/26_texture_mapping.cpp | 45 ++++++++---------- attachments/27_depth_buffering.cpp | 45 ++++++++---------- attachments/28_model_loading.cpp | 45 ++++++++---------- attachments/29_mipmapping.cpp | 45 ++++++++---------- attachments/30_multisampling.cpp | 45 ++++++++---------- attachments/31_compute_shader.cpp | 36 +++++---------- attachments/32_ecosystem_utilities.cpp | 45 ++++++++---------- attachments/33_vulkan_profiles.cpp | 64 +++++++++++--------------- attachments/34_android.cpp | 62 +++++++++++-------------- attachments/35_gltf_ktx.cpp | 45 ++++++++---------- attachments/36_multiple_objects.cpp | 45 ++++++++---------- attachments/37_multithreading.cpp | 16 +++++-- attachments/38_ray_tracing.cpp | 14 ++++-- 21 files changed, 394 insertions(+), 520 deletions(-) diff --git a/attachments/18_vertex_input.cpp b/attachments/18_vertex_input.cpp index 10061e61..45c4a740 100644 --- a/attachments/18_vertex_input.cpp +++ b/attachments/18_vertex_input.cpp @@ -532,13 +532,18 @@ class HelloTriangleApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } @@ -556,37 +561,25 @@ class HelloTriangleApplication .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } - frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; + frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } [[nodiscard]] vk::raii::ShaderModule createShaderModule(const std::vector &code) const diff --git a/attachments/19_vertex_buffer.cpp b/attachments/19_vertex_buffer.cpp index 07fc80d2..27c86671 100644 --- a/attachments/19_vertex_buffer.cpp +++ b/attachments/19_vertex_buffer.cpp @@ -568,13 +568,18 @@ class HelloTriangleApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } @@ -592,35 +597,23 @@ class HelloTriangleApplication .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/20_staging_buffer.cpp b/attachments/20_staging_buffer.cpp index 28f1f40b..cd253a6f 100644 --- a/attachments/20_staging_buffer.cpp +++ b/attachments/20_staging_buffer.cpp @@ -588,13 +588,18 @@ class HelloTriangleApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } @@ -612,35 +617,23 @@ class HelloTriangleApplication .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/21_index_buffer.cpp b/attachments/21_index_buffer.cpp index e427a625..9f525f27 100644 --- a/attachments/21_index_buffer.cpp +++ b/attachments/21_index_buffer.cpp @@ -614,13 +614,18 @@ class HelloTriangleApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } @@ -638,35 +643,23 @@ class HelloTriangleApplication .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/22_descriptor_layout.cpp b/attachments/22_descriptor_layout.cpp index bb379979..729907b0 100644 --- a/attachments/22_descriptor_layout.cpp +++ b/attachments/22_descriptor_layout.cpp @@ -673,13 +673,18 @@ class HelloTriangleApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } updateUniformBuffer(frameIndex); @@ -698,35 +703,23 @@ class HelloTriangleApplication .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/23_descriptor_sets.cpp b/attachments/23_descriptor_sets.cpp index 269a76a9..21f3237b 100644 --- a/attachments/23_descriptor_sets.cpp +++ b/attachments/23_descriptor_sets.cpp @@ -701,13 +701,18 @@ class HelloTriangleApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } updateUniformBuffer(frameIndex); @@ -726,35 +731,23 @@ class HelloTriangleApplication .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/24_texture_image.cpp b/attachments/24_texture_image.cpp index 5a622955..1ece1440 100644 --- a/attachments/24_texture_image.cpp +++ b/attachments/24_texture_image.cpp @@ -810,13 +810,18 @@ class HelloTriangleApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } updateUniformBuffer(frameIndex); @@ -835,35 +840,23 @@ class HelloTriangleApplication .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/25_sampler.cpp b/attachments/25_sampler.cpp index 9bff8a0b..da0e7da7 100644 --- a/attachments/25_sampler.cpp +++ b/attachments/25_sampler.cpp @@ -846,13 +846,18 @@ class HelloTriangleApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } updateUniformBuffer(frameIndex); @@ -871,35 +876,23 @@ class HelloTriangleApplication .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/26_texture_mapping.cpp b/attachments/26_texture_mapping.cpp index b5d67f96..bee87017 100644 --- a/attachments/26_texture_mapping.cpp +++ b/attachments/26_texture_mapping.cpp @@ -911,13 +911,18 @@ class HelloTriangleApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } updateUniformBuffer(frameIndex); @@ -936,35 +941,23 @@ class HelloTriangleApplication .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/27_depth_buffering.cpp b/attachments/27_depth_buffering.cpp index 6fd30340..eda15492 100644 --- a/attachments/27_depth_buffering.cpp +++ b/attachments/27_depth_buffering.cpp @@ -1012,13 +1012,18 @@ class HelloTriangleApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } updateUniformBuffer(frameIndex); @@ -1037,35 +1042,23 @@ class HelloTriangleApplication .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/28_model_loading.cpp b/attachments/28_model_loading.cpp index adc3e40d..a485743b 100644 --- a/attachments/28_model_loading.cpp +++ b/attachments/28_model_loading.cpp @@ -1068,13 +1068,18 @@ class HelloTriangleApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } updateUniformBuffer(frameIndex); @@ -1093,35 +1098,23 @@ class HelloTriangleApplication .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/29_mipmapping.cpp b/attachments/29_mipmapping.cpp index 77347ebb..0ba69637 100644 --- a/attachments/29_mipmapping.cpp +++ b/attachments/29_mipmapping.cpp @@ -1138,13 +1138,18 @@ class HelloTriangleApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } updateUniformBuffer(frameIndex); @@ -1163,35 +1168,23 @@ class HelloTriangleApplication .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/30_multisampling.cpp b/attachments/30_multisampling.cpp index 3c0b58b1..7ec0d044 100644 --- a/attachments/30_multisampling.cpp +++ b/attachments/30_multisampling.cpp @@ -1201,13 +1201,18 @@ class HelloTriangleApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } updateUniformBuffer(frameIndex); @@ -1226,35 +1231,23 @@ class HelloTriangleApplication .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/31_compute_shader.cpp b/attachments/31_compute_shader.cpp index 6b38a90a..75f08643 100644 --- a/attachments/31_compute_shader.cpp +++ b/attachments/31_compute_shader.cpp @@ -413,7 +413,7 @@ class ComputeShaderApplication .format = swapChainSurfaceFormat.format, .components = {vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity}, .subresourceRange = {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}}; - for (auto& image : swapChainImages) + for (auto &image : swapChainImages) { imageViewCreateInfo.image = image; swapChainImageViews.emplace_back(device, imageViewCreateInfo); @@ -811,7 +811,7 @@ class ComputeShaderApplication void drawFrame() { auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, nullptr, *inFlightFences[frameIndex]); - auto fenceResult = device.waitForFences(*inFlightFences[frameIndex], vk::True, UINT64_MAX); + auto fenceResult = device.waitForFences(*inFlightFences[frameIndex], vk::True, UINT64_MAX); if (fenceResult != vk::Result::eSuccess) { throw std::runtime_error("failed to wait for fence!"); @@ -884,7 +884,7 @@ class ComputeShaderApplication if (result != vk::Result::eSuccess) { throw std::runtime_error("failed to wait for semaphore!"); - } + } vk::PresentInfoKHR presentInfo{ .waitSemaphoreCount = 0, // No binary semaphores needed @@ -893,30 +893,18 @@ class ComputeShaderApplication .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; - try + result = queue.presentKHR(presentInfo); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - result = queue.presentKHR(presentInfo); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/attachments/32_ecosystem_utilities.cpp b/attachments/32_ecosystem_utilities.cpp index 8fef1204..61a5076b 100644 --- a/attachments/32_ecosystem_utilities.cpp +++ b/attachments/32_ecosystem_utilities.cpp @@ -1592,13 +1592,18 @@ class HelloTriangleApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } updateUniformBuffer(frameIndex); @@ -1656,35 +1661,23 @@ class HelloTriangleApplication queue.submit(submitInfo, *inFlightFences[frameIndex]); } - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/33_vulkan_profiles.cpp b/attachments/33_vulkan_profiles.cpp index a0627897..d8bc9a5f 100644 --- a/attachments/33_vulkan_profiles.cpp +++ b/attachments/33_vulkan_profiles.cpp @@ -1554,23 +1554,28 @@ class HelloTriangleApplication void drawFrame() { - vk::Result result = device.waitForFences({*inFlightFences[frameIndex]}, VK_TRUE, UINT64_MAX); - if (result != vk::Result::eSuccess) + vk::Result fenceResult = device.waitForFences({*inFlightFences[frameIndex]}, VK_TRUE, UINT64_MAX); + if (fenceResult != vk::Result::eSuccess) { throw std::runtime_error("failed to wait for fence!"); } - uint32_t imageIndex; - try - { - auto [result, idx] = swapChain.acquireNextImage(UINT64_MAX, *imageAvailableSemaphores[frameIndex]); - imageIndex = idx; - } - catch (vk::OutOfDateKHRError &) + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *imageAvailableSemaphores[frameIndex], nullptr); + + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. + if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) + { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); + throw std::runtime_error("failed to acquire swap chain image!"); + } updateUniformBuffer(frameIndex); @@ -1590,36 +1595,23 @@ class HelloTriangleApplication .pSignalSemaphores = &*presentCompleteSemaphore[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphore[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{ - .waitSemaphoreCount = 1, - .pWaitSemaphores = &*presentCompleteSemaphore[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - auto result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/34_android.cpp b/attachments/34_android.cpp index ce26e3ca..89a73ae7 100644 --- a/attachments/34_android.cpp +++ b/attachments/34_android.cpp @@ -1317,17 +1317,22 @@ class HelloTriangleApplication { static_cast(device.waitForFences({*inFlightFences[frameIndex]}, VK_TRUE, UINT64_MAX)); - uint32_t imageIndex; - try - { - auto [result, idx] = swapChain.acquireNextImage(UINT64_MAX, *imageAvailableSemaphores[frameIndex]); - imageIndex = idx; - } - catch (vk::OutOfDateKHRError &) + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *imageAvailableSemaphores[frameIndex], nullptr); + + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. + if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) + { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); + throw std::runtime_error("failed to acquire swap chain image!"); + } // Update uniform buffer with current transformation updateUniformBuffer(frameIndex); @@ -1348,38 +1353,23 @@ class HelloTriangleApplication .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{ - .waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - - vk::Result result = queue.presentKHR(presentInfoKHR); - - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("Failed to present swap chain image"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/attachments/35_gltf_ktx.cpp b/attachments/35_gltf_ktx.cpp index 89b99135..6d741498 100644 --- a/attachments/35_gltf_ktx.cpp +++ b/attachments/35_gltf_ktx.cpp @@ -1401,13 +1401,18 @@ class VulkanApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } updateUniformBuffer(frameIndex); @@ -1426,35 +1431,23 @@ class VulkanApplication .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/36_multiple_objects.cpp b/attachments/36_multiple_objects.cpp index 3949071b..dda1b32d 100644 --- a/attachments/36_multiple_objects.cpp +++ b/attachments/36_multiple_objects.cpp @@ -1534,13 +1534,18 @@ class VulkanApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } @@ -1561,35 +1566,23 @@ class VulkanApplication .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; queue.submit(submitInfo, *inFlightFences[frameIndex]); - try + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; + result = queue.presentKHR(presentInfoKHR); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } - catch (const vk::SystemError &e) + else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/37_multithreading.cpp b/attachments/37_multithreading.cpp index 90c60ff5..3ea2d09c 100644 --- a/attachments/37_multithreading.cpp +++ b/attachments/37_multithreading.cpp @@ -1201,13 +1201,19 @@ class MultithreadedApplication // Acquire the next image auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *imageAvailableSemaphores[frameIndex], nullptr); + + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. else if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } @@ -1326,15 +1332,17 @@ class MultithreadedApplication .pImageIndices = &imageIndex}; result = queue.presentKHR(presentInfo); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { framebufferResized = false; recreateSwapChain(); - return; } - else if (result != vk::Result::eSuccess) + else { - throw std::runtime_error("failed to present swap chain image!"); + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } // Move to the next frame diff --git a/attachments/38_ray_tracing.cpp b/attachments/38_ray_tracing.cpp index d091c4cb..24301e34 100644 --- a/attachments/38_ray_tracing.cpp +++ b/attachments/38_ray_tracing.cpp @@ -1831,13 +1831,18 @@ class VulkanRaytracingApplication auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } + // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. + // On any error code, aquireNextImage already threw an exception. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } updateUniformBuffer(frameIndex); @@ -1866,14 +1871,17 @@ class VulkanRaytracingApplication .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; result = presentQueue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) + // Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result + // here and does not need to be caught by an exception. + if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { framebufferResized = false; recreateSwapChain(); } - else if (result != vk::Result::eSuccess) + else { - throw std::runtime_error("failed to present swap chain image!"); + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } From 18233afef7ebd06e70cf5b97bd19a2715e99134a Mon Sep 17 00:00:00 2001 From: asuessenbach Date: Thu, 8 Jan 2026 15:47:40 +0100 Subject: [PATCH 3/3] Update documentation on swap chain recreation. --- attachments/17_swap_chain_recreation.cpp | 4 +- attachments/18_vertex_input.cpp | 2 + attachments/19_vertex_buffer.cpp | 2 + attachments/20_staging_buffer.cpp | 2 + attachments/21_index_buffer.cpp | 2 + attachments/22_descriptor_layout.cpp | 2 + attachments/23_descriptor_sets.cpp | 2 + attachments/24_texture_image.cpp | 2 + attachments/25_sampler.cpp | 2 + attachments/26_texture_mapping.cpp | 2 + attachments/27_depth_buffering.cpp | 2 + attachments/28_model_loading.cpp | 2 + attachments/29_mipmapping.cpp | 2 + attachments/30_multisampling.cpp | 2 + attachments/32_ecosystem_utilities.cpp | 2 + attachments/33_vulkan_profiles.cpp | 3 +- attachments/34_android.cpp | 3 +- attachments/35_gltf_ktx.cpp | 2 + attachments/36_multiple_objects.cpp | 2 + attachments/38_ray_tracing.cpp | 2 + .../04_Swap_chain_recreation.adoc | 111 +++++++++--------- 21 files changed, 99 insertions(+), 56 deletions(-) diff --git a/attachments/17_swap_chain_recreation.cpp b/attachments/17_swap_chain_recreation.cpp index d35a488b..20657e80 100644 --- a/attachments/17_swap_chain_recreation.cpp +++ b/attachments/17_swap_chain_recreation.cpp @@ -522,13 +522,15 @@ class HelloTriangleApplication } // On other success codes than eSuccess and eSuboptimalKHR we just throw an exception. // On any error code, aquireNextImage already threw an exception. - if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) + else if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/18_vertex_input.cpp b/attachments/18_vertex_input.cpp index 45c4a740..ded31e38 100644 --- a/attachments/18_vertex_input.cpp +++ b/attachments/18_vertex_input.cpp @@ -547,7 +547,9 @@ class HelloTriangleApplication throw std::runtime_error("failed to acquire swap chain image!"); } + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/19_vertex_buffer.cpp b/attachments/19_vertex_buffer.cpp index 27c86671..e726f047 100644 --- a/attachments/19_vertex_buffer.cpp +++ b/attachments/19_vertex_buffer.cpp @@ -583,7 +583,9 @@ class HelloTriangleApplication throw std::runtime_error("failed to acquire swap chain image!"); } + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/20_staging_buffer.cpp b/attachments/20_staging_buffer.cpp index cd253a6f..a641a2c0 100644 --- a/attachments/20_staging_buffer.cpp +++ b/attachments/20_staging_buffer.cpp @@ -603,7 +603,9 @@ class HelloTriangleApplication throw std::runtime_error("failed to acquire swap chain image!"); } + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/21_index_buffer.cpp b/attachments/21_index_buffer.cpp index 9f525f27..2cb13ee1 100644 --- a/attachments/21_index_buffer.cpp +++ b/attachments/21_index_buffer.cpp @@ -629,7 +629,9 @@ class HelloTriangleApplication throw std::runtime_error("failed to acquire swap chain image!"); } + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/22_descriptor_layout.cpp b/attachments/22_descriptor_layout.cpp index 729907b0..30a02dc1 100644 --- a/attachments/22_descriptor_layout.cpp +++ b/attachments/22_descriptor_layout.cpp @@ -689,7 +689,9 @@ class HelloTriangleApplication } updateUniformBuffer(frameIndex); + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/23_descriptor_sets.cpp b/attachments/23_descriptor_sets.cpp index 21f3237b..2b4062ec 100644 --- a/attachments/23_descriptor_sets.cpp +++ b/attachments/23_descriptor_sets.cpp @@ -717,7 +717,9 @@ class HelloTriangleApplication } updateUniformBuffer(frameIndex); + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/24_texture_image.cpp b/attachments/24_texture_image.cpp index 1ece1440..61b26f98 100644 --- a/attachments/24_texture_image.cpp +++ b/attachments/24_texture_image.cpp @@ -826,7 +826,9 @@ class HelloTriangleApplication } updateUniformBuffer(frameIndex); + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/25_sampler.cpp b/attachments/25_sampler.cpp index da0e7da7..5285bfaa 100644 --- a/attachments/25_sampler.cpp +++ b/attachments/25_sampler.cpp @@ -862,7 +862,9 @@ class HelloTriangleApplication } updateUniformBuffer(frameIndex); + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/26_texture_mapping.cpp b/attachments/26_texture_mapping.cpp index bee87017..7c7e1fcf 100644 --- a/attachments/26_texture_mapping.cpp +++ b/attachments/26_texture_mapping.cpp @@ -927,7 +927,9 @@ class HelloTriangleApplication } updateUniformBuffer(frameIndex); + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/27_depth_buffering.cpp b/attachments/27_depth_buffering.cpp index eda15492..e9b23894 100644 --- a/attachments/27_depth_buffering.cpp +++ b/attachments/27_depth_buffering.cpp @@ -1028,7 +1028,9 @@ class HelloTriangleApplication } updateUniformBuffer(frameIndex); + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/28_model_loading.cpp b/attachments/28_model_loading.cpp index a485743b..d6e4712f 100644 --- a/attachments/28_model_loading.cpp +++ b/attachments/28_model_loading.cpp @@ -1084,7 +1084,9 @@ class HelloTriangleApplication } updateUniformBuffer(frameIndex); + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/29_mipmapping.cpp b/attachments/29_mipmapping.cpp index 0ba69637..6760e216 100644 --- a/attachments/29_mipmapping.cpp +++ b/attachments/29_mipmapping.cpp @@ -1154,7 +1154,9 @@ class HelloTriangleApplication } updateUniformBuffer(frameIndex); + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/30_multisampling.cpp b/attachments/30_multisampling.cpp index 7ec0d044..517317ba 100644 --- a/attachments/30_multisampling.cpp +++ b/attachments/30_multisampling.cpp @@ -1217,7 +1217,9 @@ class HelloTriangleApplication } updateUniformBuffer(frameIndex); + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/32_ecosystem_utilities.cpp b/attachments/32_ecosystem_utilities.cpp index 61a5076b..596f424e 100644 --- a/attachments/32_ecosystem_utilities.cpp +++ b/attachments/32_ecosystem_utilities.cpp @@ -1608,7 +1608,9 @@ class HelloTriangleApplication } updateUniformBuffer(frameIndex); + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/33_vulkan_profiles.cpp b/attachments/33_vulkan_profiles.cpp index d8bc9a5f..edb5e9f1 100644 --- a/attachments/33_vulkan_profiles.cpp +++ b/attachments/33_vulkan_profiles.cpp @@ -1579,7 +1579,8 @@ class HelloTriangleApplication updateUniformBuffer(frameIndex); - device.resetFences({*inFlightFences[frameIndex]}); + // Only reset the fence if we are submitting work + device.resetFences(*inFlightFences[frameIndex]); commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/34_android.cpp b/attachments/34_android.cpp index 89a73ae7..af41e8f9 100644 --- a/attachments/34_android.cpp +++ b/attachments/34_android.cpp @@ -1337,7 +1337,8 @@ class HelloTriangleApplication // Update uniform buffer with current transformation updateUniformBuffer(frameIndex); - device.resetFences({*inFlightFences[frameIndex]}); + // Only reset the fence if we are submitting work + device.resetFences(*inFlightFences[frameIndex]); commandBuffers[frameIndex].reset(); recordCommandBuffer(commandBuffers[frameIndex], imageIndex); diff --git a/attachments/35_gltf_ktx.cpp b/attachments/35_gltf_ktx.cpp index 6d741498..1e2f0528 100644 --- a/attachments/35_gltf_ktx.cpp +++ b/attachments/35_gltf_ktx.cpp @@ -1417,7 +1417,9 @@ class VulkanApplication } updateUniformBuffer(frameIndex); + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/36_multiple_objects.cpp b/attachments/36_multiple_objects.cpp index dda1b32d..2ee3aed7 100644 --- a/attachments/36_multiple_objects.cpp +++ b/attachments/36_multiple_objects.cpp @@ -1552,7 +1552,9 @@ class VulkanApplication // Update uniform buffers for all objects updateUniformBuffers(); + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/38_ray_tracing.cpp b/attachments/38_ray_tracing.cpp index 24301e34..c87af500 100644 --- a/attachments/38_ray_tracing.cpp +++ b/attachments/38_ray_tracing.cpp @@ -1851,7 +1851,9 @@ class VulkanRaytracingApplication updateTopLevelAS(ubo.model); #endif // LAB_TASK_LEVEL >= LAB_TASK_AS_ANIMATION + // Only reset the fence if we are submitting work device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); 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 f0a90011..d7d12559 100644 --- a/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc +++ b/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc @@ -79,22 +79,26 @@ You need to pass the previous swap chain to the `oldSwapchain` field in the `VkS Now we just need to figure out when swap chain recreation is necessary and call our new `recreateSwapChain` function. Luckily, Vulkan will usually just tell us that the swap chain is no longer adequate during presentation. -The `vkAcquireNextImageKHR` and `vkQueuePresentKHR` functions can return the following special values to indicate this. +The `vk::raii::SwapchainKHR::acquireNextImage` and `vk::raii::Queue::presentKHR` functions can return the following special values to indicate this. -* `VK_ERROR_OUT_OF_DATE_KHR`: The swap chain has become incompatible with the surface and can no longer be used for rendering. +* `vk::Result::eErrorOutOfDateKHR`: The swap chain has become incompatible with the surface and can no longer be used for rendering. Usually happens after a window resize. -* `VK_SUBOPTIMAL_KHR`: The swap chain can still be used to successfully present to the surface, but the surface properties are no longer matched exactly. +Note that “vk::Result::eErrorOutOfDateKHR” is actually an error code and would trigger an exception by default. By defining “VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS,” this is treated as a success code and can therefore be returned by “vk::raii::SwapchainKHR::acquireNextImage” and “vk::raii::Queue::presentKHR.” +* `vk::Result::eSuboptimalKHR`: The swap chain can still be used to successfully present to the surface, but the surface properties are no longer matched exactly. [,c++] ---- -auto [result, imageIndex] = swapChain.acquireNextImage( UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr ); +auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); -if (result == vk::Result::eErrorOutOfDateKHR) { - recreateSwapChain(); - return; +if (result == vk::Result::eErrorOutOfDateKHR) +{ + recreateSwapChain(); + return; } -if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { - throw std::runtime_error("failed to acquire swap chain image!"); +if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) +{ + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); + throw std::runtime_error("failed to acquire swap chain image!"); } ---- @@ -102,90 +106,89 @@ If the swap chain turns out to be out of date when attempting to acquire an imag Therefore, we should immediately recreate the swap chain and try again in the next `drawFrame` call. 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_SUCCESS` and `VK_SUBOPTIMAL_KHR` are considered "success" return codes. +Both `vk::Result::eSuccess` and `vk::Result::eSuboptimalKHR` are considered "success" return codes. [,c++] ---- -result = presentQueue.presentKHR( presentInfoKHR ); -if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR) { - recreateSwapChain(); -} else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); +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); } frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; ---- -The `vkQueuePresentKHR` function returns the same values with the same meaning. +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. [,c++] ---- -try +const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; +result = queue.presentKHR(presentInfoKHR); +if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized) { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) - { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != vk::Result::eSuccess) - { - throw std::runtime_error("failed to present swap chain image!"); - } + framebufferResized = false; + recreateSwapChain(); } -catch (const vk::SystemError &e) +else { - if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) - { - recreateSwapChain(); - return; - } - else - { - throw; - } + // There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception. + assert(result == vk::Result::eSuccess); } ---- -Recent versions of Vulkan-hpp throw exceptions on unsuccessful return codes. To handle exceptions thrown by `vkQueuePresentKHR`, catch `vk::SystemError` and check the error code as shown above. - == 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 `vkWaitForFences` but never continues past it. -This is because when `vkAcquireNextImageKHR` returns `VK_ERROR_OUT_OF_DATE_KHR`, we recreate the swapchain and then return from `drawFrame`. +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 `vkWaitForFences` to halt forever. +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. There is a simple fix thankfully. Delay resetting the fence until after we know for sure, we will be submitting work with it. -Thus, if we return early, the fence is still signaled and `vkWaitForFences` wont deadlock the next time we use the same fence object. +Thus, if we return early, the fence is still signaled and `vk::raii::Device::waitForFences` wont deadlock the next time we use the same fence object. The beginning of `drawFrame` should now look like this: [,c++] ---- -vkWaitForFences(device, 1, &inFlightFences[frameIndex], VK_TRUE, UINT64_MAX); +auto fenceResult = device.waitForFences(*inFlightFences[frameIndex], vk::True, UINT64_MAX); +if (fenceResult != vk::Result::eSuccess) +{ + throw std::runtime_error("failed to wait for fence!"); +} -uint32_t imageIndex; -VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[frameIndex], VK_NULL_HANDLE, &imageIndex); +auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); -if (result == VK_ERROR_OUT_OF_DATE_KHR) { +if (result == vk::Result::eErrorOutOfDateKHR) +{ recreateSwapChain(); return; -} else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { +} +else if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) +{ + assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady); throw std::runtime_error("failed to acquire swap chain image!"); } // Only reset the fence if we are submitting work -vkResetFences(device, 1, &inFlightFences[frameIndex]); +device.resetFences(*inFlightFences[frameIndex]); ---- == Handling resizes explicitly -Although many drivers and platforms trigger `VK_ERROR_OUT_OF_DATE_KHR` automatically after a window resize, it is not guaranteed to happen. +Although many drivers and platforms trigger `vk::Result::eErrorOutOfDateKHR` automatically after a window resize, it is not guaranteed to happen. That's why we'll add some extra code to also handle resizes explicitly. First, add a new member variable that flags that a resize has happened: @@ -203,12 +206,14 @@ The `drawFrame` function should then be modified to also check for this flag: if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { framebufferResized = false; recreateSwapChain(); -} else if (result != vk::Result::eSuccess) { +} +else +{ ... } ---- -It is important to do this after `vkQueuePresentKHR` to ensure that the semaphores are in a consistent state, otherwise a signaled semaphore may never be properly waited upon. +It is important to do this after `vk::raii::Queue::presentKHR` to ensure that the semaphores are in a consistent state, otherwise a signaled semaphore may never be properly waited upon. Now, to actually detect resizes, we can use the `glfwSetFramebufferSizeCallback` function in the GLFW framework to set up a callback: [,c++]