diff --git a/attachments/15_hello_triangle.cpp b/attachments/15_hello_triangle.cpp index df7406b7..d4edc4f4 100644 --- a/attachments/15_hello_triangle.cpp +++ b/attachments/15_hello_triangle.cpp @@ -467,8 +467,11 @@ class HelloTriangleApplication vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore, .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffer, .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore}; queue.submit(submitInfo, *drawFence); - while (vk::Result::eTimeout == device.waitForFences(*drawFence, vk::True, UINT64_MAX)) - ; + result = device.waitForFences(*drawFence, vk::True, UINT64_MAX); + if (result != vk::Result::eSuccess) + { + throw std::runtime_error("failed to wait for fence!"); + } const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore, .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; result = queue.presentKHR(presentInfoKHR); diff --git a/attachments/16_frames_in_flight.cpp b/attachments/16_frames_in_flight.cpp index b965a0df..a5095b44 100644 --- a/attachments/16_frames_in_flight.cpp +++ b/attachments/16_frames_in_flight.cpp @@ -471,8 +471,11 @@ class HelloTriangleApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/attachments/17_swap_chain_recreation.cpp b/attachments/17_swap_chain_recreation.cpp index cdce724d..cbe6b2dd 100644 --- a/attachments/17_swap_chain_recreation.cpp +++ b/attachments/17_swap_chain_recreation.cpp @@ -505,8 +505,11 @@ class HelloTriangleApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); @@ -521,7 +524,6 @@ class HelloTriangleApplication throw std::runtime_error("failed to acquire swap chain image!"); } - device.resetFences(*inFlightFences[frameIndex]); commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); diff --git a/attachments/18_vertex_input.cpp b/attachments/18_vertex_input.cpp index 881dee65..ae6dc48a 100644 --- a/attachments/18_vertex_input.cpp +++ b/attachments/18_vertex_input.cpp @@ -524,8 +524,11 @@ class HelloTriangleApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/attachments/19_vertex_buffer.cpp b/attachments/19_vertex_buffer.cpp index 06bafaf4..15989885 100644 --- a/attachments/19_vertex_buffer.cpp +++ b/attachments/19_vertex_buffer.cpp @@ -560,8 +560,11 @@ class HelloTriangleApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/attachments/20_staging_buffer.cpp b/attachments/20_staging_buffer.cpp index 8f1f9ea3..2c53030d 100644 --- a/attachments/20_staging_buffer.cpp +++ b/attachments/20_staging_buffer.cpp @@ -580,8 +580,11 @@ class HelloTriangleApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/attachments/21_index_buffer.cpp b/attachments/21_index_buffer.cpp index d5ca4403..0b8f65ad 100644 --- a/attachments/21_index_buffer.cpp +++ b/attachments/21_index_buffer.cpp @@ -606,8 +606,11 @@ class HelloTriangleApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/attachments/22_descriptor_layout.cpp b/attachments/22_descriptor_layout.cpp index 4b56793e..f5fd719f 100644 --- a/attachments/22_descriptor_layout.cpp +++ b/attachments/22_descriptor_layout.cpp @@ -665,8 +665,11 @@ class HelloTriangleApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/attachments/23_descriptor_sets.cpp b/attachments/23_descriptor_sets.cpp index 82db8f14..86941754 100644 --- a/attachments/23_descriptor_sets.cpp +++ b/attachments/23_descriptor_sets.cpp @@ -693,8 +693,11 @@ class HelloTriangleApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/attachments/24_texture_image.cpp b/attachments/24_texture_image.cpp index 88302662..7816c45b 100644 --- a/attachments/24_texture_image.cpp +++ b/attachments/24_texture_image.cpp @@ -802,8 +802,11 @@ class HelloTriangleApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/attachments/25_sampler.cpp b/attachments/25_sampler.cpp index 7a6437a2..eee63145 100644 --- a/attachments/25_sampler.cpp +++ b/attachments/25_sampler.cpp @@ -838,8 +838,11 @@ class HelloTriangleApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/attachments/26_texture_mapping.cpp b/attachments/26_texture_mapping.cpp index e5e1db67..d51cc788 100644 --- a/attachments/26_texture_mapping.cpp +++ b/attachments/26_texture_mapping.cpp @@ -903,8 +903,11 @@ class HelloTriangleApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/attachments/27_depth_buffering.cpp b/attachments/27_depth_buffering.cpp index d56aca06..b7d60670 100644 --- a/attachments/27_depth_buffering.cpp +++ b/attachments/27_depth_buffering.cpp @@ -1004,8 +1004,11 @@ class HelloTriangleApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/attachments/28_model_loading.cpp b/attachments/28_model_loading.cpp index 4fc391ce..448ac1c8 100644 --- a/attachments/28_model_loading.cpp +++ b/attachments/28_model_loading.cpp @@ -1060,8 +1060,11 @@ class HelloTriangleApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/attachments/29_mipmapping.cpp b/attachments/29_mipmapping.cpp index cbaea33f..d796e68a 100644 --- a/attachments/29_mipmapping.cpp +++ b/attachments/29_mipmapping.cpp @@ -1130,8 +1130,11 @@ class HelloTriangleApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/attachments/30_multisampling.cpp b/attachments/30_multisampling.cpp index 0a22fcfd..7ee65259 100644 --- a/attachments/30_multisampling.cpp +++ b/attachments/30_multisampling.cpp @@ -1193,8 +1193,11 @@ class HelloTriangleApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/attachments/31_compute_shader.cpp b/attachments/31_compute_shader.cpp index 0b6369e7..6b38a90a 100644 --- a/attachments/31_compute_shader.cpp +++ b/attachments/31_compute_shader.cpp @@ -811,8 +811,11 @@ class ComputeShaderApplication void drawFrame() { auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, nullptr, *inFlightFences[frameIndex]); - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); // Update timeline value for this frame @@ -877,8 +880,11 @@ class ComputeShaderApplication .pValues = &graphicsSignalValue}; // Wait for graphics to complete before presenting - while (vk::Result::eTimeout == device.waitSemaphores(waitInfo, UINT64_MAX)) - ; + auto result = device.waitSemaphores(waitInfo, UINT64_MAX); + if (result != vk::Result::eSuccess) + { + throw std::runtime_error("failed to wait for semaphore!"); + } vk::PresentInfoKHR presentInfo{ .waitSemaphoreCount = 0, // No binary semaphores needed diff --git a/attachments/32_ecosystem_utilities.cpp b/attachments/32_ecosystem_utilities.cpp index f7bc8ae1..22a67e5b 100644 --- a/attachments/32_ecosystem_utilities.cpp +++ b/attachments/32_ecosystem_utilities.cpp @@ -1584,8 +1584,11 @@ class HelloTriangleApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/attachments/33_vulkan_profiles.cpp b/attachments/33_vulkan_profiles.cpp index 8d8a9402..a0627897 100644 --- a/attachments/33_vulkan_profiles.cpp +++ b/attachments/33_vulkan_profiles.cpp @@ -1554,7 +1554,11 @@ class HelloTriangleApplication void drawFrame() { - static_cast(device.waitForFences({*inFlightFences[frameIndex]}, VK_TRUE, UINT64_MAX)); + vk::Result result = device.waitForFences({*inFlightFences[frameIndex]}, VK_TRUE, UINT64_MAX); + if (result != vk::Result::eSuccess) + { + throw std::runtime_error("failed to wait for fence!"); + } uint32_t imageIndex; try diff --git a/attachments/35_gltf_ktx.cpp b/attachments/35_gltf_ktx.cpp index 98b100b1..48b68d2c 100644 --- a/attachments/35_gltf_ktx.cpp +++ b/attachments/35_gltf_ktx.cpp @@ -1393,8 +1393,11 @@ class VulkanApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/attachments/36_multiple_objects.cpp b/attachments/36_multiple_objects.cpp index c676510d..f0a62176 100644 --- a/attachments/36_multiple_objects.cpp +++ b/attachments/36_multiple_objects.cpp @@ -1526,8 +1526,11 @@ class VulkanApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/attachments/37_multithreading.cpp b/attachments/37_multithreading.cpp index ab664963..90c60ff5 100644 --- a/attachments/37_multithreading.cpp +++ b/attachments/37_multithreading.cpp @@ -1185,8 +1185,11 @@ class MultithreadedApplication void drawFrame() { // Wait for the previous frame to finish - while (vk::Result::eTimeout == 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!"); + } // If the framebuffer was resized, rebuild the swap chain before acquiring a new image if (framebufferResized) diff --git a/attachments/38_ray_tracing.cpp b/attachments/38_ray_tracing.cpp index 4987517b..112e436c 100644 --- a/attachments/38_ray_tracing.cpp +++ b/attachments/38_ray_tracing.cpp @@ -1823,8 +1823,11 @@ class VulkanRaytracingApplication { // Note: inFlightFences, presentCompleteSemaphores, and commandBuffers are indexed by frameIndex, // while renderFinishedSemaphores is indexed by imageIndex - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/en/03_Drawing_a_triangle/03_Drawing/02_Rendering_and_presentation.adoc b/en/03_Drawing_a_triangle/03_Drawing/02_Rendering_and_presentation.adoc index 3574eb5e..a9b6d402 100644 --- a/en/03_Drawing_a_triangle/03_Drawing/02_Rendering_and_presentation.adoc +++ b/en/03_Drawing_a_triangle/03_Drawing/02_Rendering_and_presentation.adoc @@ -192,7 +192,7 @@ void createSyncObjects() { } ---- -Creating semaphores requires filling in the `VkSemaphoreCreateInfo`, but in the current version of the API it doesn't actually have any required fields besides `sType`: +Creating semaphores requires filling in the `vk::SemaphoreCreateInfo`, but in the current version of the API it doesn't actually have any fields relevant to the tutorial: [,c++] ---- @@ -210,36 +210,43 @@ Onto the main drawing function! == Waiting for the previous frame At the start of the frame, we want to wait until the previous frame has finished, so that the command buffer and semaphores are available to use. -To do that, we call `vkWaitForFences`: +To do that, we call `device.waitForFences`: [,c++] ---- void drawFrame() { - auto [result, imageIndex] = swapChain.acquireNextImage( UINT64_MAX, *presentCompleteSemaphore, nullptr ); + auto fenceResult = device.waitForFences(*drawFence, vk::True, UINT64_MAX); } ---- -First, let's grab an image from the framebuffer after the previous frame has -finished. -The first two parameters of `vkAcquireNextImageKHR` are the logical device and the swap chain from which we wish to acquire an image. -The third parameter specifies a timeout in nanoseconds for an image to become available. +The `waitForFences` function takes an array of fences and waits on the host for either any or all of the fences to be signaled before returning. +The `vk::True` we pass here indicates that we want to wait for all fences, but in the case of a single one it doesn't matter. +This function also has a timeout parameter that we set to the maximum value of a 64 bit unsigned integer, `UINT64_MAX`, which effectively disables the timeout. + +Next, let's grab an image from the framebuffer after the previous frame has +finished: + +[,c++] +---- +void drawFrame() { + ... + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); +} +---- + +The first parameter specifies a timeout in nanoseconds for an image to become available. Using the maximum value of a 64-bit unsigned integer means we effectively disable the timeout. The next two parameters specify synchronization objects that are to be signaled when the presentation engine is finished using the image. That's the point in time where we can start drawing to it. It is possible to specify a semaphore, fence or both. -We're going to use our `imageAvailableSemaphore` for that purpose here. +We're going to use our `presentCompleteSemaphores` for that purpose here. The last parameter specifies a variable to output the index of the swap chain image that has become available. The index refers to the `VkImage` in our `swapChainImages` array. We're going to use that index to pick the `VkFrameBuffer`. Then we'll record into that framebuffer. -The `vkWaitForFences` function takes an array of fences and waits on the host for either any or all of the fences to be signaled before returning. -The `VK_TRUE` we pass here indicates that we want to wait for all fences, but in the case of a single one it doesn't matter. -This function also has a timeout parameter that we set to the maximum value of a 64 bit unsigned integer, `UINT64_MAX`, which effectively disables the timeout. - - == Recording the command buffer With the imageIndex specifying the swap chain image to use in hand, we can now record the command buffer. @@ -255,19 +262,26 @@ already happened, so we know to wait on it later. [,c++] ---- -device.resetFences( *drawFence ); +device.resetFences(*drawFence); ---- With a fully recorded command buffer, we can now submit it. == Submitting the command buffer -Queue submission and synchronization is configured through parameters in the `VkSubmitInfo` structure. +Queue submission and synchronization is configured through parameters in the `vk::SubmitInfo` structure. [,c++] ---- vk::PipelineStageFlags waitDestinationStageMask( vk::PipelineStageFlagBits::eColorAttachmentOutput ); -const vk::SubmitInfo submitInfo( **presentCompleteSemaphore, waitDestinationStageMask, **commandBuffer, **renderFinishedSemaphore ); +const vk::SubmitInfo submitInfo{ + .waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphore, + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffer, + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphore}; ---- The first three parameters specify which semaphores to wait on before execution begins and in which stage(s) of the pipeline to wait. @@ -287,18 +301,10 @@ In our case we're using the `renderFinishedSemaphore` for that purpose. graphicsQueue.submit(submitInfo, *drawFence); ---- -We can now submit the command buffer to the graphics queue using `vkQueueSubmit`. -The function takes an array of `VkSubmitInfo` structures as argument for efficiency when the workload is much larger. +We can now submit the command buffer to the graphics queue using `submit`. +The function takes an array of `vk::SubmitInfo` structures as argument for efficiency when the workload is much larger. The last parameter references an optional fence that will be signaled when the command buffers finish execution. -This allows us to know when it is safe for the command buffer to be reused, thus we want to give it `drawFence`. -Now we want the CPU to wait while the GPU finishes rendering that frame we -just submitted: - -[,c++] ----- -while ( vk::Result::eTimeout == device.waitForFences( *drawFence, vk::True, UINT64_MAX ) ) - ; ----- +This allows us to know when it is safe for the command buffer to be reused, thus we want to give it `drawFence`, which is waited on in the next frame. == Subpass dependencies @@ -357,14 +363,19 @@ link:/attachments/15_hello_triangle.cpp[demo code.] == Presentation The last step of drawing a frame is submitting the result back to the swap chain to have it eventually show up on the screen. -Presentation is configured through a `VkPresentInfoKHR` structure at the end of the `drawFrame` function. +Presentation is configured through a `vk::PresentInfoKHR` structure at the end of the `drawFrame` function. [,c++] ---- -const vk::PresentInfoKHR presentInfoKHR( **renderFinishedSemaphore, **swapChain, imageIndex ); +const vk::PresentInfoKHR presentInfoKHR{ + .waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphore, + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; ---- -The first two parameters specify which semaphores to wait on before presentation can happen, just like `VkSubmitInfo`. +The first two parameters specify which semaphores to wait on before presentation can happen, just like `vk::SubmitInfo`. Since we want to wait on the command buffer to finish execution, thus our triangle being drawn, we take the semaphores which will be signaled and wait on them, thus we use `signalSemaphores`. The next two parameters specify the swap chains to present images to and the index of the image for each swap chain. @@ -376,16 +387,16 @@ presentInfo.pResults = nullptr; // Optional ---- There is one last optional parameter called `pResults`. -It allows you to specify an array of `VkResult` values to check for every swap chain if presentation was successful. +It allows you to specify an array of `vk::Result` values to check for every swap chain if presentation was successful. It's not necessary if you're only using a single swap chain, because you can use the return value of the present function. [,c++] ---- -result = presentQueue.presentKHR( presentInfoKHR ); +result = presentQueue.presentKHR(presentInfoKHR); ---- -The `vkQueuePresentKHR` function submits the request to present an image to the swap chain. -We'll add error handling for both `vkAcquireNextImageKHR` and `vkQueuePresentKHR` in the next chapter, because their failure does not necessarily mean that the program should terminate, unlike the functions we've seen so far. +The `presentKHR` function submits the request to present an image to the swap chain. +We'll add error handling for both `swapChain.acquireNextImage` and `queue.presentKHR` in the next chapter, because their failure does not necessarily mean that the program should terminate, unlike the functions we've seen so far. If you did everything correctly up to this point, then you should now see something resembling the following when you run your program: diff --git a/en/03_Drawing_a_triangle/03_Drawing/03_Frames_in_flight.adoc b/en/03_Drawing_a_triangle/03_Drawing/03_Frames_in_flight.adoc index 45cbec26..82813042 100644 --- a/en/03_Drawing_a_triangle/03_Drawing/03_Frames_in_flight.adoc +++ b/en/03_Drawing_a_triangle/03_Drawing/03_Frames_in_flight.adoc @@ -88,8 +88,11 @@ The `drawFrame` function can now be modified to use the right objects: [,c++] ---- void drawFrame() { - while (vk::Result::eTimeout == 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!"); + } device.resetFences(*inFlightFences[frameIndex]); auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); diff --git a/en/11_Compute_Shader.adoc b/en/11_Compute_Shader.adoc index f0e918ed..84ca031e 100644 --- a/en/11_Compute_Shader.adoc +++ b/en/11_Compute_Shader.adoc @@ -769,8 +769,11 @@ vk::SemaphoreWaitInfo waitInfo{ }; // Wait for graphics to complete before presenting -while (vk::Result::eTimeout == device.waitSemaphores(waitInfo, UINT64_MAX)) - ; +auto result = device.waitSemaphores(waitInfo, UINT64_MAX); +if (result != vk::Result::eSuccess) +{ + throw std::runtime_error("failed to wait for semaphore!"); +} vk::PresentInfoKHR presentInfo{ .waitSemaphoreCount = 0, // No binary semaphores needed diff --git a/en/17_Multithreading.adoc b/en/17_Multithreading.adoc index 92f9de2b..cb5c4ee2 100644 --- a/en/17_Multithreading.adoc +++ b/en/17_Multithreading.adoc @@ -297,8 +297,11 @@ Finally, we'll update our main loop to coordinate the worker threads: ---- void drawFrame() { // Wait for the previous frame to finish - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[frameIndex], vk::True, UINT64_MAX)); - device.resetFences(*inFlightFences[frameIndex]); + auto fenceResult = device.waitForFences(*inFlightFences[frameIndex], vk::True, UINT64_MAX); + if (fenceResult != vk::Result::eSuccess) + { + throw std::runtime_error("failed to wait for fence!"); + } // Acquire the next image auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *imageAvailableSemaphores[frameIndex], nullptr); @@ -352,6 +355,7 @@ void drawFrame() { { std::lock_guard lock(queueSubmitMutex); + device.resetFences(*inFlightFences[frameIndex]); graphicsQueue.submit(graphicsSubmitInfo, *inFlightFences[frameIndex]); }