diff --git a/attachments/15_hello_triangle.cpp b/attachments/15_hello_triangle.cpp index 1848011e..b6036460 100644 --- a/attachments/15_hello_triangle.cpp +++ b/attachments/15_hello_triangle.cpp @@ -417,7 +417,7 @@ class HelloTriangleApplication } void transition_image_layout( - uint32_t currentFrame, + uint32_t imageIndex, vk::ImageLayout old_layout, vk::ImageLayout new_layout, vk::AccessFlags2 src_access_mask, @@ -434,7 +434,7 @@ class HelloTriangleApplication .newLayout = new_layout, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = swapChainImages[currentFrame], + .image = swapChainImages[imageIndex], .subresourceRange = { .aspectMask = vk::ImageAspectFlagBits::eColor, .baseMipLevel = 0, diff --git a/attachments/16_frames_in_flight.cpp b/attachments/16_frames_in_flight.cpp index 5e6725c2..8c65b06b 100644 --- a/attachments/16_frames_in_flight.cpp +++ b/attachments/16_frames_in_flight.cpp @@ -64,11 +64,10 @@ class HelloTriangleApplication vk::raii::CommandPool commandPool = nullptr; std::vector commandBuffers; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t semaphoreIndex = 0; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; std::vector requiredDeviceExtension = { vk::KHRSwapchainExtensionName, @@ -377,7 +376,8 @@ class HelloTriangleApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( imageIndex, @@ -400,12 +400,12 @@ class HelloTriangleApplication .layerCount = 1, .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].draw(3, 1, 0, 0); - commandBuffers[currentFrame].endRendering(); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.draw(3, 1, 0, 0); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( imageIndex, @@ -416,7 +416,7 @@ class HelloTriangleApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe // dstStage ); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -448,42 +448,53 @@ class HelloTriangleApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[semaphoreIndex], nullptr); + device.resetFences(*inFlightFences[frameIndex]); - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[semaphoreIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); - - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); + + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; result = queue.presentKHR(presentInfoKHR); switch (result) { @@ -495,8 +506,7 @@ class HelloTriangleApplication default: break; // an unexpected result is returned! } - semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); - currentFrame = (currentFrame + 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/17_swap_chain_recreation.cpp b/attachments/17_swap_chain_recreation.cpp index 6f7f5b1b..0079b781 100644 --- a/attachments/17_swap_chain_recreation.cpp +++ b/attachments/17_swap_chain_recreation.cpp @@ -64,11 +64,10 @@ class HelloTriangleApplication vk::raii::CommandPool commandPool = nullptr; std::vector commandBuffers; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t semaphoreIndex = 0; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; @@ -411,7 +410,8 @@ class HelloTriangleApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( imageIndex, @@ -434,12 +434,12 @@ class HelloTriangleApplication .layerCount = 1, .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].draw(3, 1, 0, 0); - commandBuffers[currentFrame].endRendering(); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.draw(3, 1, 0, 0); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( imageIndex, @@ -450,7 +450,7 @@ class HelloTriangleApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe // dstStage ); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -482,32 +482,34 @@ class HelloTriangleApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[semaphoreIndex], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -519,19 +521,29 @@ class HelloTriangleApplication throw std::runtime_error("failed to acquire swap chain image!"); } - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + device.resetFences(*inFlightFences[frameIndex]); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[semaphoreIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; + 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) + if (result == vk::Result::eSuboptimalKHR || framebufferResized) { framebufferResized = false; recreateSwapChain(); @@ -553,8 +565,7 @@ class HelloTriangleApplication throw; } } - semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); - currentFrame = (currentFrame + 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/18_vertex_input.cpp b/attachments/18_vertex_input.cpp index 2aaa6406..2ae5adff 100644 --- a/attachments/18_vertex_input.cpp +++ b/attachments/18_vertex_input.cpp @@ -89,11 +89,10 @@ class HelloTriangleApplication vk::raii::CommandPool commandPool = nullptr; std::vector commandBuffers; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t semaphoreIndex = 0; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; @@ -430,7 +429,8 @@ class HelloTriangleApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( imageIndex, @@ -453,12 +453,12 @@ class HelloTriangleApplication .layerCount = 1, .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].draw(3, 1, 0, 0); - commandBuffers[currentFrame].endRendering(); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.draw(3, 1, 0, 0); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( imageIndex, @@ -469,7 +469,7 @@ class HelloTriangleApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe // dstStage ); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -501,32 +501,34 @@ class HelloTriangleApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[semaphoreIndex], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -538,17 +540,26 @@ class HelloTriangleApplication throw std::runtime_error("failed to acquire swap chain image!"); } - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[semaphoreIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; + 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) { @@ -572,8 +583,7 @@ class HelloTriangleApplication throw; } } - semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); - currentFrame = (currentFrame + 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 169a5332..17a1310e 100644 --- a/attachments/19_vertex_buffer.cpp +++ b/attachments/19_vertex_buffer.cpp @@ -92,11 +92,10 @@ class HelloTriangleApplication vk::raii::CommandPool commandPool = nullptr; std::vector commandBuffers; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t semaphoreIndex = 0; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; @@ -465,7 +464,8 @@ class HelloTriangleApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( imageIndex, @@ -488,13 +488,13 @@ class HelloTriangleApplication .layerCount = 1, .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].draw(3, 1, 0, 0); - commandBuffers[currentFrame].endRendering(); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffer.draw(3, 1, 0, 0); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( imageIndex, @@ -505,7 +505,7 @@ class HelloTriangleApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe // dstStage ); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -537,32 +537,34 @@ class HelloTriangleApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[semaphoreIndex], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -574,17 +576,26 @@ class HelloTriangleApplication throw std::runtime_error("failed to acquire swap chain image!"); } - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[semaphoreIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; + 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) { @@ -608,8 +619,7 @@ class HelloTriangleApplication throw; } } - semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); - currentFrame = (currentFrame + 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/20_staging_buffer.cpp b/attachments/20_staging_buffer.cpp index 0f8bd493..d5c1be50 100644 --- a/attachments/20_staging_buffer.cpp +++ b/attachments/20_staging_buffer.cpp @@ -92,11 +92,10 @@ class HelloTriangleApplication vk::raii::CommandPool commandPool = nullptr; std::vector commandBuffers; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t semaphoreIndex = 0; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; @@ -485,7 +484,8 @@ class HelloTriangleApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( imageIndex, @@ -508,13 +508,13 @@ class HelloTriangleApplication .layerCount = 1, .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].draw(3, 1, 0, 0); - commandBuffers[currentFrame].endRendering(); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffer.draw(3, 1, 0, 0); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( imageIndex, @@ -525,7 +525,7 @@ class HelloTriangleApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe // dstStage ); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -557,32 +557,34 @@ class HelloTriangleApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[semaphoreIndex], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -594,17 +596,26 @@ class HelloTriangleApplication throw std::runtime_error("failed to acquire swap chain image!"); } - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[semaphoreIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; + 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) { @@ -628,8 +639,7 @@ class HelloTriangleApplication throw; } } - semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); - currentFrame = (currentFrame + 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/21_index_buffer.cpp b/attachments/21_index_buffer.cpp index 1b589051..9866806a 100644 --- a/attachments/21_index_buffer.cpp +++ b/attachments/21_index_buffer.cpp @@ -98,11 +98,10 @@ class HelloTriangleApplication vk::raii::CommandPool commandPool = nullptr; std::vector commandBuffers; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t semaphoreIndex = 0; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; @@ -510,7 +509,8 @@ class HelloTriangleApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( imageIndex, @@ -533,14 +533,14 @@ class HelloTriangleApplication .layerCount = 1, .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].bindIndexBuffer(*indexBuffer, 0, vk::IndexTypeValue::value); - commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0); - commandBuffers[currentFrame].endRendering(); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexTypeValue::value); + commandBuffer.drawIndexed(indices.size(), 1, 0, 0, 0); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( imageIndex, @@ -551,7 +551,7 @@ class HelloTriangleApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe // dstStage ); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -583,32 +583,34 @@ class HelloTriangleApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[semaphoreIndex], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -620,17 +622,26 @@ class HelloTriangleApplication throw std::runtime_error("failed to acquire swap chain image!"); } - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[semaphoreIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; + 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) { @@ -654,8 +665,7 @@ class HelloTriangleApplication throw; } } - semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); - currentFrame = (currentFrame + 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/22_descriptor_layout.cpp b/attachments/22_descriptor_layout.cpp index 9e93618d..fd807e59 100644 --- a/attachments/22_descriptor_layout.cpp +++ b/attachments/22_descriptor_layout.cpp @@ -114,11 +114,10 @@ class HelloTriangleApplication vk::raii::CommandPool commandPool = nullptr; std::vector commandBuffers; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t semaphoreIndex = 0; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; @@ -553,7 +552,8 @@ class HelloTriangleApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( imageIndex, @@ -576,14 +576,14 @@ class HelloTriangleApplication .layerCount = 1, .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].bindIndexBuffer(*indexBuffer, 0, vk::IndexTypeValue::value); - commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0); - commandBuffers[currentFrame].endRendering(); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexTypeValue::value); + commandBuffer.drawIndexed(indices.size(), 1, 0, 0, 0); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( imageIndex, @@ -594,7 +594,7 @@ class HelloTriangleApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe // dstStage ); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -626,23 +626,21 @@ class HelloTriangleApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } @@ -665,9 +663,13 @@ class HelloTriangleApplication void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[semaphoreIndex], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -678,19 +680,28 @@ class HelloTriangleApplication { throw std::runtime_error("failed to acquire swap chain image!"); } - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[semaphoreIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; + 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) { @@ -714,8 +725,7 @@ class HelloTriangleApplication throw; } } - semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); - currentFrame = (currentFrame + 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/23_descriptor_sets.cpp b/attachments/23_descriptor_sets.cpp index 0bb63cd0..096e655d 100644 --- a/attachments/23_descriptor_sets.cpp +++ b/attachments/23_descriptor_sets.cpp @@ -117,11 +117,10 @@ class HelloTriangleApplication vk::raii::CommandPool commandPool = nullptr; std::vector commandBuffers; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t semaphoreIndex = 0; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; @@ -580,7 +579,8 @@ class HelloTriangleApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( imageIndex, @@ -603,15 +603,15 @@ class HelloTriangleApplication .layerCount = 1, .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint16); - commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[currentFrame], nullptr); - commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0); - commandBuffers[currentFrame].endRendering(); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint16); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[frameIndex], nullptr); + commandBuffer.drawIndexed(indices.size(), 1, 0, 0, 0); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( imageIndex, @@ -622,7 +622,7 @@ class HelloTriangleApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe // dstStage ); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -654,23 +654,21 @@ class HelloTriangleApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } @@ -693,9 +691,13 @@ class HelloTriangleApplication void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[semaphoreIndex], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -706,19 +708,28 @@ class HelloTriangleApplication { throw std::runtime_error("failed to acquire swap chain image!"); } - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[semaphoreIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; + 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) { @@ -742,8 +753,7 @@ class HelloTriangleApplication throw; } } - semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); - currentFrame = (currentFrame + 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/24_texture_image.cpp b/attachments/24_texture_image.cpp index 066e9e07..7b523383 100644 --- a/attachments/24_texture_image.cpp +++ b/attachments/24_texture_image.cpp @@ -123,11 +123,10 @@ class HelloTriangleApplication vk::raii::CommandPool commandPool = nullptr; std::vector commandBuffers; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t semaphoreIndex = 0; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; @@ -689,7 +688,8 @@ class HelloTriangleApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( imageIndex, @@ -712,15 +712,15 @@ class HelloTriangleApplication .layerCount = 1, .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint16); - commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[currentFrame], nullptr); - commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0); - commandBuffers[currentFrame].endRendering(); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint16); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[frameIndex], nullptr); + commandBuffer.drawIndexed(indices.size(), 1, 0, 0, 0); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( imageIndex, @@ -731,7 +731,7 @@ class HelloTriangleApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe // dstStage ); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -763,23 +763,21 @@ class HelloTriangleApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } @@ -802,9 +800,13 @@ class HelloTriangleApplication void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[semaphoreIndex], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -815,19 +817,28 @@ class HelloTriangleApplication { throw std::runtime_error("failed to acquire swap chain image!"); } - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[semaphoreIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; + 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) { @@ -851,8 +862,7 @@ class HelloTriangleApplication throw; } } - semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); - currentFrame = (currentFrame + 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/25_sampler.cpp b/attachments/25_sampler.cpp index 7e644e2d..7f422b95 100644 --- a/attachments/25_sampler.cpp +++ b/attachments/25_sampler.cpp @@ -125,11 +125,10 @@ class HelloTriangleApplication vk::raii::CommandPool commandPool = nullptr; std::vector commandBuffers; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t semaphoreIndex = 0; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; @@ -725,7 +724,8 @@ class HelloTriangleApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( imageIndex, @@ -748,15 +748,15 @@ class HelloTriangleApplication .layerCount = 1, .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint16); - commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[currentFrame], nullptr); - commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0); - commandBuffers[currentFrame].endRendering(); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint16); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[frameIndex], nullptr); + commandBuffer.drawIndexed(indices.size(), 1, 0, 0, 0); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( imageIndex, @@ -767,7 +767,7 @@ class HelloTriangleApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe // dstStage ); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -799,23 +799,21 @@ class HelloTriangleApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } @@ -838,9 +836,13 @@ class HelloTriangleApplication void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[semaphoreIndex], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -851,19 +853,28 @@ class HelloTriangleApplication { throw std::runtime_error("failed to acquire swap chain image!"); } - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[semaphoreIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; + 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) { @@ -887,8 +898,7 @@ class HelloTriangleApplication throw; } } - semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); - currentFrame = (currentFrame + 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/26_texture_mapping.cpp b/attachments/26_texture_mapping.cpp index ea516cd1..80f862c7 100644 --- a/attachments/26_texture_mapping.cpp +++ b/attachments/26_texture_mapping.cpp @@ -127,11 +127,10 @@ class HelloTriangleApplication vk::raii::CommandPool commandPool = nullptr; std::vector commandBuffers; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t semaphoreIndex = 0; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; @@ -790,7 +789,8 @@ class HelloTriangleApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( imageIndex, @@ -813,15 +813,15 @@ class HelloTriangleApplication .layerCount = 1, .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint16); - commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[currentFrame], nullptr); - commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0); - commandBuffers[currentFrame].endRendering(); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint16); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[frameIndex], nullptr); + commandBuffer.drawIndexed(indices.size(), 1, 0, 0, 0); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( imageIndex, @@ -832,7 +832,7 @@ class HelloTriangleApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe // dstStage ); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -864,23 +864,21 @@ class HelloTriangleApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } @@ -903,9 +901,13 @@ class HelloTriangleApplication void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[semaphoreIndex], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -916,19 +918,28 @@ class HelloTriangleApplication { throw std::runtime_error("failed to acquire swap chain image!"); } - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[semaphoreIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; + 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) { @@ -952,8 +963,7 @@ class HelloTriangleApplication throw; } } - semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); - currentFrame = (currentFrame + 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/27_depth_buffering.cpp b/attachments/27_depth_buffering.cpp index 98a46715..ada64ce0 100644 --- a/attachments/27_depth_buffering.cpp +++ b/attachments/27_depth_buffering.cpp @@ -138,11 +138,10 @@ class HelloTriangleApplication vk::raii::CommandPool commandPool = nullptr; std::vector commandBuffers; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t semaphoreIndex = 0; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; @@ -870,7 +869,8 @@ class HelloTriangleApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( swapChainImages[imageIndex], @@ -915,15 +915,15 @@ class HelloTriangleApplication .colorAttachmentCount = 1, .pColorAttachments = &colorAttachmentInfo, .pDepthAttachment = &depthAttachmentInfo}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint16); - commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[currentFrame], nullptr); - commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0); - commandBuffers[currentFrame].endRendering(); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint16); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[frameIndex], nullptr); + commandBuffer.drawIndexed(indices.size(), 1, 0, 0, 0); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( swapChainImages[imageIndex], @@ -934,7 +934,7 @@ class HelloTriangleApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe, // dstStage vk::ImageAspectFlagBits::eColor); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -967,23 +967,21 @@ class HelloTriangleApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } @@ -1006,9 +1004,13 @@ class HelloTriangleApplication void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[semaphoreIndex], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -1019,19 +1021,28 @@ class HelloTriangleApplication { throw std::runtime_error("failed to acquire swap chain image!"); } - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[semaphoreIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; + 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) { @@ -1055,8 +1066,7 @@ class HelloTriangleApplication throw; } } - semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); - currentFrame = (currentFrame + 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/28_model_loading.cpp b/attachments/28_model_loading.cpp index 6a9f0ed1..200deb09 100644 --- a/attachments/28_model_loading.cpp +++ b/attachments/28_model_loading.cpp @@ -146,11 +146,10 @@ class HelloTriangleApplication vk::raii::CommandPool commandPool = nullptr; std::vector commandBuffers; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t semaphoreIndex = 0; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; @@ -926,7 +925,8 @@ class HelloTriangleApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( swapChainImages[imageIndex], @@ -971,15 +971,15 @@ class HelloTriangleApplication .colorAttachmentCount = 1, .pColorAttachments = &colorAttachmentInfo, .pDepthAttachment = &depthAttachmentInfo}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); - commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[currentFrame], nullptr); - commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0); - commandBuffers[currentFrame].endRendering(); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[frameIndex], nullptr); + commandBuffer.drawIndexed(indices.size(), 1, 0, 0, 0); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( swapChainImages[imageIndex], @@ -990,7 +990,7 @@ class HelloTriangleApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe, // dstStage vk::ImageAspectFlagBits::eColor); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -1023,23 +1023,21 @@ class HelloTriangleApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } @@ -1062,9 +1060,13 @@ class HelloTriangleApplication void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[semaphoreIndex], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -1075,19 +1077,28 @@ class HelloTriangleApplication { throw std::runtime_error("failed to acquire swap chain image!"); } - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[semaphoreIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; + 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) { @@ -1111,8 +1122,7 @@ class HelloTriangleApplication throw; } } - semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); - currentFrame = (currentFrame + 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/29_mipmapping.cpp b/attachments/29_mipmapping.cpp index 798ac1ba..f9c78533 100644 --- a/attachments/29_mipmapping.cpp +++ b/attachments/29_mipmapping.cpp @@ -147,11 +147,10 @@ class HelloTriangleApplication vk::raii::CommandPool commandPool = nullptr; std::vector commandBuffers; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t semaphoreIndex = 0; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; @@ -994,7 +993,8 @@ class HelloTriangleApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( swapChainImages[imageIndex], @@ -1039,15 +1039,15 @@ class HelloTriangleApplication .colorAttachmentCount = 1, .pColorAttachments = &colorAttachmentInfo, .pDepthAttachment = &depthAttachmentInfo}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); - commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[currentFrame], nullptr); - commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0); - commandBuffers[currentFrame].endRendering(); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[frameIndex], nullptr); + commandBuffer.drawIndexed(indices.size(), 1, 0, 0, 0); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( swapChainImages[imageIndex], @@ -1058,7 +1058,7 @@ class HelloTriangleApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe, // dstStage vk::ImageAspectFlagBits::eColor); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -1091,23 +1091,21 @@ class HelloTriangleApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } @@ -1130,9 +1128,13 @@ class HelloTriangleApplication void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[semaphoreIndex], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -1143,19 +1145,28 @@ class HelloTriangleApplication { throw std::runtime_error("failed to acquire swap chain image!"); } - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[semaphoreIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; + 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) { @@ -1179,8 +1190,7 @@ class HelloTriangleApplication throw; } } - semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); - currentFrame = (currentFrame + 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/30_multisampling.cpp b/attachments/30_multisampling.cpp index 6f5262c5..6a71e98a 100644 --- a/attachments/30_multisampling.cpp +++ b/attachments/30_multisampling.cpp @@ -152,11 +152,10 @@ class HelloTriangleApplication vk::raii::CommandPool commandPool = nullptr; std::vector commandBuffers; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t semaphoreIndex = 0; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; @@ -1044,7 +1043,8 @@ class HelloTriangleApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( swapChainImages[imageIndex], @@ -1104,15 +1104,15 @@ class HelloTriangleApplication .colorAttachmentCount = 1, .pColorAttachments = &colorAttachment, .pDepthAttachment = &depthAttachment}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); - commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[currentFrame], nullptr); - commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0); - commandBuffers[currentFrame].endRendering(); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[frameIndex], nullptr); + commandBuffer.drawIndexed(indices.size(), 1, 0, 0, 0); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( swapChainImages[imageIndex], @@ -1123,7 +1123,7 @@ class HelloTriangleApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe, // dstStage vk::ImageAspectFlagBits::eColor); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -1156,23 +1156,21 @@ class HelloTriangleApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } @@ -1195,9 +1193,13 @@ class HelloTriangleApplication void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[semaphoreIndex], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -1208,19 +1210,28 @@ class HelloTriangleApplication { throw std::runtime_error("failed to acquire swap chain image!"); } - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[semaphoreIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; + 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) { @@ -1244,8 +1255,7 @@ class HelloTriangleApplication throw; } } - semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); - currentFrame = (currentFrame + 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/31_compute_shader.cpp b/attachments/31_compute_shader.cpp index 9afe1fa3..84fc1149 100644 --- a/attachments/31_compute_shader.cpp +++ b/attachments/31_compute_shader.cpp @@ -118,7 +118,7 @@ class ComputeShaderApplication vk::raii::Semaphore semaphore = nullptr; uint64_t timelineValue = 0; std::vector inFlightFences; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; double lastFrameTime = 0.0; @@ -697,8 +697,9 @@ class ComputeShaderApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].reset(); - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.reset(); + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( imageIndex, @@ -721,13 +722,13 @@ class ComputeShaderApplication .layerCount = 1, .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].bindVertexBuffers(0, {shaderStorageBuffers[currentFrame]}, {0}); - commandBuffers[currentFrame].draw(PARTICLE_COUNT, 1, 0, 0); - commandBuffers[currentFrame].endRendering(); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.bindVertexBuffers(0, {shaderStorageBuffers[frameIndex]}, {0}); + commandBuffer.draw(PARTICLE_COUNT, 1, 0, 0); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( imageIndex, @@ -738,7 +739,7 @@ class ComputeShaderApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe // dstStage ); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -770,17 +771,18 @@ class ComputeShaderApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void recordComputeCommandBuffer() { - computeCommandBuffers[currentFrame].reset(); - computeCommandBuffers[currentFrame].begin({}); - computeCommandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eCompute, computePipeline); - computeCommandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eCompute, computePipelineLayout, 0, {computeDescriptorSets[currentFrame]}, {}); - computeCommandBuffers[currentFrame].dispatch(PARTICLE_COUNT / 256, 1, 1); - computeCommandBuffers[currentFrame].end(); + auto &commandBuffer = computeCommandBuffers[frameIndex]; + commandBuffer.reset(); + commandBuffer.begin({}); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eCompute, computePipeline); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eCompute, computePipelineLayout, 0, {computeDescriptorSets[frameIndex]}, {}); + commandBuffer.dispatch(PARTICLE_COUNT / 256, 1, 1); + commandBuffer.end(); } void createSyncObjects() @@ -808,10 +810,10 @@ class ComputeShaderApplication void drawFrame() { - auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, nullptr, *inFlightFences[currentFrame]); - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, nullptr, *inFlightFences[frameIndex]); + while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[frameIndex], vk::True, UINT64_MAX)) ; - device.resetFences(*inFlightFences[currentFrame]); + device.resetFences(*inFlightFences[frameIndex]); // Update timeline value for this frame uint64_t computeWaitValue = timelineValue; @@ -819,7 +821,7 @@ class ComputeShaderApplication uint64_t graphicsWaitValue = computeSignalValue; uint64_t graphicsSignalValue = ++timelineValue; - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); { recordComputeCommandBuffer(); @@ -838,7 +840,7 @@ class ComputeShaderApplication .pWaitSemaphores = &*semaphore, .pWaitDstStageMask = waitStages, .commandBufferCount = 1, - .pCommandBuffers = &*computeCommandBuffers[currentFrame], + .pCommandBuffers = &*computeCommandBuffers[frameIndex], .signalSemaphoreCount = 1, .pSignalSemaphores = &*semaphore}; @@ -862,7 +864,7 @@ class ComputeShaderApplication .pWaitSemaphores = &*semaphore, .pWaitDstStageMask = &waitStage, .commandBufferCount = 1, - .pCommandBuffers = &*commandBuffers[currentFrame], + .pCommandBuffers = &*commandBuffers[frameIndex], .signalSemaphoreCount = 1, .pSignalSemaphores = &*semaphore}; @@ -911,7 +913,7 @@ class ComputeShaderApplication } } } - currentFrame = (currentFrame + 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/32_ecosystem_utilities.cpp b/attachments/32_ecosystem_utilities.cpp index a57dfd55..0ddcfc2a 100644 --- a/attachments/32_ecosystem_utilities.cpp +++ b/attachments/32_ecosystem_utilities.cpp @@ -162,12 +162,12 @@ class HelloTriangleApplication std::vector commandBuffers; // Synchronization objects - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; + uint32_t frameIndex = 0; vk::raii::Semaphore timelineSemaphore = nullptr; uint64_t timelineValue = 0; - uint32_t currentFrame = 0; bool framebufferResized = false; @@ -1341,7 +1341,8 @@ class HelloTriangleApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); vk::ClearValue clearColor = vk::ClearColorValue(0.0f, 0.0f, 0.0f, 1.0f); vk::ClearValue clearDepth = vk::ClearDepthStencilValue(1.0f, 0); @@ -1388,7 +1389,7 @@ class HelloTriangleApplication .imageMemoryBarrierCount = static_cast(barriers.size()), .pImageMemoryBarriers = barriers.data()}; - commandBuffers[currentFrame].pipelineBarrier2(dependencyInfo); + commandBuffer.pipelineBarrier2(dependencyInfo); } else { @@ -1424,7 +1425,7 @@ class HelloTriangleApplication .subresourceRange = {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}}; std::array barriers = {colorBarrier, depthBarrier, swapchainBarrier}; - commandBuffers[currentFrame].pipelineBarrier( + commandBuffer.pipelineBarrier( vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests, vk::DependencyFlagBits::eByRegion, @@ -1458,7 +1459,7 @@ class HelloTriangleApplication .pColorAttachments = &colorAttachment, .pDepthAttachment = &depthAttachment}; - commandBuffers[currentFrame].beginRendering(renderingInfo); + commandBuffer.beginRendering(renderingInfo); } else { @@ -1472,21 +1473,21 @@ class HelloTriangleApplication .clearValueCount = static_cast(clearValues.size()), .pClearValues = clearValues.data()}; - commandBuffers[currentFrame].beginRenderPass(renderPassInfo, vk::SubpassContents::eInline); + commandBuffer.beginRenderPass(renderPassInfo, vk::SubpassContents::eInline); } // Common rendering commands - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); - commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[currentFrame], nullptr); - commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[frameIndex], nullptr); + commandBuffer.drawIndexed(indices.size(), 1, 0, 0, 0); if (appInfo.dynamicRenderingSupported) { - commandBuffers[currentFrame].endRendering(); + commandBuffer.endRendering(); // Transition swapchain image to present layout if (appInfo.synchronization2Supported) @@ -1505,7 +1506,7 @@ class HelloTriangleApplication .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependencyInfo); + commandBuffer.pipelineBarrier2(dependencyInfo); } else { @@ -1519,7 +1520,7 @@ class HelloTriangleApplication .image = swapChainImages[imageIndex], .subresourceRange = {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}}; - commandBuffers[currentFrame].pipelineBarrier( + commandBuffer.pipelineBarrier( vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eBottomOfPipe, vk::DependencyFlagBits::eByRegion, @@ -1530,17 +1531,15 @@ class HelloTriangleApplication } else { - commandBuffers[currentFrame].endRenderPass(); + commandBuffer.endRenderPass(); } - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); if (appInfo.timelineSemaphoresSupported) { @@ -1554,27 +1553,16 @@ class HelloTriangleApplication .pNext = &timelineCreateInfo}; timelineSemaphore = vk::raii::Semaphore(device, semaphoreInfo); - - // Still need binary semaphores for swapchain operations - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) - { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - } } - else + + for (size_t i = 0; i < swapChainImages.size(); i++) { - // Create binary semaphores and fences - std::cout << "Creating binary semaphores and fences\n"; - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) - { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - } + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } @@ -1597,9 +1585,13 @@ class HelloTriangleApplication void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[currentFrame], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -1610,10 +1602,9 @@ class HelloTriangleApplication { throw std::runtime_error("failed to acquire swap chain image!"); } - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); if (appInfo.timelineSemaphoresSupported) @@ -1627,11 +1618,11 @@ class HelloTriangleApplication .signalSemaphoreValueCount = 1, .pSignalSemaphoreValues = &signalValue}; - std::array waitSemaphores = {*presentCompleteSemaphore[currentFrame], *timelineSemaphore}; + std::array waitSemaphores = {*presentCompleteSemaphores[frameIndex], *timelineSemaphore}; std::array waitStages = {vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eVertexInput}; std::array waitValues = {0, waitValue}; // Binary semaphore value is ignored - std::array signalSemaphores = {*renderFinishedSemaphore[currentFrame], *timelineSemaphore}; + std::array signalSemaphores = {*renderFinishedSemaphores[imageIndex], *timelineSemaphore}; std::array signalValues = {0, signalValue}; // Binary semaphore value is ignored timelineInfo.waitSemaphoreValueCount = 1; // Only for the timeline semaphore @@ -1645,35 +1636,33 @@ class HelloTriangleApplication .pWaitSemaphores = &waitSemaphores[0], .pWaitDstStageMask = &waitStages[0], .commandBufferCount = 1, - .pCommandBuffers = &*commandBuffers[currentFrame], + .pCommandBuffers = &*commandBuffers[frameIndex], .signalSemaphoreCount = 2, // Signal both semaphores .pSignalSemaphores = signalSemaphores.data()}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + queue.submit(submitInfo, *inFlightFences[frameIndex]); } else { // Use traditional binary semaphores vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{ - .waitSemaphoreCount = 1, - .pWaitSemaphores = &*presentCompleteSemaphore[currentFrame], - .pWaitDstStageMask = &waitDestinationStageMask, - .commandBufferCount = 1, - .pCommandBuffers = &*commandBuffers[currentFrame], - .signalSemaphoreCount = 1, - .pSignalSemaphores = &*renderFinishedSemaphore[currentFrame]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); } try { - const vk::PresentInfoKHR presentInfoKHR{ - .waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphore[currentFrame], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; + 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) { @@ -1697,7 +1686,7 @@ class HelloTriangleApplication throw; } } - currentFrame = (currentFrame + 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/33_vulkan_profiles.cpp b/attachments/33_vulkan_profiles.cpp index c2d3d60c..eccfcdcb 100644 --- a/attachments/33_vulkan_profiles.cpp +++ b/attachments/33_vulkan_profiles.cpp @@ -129,7 +129,7 @@ class HelloTriangleApplication std::vector renderFinishedSemaphores; std::vector inFlightFences; std::vector presentCompleteSemaphore; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; vk::raii::Buffer vertexBuffer = nullptr; vk::raii::DeviceMemory vertexBufferMemory = nullptr; @@ -1345,7 +1345,8 @@ class HelloTriangleApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Transition the attachments to the correct layouts for dynamic rendering @@ -1418,7 +1419,7 @@ class HelloTriangleApplication .pColorAttachments = &colorAttachment, .pDepthAttachment = &depthAttachment}; - commandBuffers[currentFrame].beginRendering(renderingInfo); + commandBuffer.beginRendering(renderingInfo); } else { @@ -1430,10 +1431,10 @@ class HelloTriangleApplication .clearValueCount = static_cast(clearValues.size()), .pClearValues = clearValues.data()}; - commandBuffers[currentFrame].beginRenderPass(renderPassInfo, vk::SubpassContents::eInline); + commandBuffer.beginRenderPass(renderPassInfo, vk::SubpassContents::eInline); } - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); vk::Viewport viewport{ .x = 0.0f, @@ -1442,21 +1443,21 @@ class HelloTriangleApplication .height = static_cast(swapChainExtent.height), .minDepth = 0.0f, .maxDepth = 1.0f}; - commandBuffers[currentFrame].setViewport(0, viewport); + commandBuffer.setViewport(0, viewport); vk::Rect2D scissor{ .offset = {0, 0}, .extent = swapChainExtent}; - commandBuffers[currentFrame].setScissor(0, scissor); + commandBuffer.setScissor(0, scissor); - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); - commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *pipelineLayout, 0, *descriptorSets[currentFrame], nullptr); - commandBuffers[currentFrame].drawIndexed(static_cast(indices.size()), 1, 0, 0, 0); + commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *pipelineLayout, 0, *descriptorSets[frameIndex], nullptr); + commandBuffer.drawIndexed(static_cast(indices.size()), 1, 0, 0, 0); if (appInfo.profileSupported) { - commandBuffers[currentFrame].endRendering(); + commandBuffer.endRendering(); // Transition the swapchain image to the correct layout for presentation transition_image_layout( @@ -1471,11 +1472,11 @@ class HelloTriangleApplication } else { - commandBuffers[currentFrame].endRenderPass(); + commandBuffer.endRenderPass(); // Traditional render pass already transitions the image to the correct layout } - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -1508,7 +1509,7 @@ class HelloTriangleApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() @@ -1553,12 +1554,12 @@ class HelloTriangleApplication void drawFrame() { - static_cast(device.waitForFences({*inFlightFences[currentFrame]}, VK_TRUE, UINT64_MAX)); + static_cast(device.waitForFences({*inFlightFences[frameIndex]}, VK_TRUE, UINT64_MAX)); uint32_t imageIndex; try { - auto [result, idx] = swapChain.acquireNextImage(UINT64_MAX, *imageAvailableSemaphores[currentFrame]); + auto [result, idx] = swapChain.acquireNextImage(UINT64_MAX, *imageAvailableSemaphores[frameIndex]); imageIndex = idx; } catch (vk::OutOfDateKHRError &) @@ -1567,23 +1568,23 @@ class HelloTriangleApplication return; } - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); - device.resetFences({*inFlightFences[currentFrame]}); + device.resetFences({*inFlightFences[frameIndex]}); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); const vk::SubmitInfo submitInfo{ .waitSemaphoreCount = 1, - .pWaitSemaphores = &*imageAvailableSemaphores[currentFrame], + .pWaitSemaphores = &*imageAvailableSemaphores[frameIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, - .pCommandBuffers = &*commandBuffers[currentFrame], + .pCommandBuffers = &*commandBuffers[frameIndex], .signalSemaphoreCount = 1, .pSignalSemaphores = &*presentCompleteSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { @@ -1616,7 +1617,7 @@ class HelloTriangleApplication throw; } } - currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; + frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } vk::SampleCountFlagBits getMaxUsableSampleCount() diff --git a/attachments/34_android.cpp b/attachments/34_android.cpp index 76e67937..8752ea1d 100644 --- a/attachments/34_android.cpp +++ b/attachments/34_android.cpp @@ -365,7 +365,7 @@ class HelloTriangleApplication std::vector imageAvailableSemaphores; std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; // Application info AppInfo appInfo; @@ -1269,7 +1269,7 @@ class HelloTriangleApplication commandBuffer.bindVertexBuffers(0, {*vertexBuffer}, {0}); commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); - commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *pipelineLayout, 0, {*descriptorSets[currentFrame]}, nullptr); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *pipelineLayout, 0, {*descriptorSets[frameIndex]}, nullptr); commandBuffer.drawIndexed(static_cast(indices.size()), 1, 0, 0, 0); commandBuffer.endRenderPass(); @@ -1279,12 +1279,12 @@ class HelloTriangleApplication // Draw frame void drawFrame() { - static_cast(device.waitForFences({*inFlightFences[currentFrame]}, VK_TRUE, UINT64_MAX)); + static_cast(device.waitForFences({*inFlightFences[frameIndex]}, VK_TRUE, UINT64_MAX)); uint32_t imageIndex; try { - auto [result, idx] = swapChain.acquireNextImage(UINT64_MAX, *imageAvailableSemaphores[currentFrame]); + auto [result, idx] = swapChain.acquireNextImage(UINT64_MAX, *imageAvailableSemaphores[frameIndex]); imageIndex = idx; } catch (vk::OutOfDateKHRError &) @@ -1294,23 +1294,23 @@ class HelloTriangleApplication } // Update uniform buffer with current transformation - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); - device.resetFences({*inFlightFences[currentFrame]}); + device.resetFences({*inFlightFences[frameIndex]}); - commandBuffers[currentFrame].reset(); - recordCommandBuffer(commandBuffers[currentFrame], imageIndex); + commandBuffers[frameIndex].reset(); + recordCommandBuffer(commandBuffers[frameIndex], imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); const vk::SubmitInfo submitInfo{ .waitSemaphoreCount = 1, - .pWaitSemaphores = &*imageAvailableSemaphores[currentFrame], + .pWaitSemaphores = &*imageAvailableSemaphores[frameIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, - .pCommandBuffers = &*commandBuffers[currentFrame], + .pCommandBuffers = &*commandBuffers[frameIndex], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { @@ -1346,7 +1346,7 @@ class HelloTriangleApplication } } - currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; + frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } // Recreate swap chain diff --git a/attachments/35_gltf_ktx.cpp b/attachments/35_gltf_ktx.cpp index 318d78e9..767ef3dd 100644 --- a/attachments/35_gltf_ktx.cpp +++ b/attachments/35_gltf_ktx.cpp @@ -313,10 +313,10 @@ class VulkanApplication vk::raii::CommandPool commandPool = nullptr; std::vector commandBuffers; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; @@ -1260,7 +1260,8 @@ class VulkanApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); transition_image_layout( swapChainImages[imageIndex], vk::ImageLayout::eUndefined, @@ -1301,15 +1302,15 @@ class VulkanApplication .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo, .pDepthAttachment = &depthAttachmentInfo}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); - commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *pipelineLayout, 0, *descriptorSets[currentFrame], nullptr); - commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0); - commandBuffers[currentFrame].endRendering(); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *pipelineLayout, 0, *descriptorSets[frameIndex], nullptr); + commandBuffer.drawIndexed(indices.size(), 1, 0, 0, 0); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( swapChainImages[imageIndex], @@ -1320,7 +1321,7 @@ class VulkanApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe, // dstStage vk::ImageAspectFlagBits::eColor); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -1353,23 +1354,21 @@ class VulkanApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } @@ -1394,9 +1393,13 @@ class VulkanApplication void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[currentFrame], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -1407,19 +1410,28 @@ class VulkanApplication { throw std::runtime_error("failed to acquire swap chain image!"); } - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[currentFrame], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; + 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) { @@ -1443,7 +1455,7 @@ class VulkanApplication throw; } } - currentFrame = (currentFrame + 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/36_multiple_objects.cpp b/attachments/36_multiple_objects.cpp index 2f248a0a..4b9ea030 100644 --- a/attachments/36_multiple_objects.cpp +++ b/attachments/36_multiple_objects.cpp @@ -365,10 +365,10 @@ class VulkanApplication vk::raii::CommandPool commandPool = nullptr; std::vector commandBuffers; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; @@ -1359,7 +1359,8 @@ class VulkanApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( swapChainImages[imageIndex], @@ -1401,31 +1402,31 @@ class VulkanApplication .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo, .pDepthAttachment = &depthAttachmentInfo}; - commandBuffers[currentFrame].beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.beginRendering(renderingInfo); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); // Bind vertex and index buffers (shared by all objects) - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); + commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); // Draw each object with its own descriptor set for (const auto &gameObject : gameObjects) { // Bind the descriptor set for this object - commandBuffers[currentFrame].bindDescriptorSets( + commandBuffer.bindDescriptorSets( vk::PipelineBindPoint::eGraphics, *pipelineLayout, 0, - *gameObject.descriptorSets[currentFrame], + *gameObject.descriptorSets[frameIndex], nullptr); // Draw the object - commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0); + commandBuffer.drawIndexed(indices.size(), 1, 0, 0, 0); } - commandBuffers[currentFrame].endRendering(); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( swapChainImages[imageIndex], @@ -1436,7 +1437,7 @@ class VulkanApplication vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage vk::PipelineStageFlagBits2::eBottomOfPipe, // dstStage vk::ImageAspectFlagBits::eColor); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -1469,23 +1470,21 @@ class VulkanApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } @@ -1521,15 +1520,19 @@ class VulkanApplication .proj = proj}; // Copy the UBO data to the mapped memory - memcpy(gameObject.uniformBuffersMapped[currentFrame], &ubo, sizeof(ubo)); + memcpy(gameObject.uniformBuffersMapped[frameIndex], &ubo, sizeof(ubo)); } } void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[currentFrame], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -1544,29 +1547,26 @@ class VulkanApplication // Update uniform buffers for all objects updateUniformBuffers(); - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{ - .waitSemaphoreCount = 1, - .pWaitSemaphores = &*presentCompleteSemaphore[currentFrame], - .pWaitDstStageMask = &waitDestinationStageMask, - .commandBufferCount = 1, - .pCommandBuffers = &*commandBuffers[currentFrame], - .signalSemaphoreCount = 1, - .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - queue.submit(submitInfo, *inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); try { - const vk::PresentInfoKHR presentInfoKHR{ - .waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex}; + 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) { @@ -1590,7 +1590,7 @@ class VulkanApplication throw; } } - currentFrame = (currentFrame + 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/37_multithreading.cpp b/attachments/37_multithreading.cpp index fc254156..6c98bd79 100644 --- a/attachments/37_multithreading.cpp +++ b/attachments/37_multithreading.cpp @@ -202,7 +202,7 @@ class MultithreadedApplication uint64_t timelineValue = 0; std::vector imageAvailableSemaphores; std::vector inFlightFences; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; double lastFrameTime = 0.0; @@ -1002,7 +1002,7 @@ class MultithreadedApplication cmdBuffer.begin(beginInfo); cmdBuffer.bindPipeline(vk::PipelineBindPoint::eCompute, *computePipeline); - cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eCompute, *computePipelineLayout, 0, {*computeDescriptorSets[currentFrame]}, {}); + cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eCompute, *computePipelineLayout, 0, {*computeDescriptorSets[frameIndex]}, {}); struct PushConstants { @@ -1020,11 +1020,11 @@ class MultithreadedApplication void recordGraphicsCommandBuffer(uint32_t imageIndex) { - graphicsCommandBuffers[currentFrame].reset(); + graphicsCommandBuffers[frameIndex].reset(); vk::CommandBufferBeginInfo beginInfo{ .flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit}; - graphicsCommandBuffers[currentFrame].begin(beginInfo); + graphicsCommandBuffers[frameIndex].begin(beginInfo); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( @@ -1050,14 +1050,14 @@ class MultithreadedApplication .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo}; - graphicsCommandBuffers[currentFrame].beginRendering(renderingInfo); + graphicsCommandBuffers[frameIndex].beginRendering(renderingInfo); - graphicsCommandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - graphicsCommandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - graphicsCommandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - graphicsCommandBuffers[currentFrame].bindVertexBuffers(0, {shaderStorageBuffers[currentFrame]}, {0}); - graphicsCommandBuffers[currentFrame].draw(PARTICLE_COUNT, 1, 0, 0); - graphicsCommandBuffers[currentFrame].endRendering(); + graphicsCommandBuffers[frameIndex].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + graphicsCommandBuffers[frameIndex].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + graphicsCommandBuffers[frameIndex].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + graphicsCommandBuffers[frameIndex].bindVertexBuffers(0, {shaderStorageBuffers[frameIndex]}, {0}); + graphicsCommandBuffers[frameIndex].draw(PARTICLE_COUNT, 1, 0, 0); + graphicsCommandBuffers[frameIndex].endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( @@ -1070,7 +1070,7 @@ class MultithreadedApplication vk::PipelineStageFlagBits2::eBottomOfPipe, // dstStage vk::ImageAspectFlagBits::eColor); - graphicsCommandBuffers[currentFrame].end(); + graphicsCommandBuffers[frameIndex].end(); } void transition_image_layout( @@ -1103,7 +1103,7 @@ class MultithreadedApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - graphicsCommandBuffers[currentFrame].pipelineBarrier2(dependency_info); + graphicsCommandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void signalThreadsToWork() @@ -1185,7 +1185,7 @@ class MultithreadedApplication void drawFrame() { // Wait for the previous frame to finish - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[frameIndex], vk::True, UINT64_MAX)) ; // If the framebuffer was resized, rebuild the swap chain before acquiring a new image @@ -1197,7 +1197,7 @@ class MultithreadedApplication } // Acquire the next image - auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *imageAvailableSemaphores[currentFrame], nullptr); + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *imageAvailableSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); @@ -1215,7 +1215,7 @@ class MultithreadedApplication uint64_t graphicsSignalValue = ++timelineValue; // Update uniform buffer with the latest delta time - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); // Signal worker threads to start processing particles signalThreadsToWork(); @@ -1275,7 +1275,7 @@ class MultithreadedApplication // Set up graphics submission vk::PipelineStageFlags graphicsWaitStages[] = {vk::PipelineStageFlagBits::eVertexInput, vk::PipelineStageFlagBits::eColorAttachmentOutput}; - std::array waitSemaphores = {*timelineSemaphore, *imageAvailableSemaphores[currentFrame]}; + std::array waitSemaphores = {*timelineSemaphore, *imageAvailableSemaphores[frameIndex]}; std::array waitSemaphoreValues = {graphicsWaitValue, 0}; vk::TimelineSemaphoreSubmitInfo graphicsTimelineInfo{ @@ -1290,15 +1290,15 @@ class MultithreadedApplication .pWaitSemaphores = waitSemaphores.data(), .pWaitDstStageMask = graphicsWaitStages, .commandBufferCount = 1, - .pCommandBuffers = &*graphicsCommandBuffers[currentFrame], + .pCommandBuffers = &*graphicsCommandBuffers[frameIndex], .signalSemaphoreCount = 1, .pSignalSemaphores = &*timelineSemaphore}; // Submit graphics work { std::lock_guard lock(queueSubmitMutex); - device.resetFences(*inFlightFences[currentFrame]); - queue.submit(graphicsSubmitInfo, *inFlightFences[currentFrame]); + device.resetFences(*inFlightFences[frameIndex]); + queue.submit(graphicsSubmitInfo, *inFlightFences[frameIndex]); } // Wait for graphics to complete before presenting @@ -1335,7 +1335,7 @@ class MultithreadedApplication } // Move to the next frame - currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; + frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } }; diff --git a/attachments/38_ray_tracing.cpp b/attachments/38_ray_tracing.cpp index 4ba405c3..029ddc3b 100644 --- a/attachments/38_ray_tracing.cpp +++ b/attachments/38_ray_tracing.cpp @@ -216,11 +216,10 @@ class VulkanRaytracingApplication std::vector commandBuffers; uint32_t graphicsIndex = 0; - std::vector presentCompleteSemaphore; - std::vector renderFinishedSemaphore; + std::vector presentCompleteSemaphores; + std::vector renderFinishedSemaphores; std::vector inFlightFences; - uint32_t semaphoreIndex = 0; - uint32_t currentFrame = 0; + uint32_t frameIndex = 0; bool framebufferResized = false; @@ -1558,7 +1557,8 @@ class VulkanRaytracingApplication void recordCommandBuffer(uint32_t imageIndex) { - commandBuffers[currentFrame].begin({}); + auto &commandBuffer = commandBuffers[frameIndex]; + commandBuffer.begin({}); // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( swapChainImages[imageIndex], @@ -1614,15 +1614,15 @@ class VulkanRaytracingApplication .pDepthAttachment = &depthAttachmentInfo}; // Note: .beginRendering replaces the previous .beginRenderPass call. - commandBuffers[currentFrame].beginRendering(renderingInfo); + commandBuffer.beginRendering(renderingInfo); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); - commandBuffers[currentFrame].setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); - commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); - commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *globalDescriptorSets[currentFrame], nullptr); - commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 1, *materialDescriptorSets[0], nullptr); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); + commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *globalDescriptorSets[frameIndex], nullptr); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 1, *materialDescriptorSets[0], nullptr); for (auto &sub : submeshes) { @@ -1633,12 +1633,12 @@ class VulkanRaytracingApplication .reflective = sub.reflective #endif // LAB_TASK_LEVEL >= LAB_TASK_REFLECTIONS }; - commandBuffers[currentFrame].pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, pushConstant); + commandBuffer.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, pushConstant); - commandBuffers[currentFrame].drawIndexed(sub.indexCount, 1, sub.indexOffset, 0, 0); + commandBuffer.drawIndexed(sub.indexCount, 1, sub.indexOffset, 0, 0); } - commandBuffers[currentFrame].endRendering(); + commandBuffer.endRendering(); // After rendering, transition the swapchain image to PRESENT_SRC transition_image_layout( @@ -1651,7 +1651,7 @@ class VulkanRaytracingApplication vk::PipelineStageFlagBits2::eBottomOfPipe, // dstStage vk::ImageAspectFlagBits::eColor); - commandBuffers[currentFrame].end(); + commandBuffer.end(); } void transition_image_layout( @@ -1684,23 +1684,21 @@ class VulkanRaytracingApplication .dependencyFlags = {}, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; - commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + commandBuffers[frameIndex].pipelineBarrier2(dependency_info); } void createSyncObjects() { - presentCompleteSemaphore.clear(); - renderFinishedSemaphore.clear(); - inFlightFences.clear(); + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); for (size_t i = 0; i < swapChainImages.size(); i++) { - presentCompleteSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphore.emplace_back(device, vk::SemaphoreCreateInfo()); + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); } for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); } } @@ -1825,9 +1823,13 @@ class VulkanRaytracingApplication void drawFrame() { - while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) + // 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 [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphore[semaphoreIndex], nullptr); + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -1838,21 +1840,30 @@ class VulkanRaytracingApplication { throw std::runtime_error("failed to acquire swap chain image!"); } - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); #if LAB_TASK_LEVEL >= LAB_TASK_AS_ANIMATION // TASK06: Update the TLAS with the current model matrix updateTopLevelAS(ubo.model); #endif // LAB_TASK_LEVEL >= LAB_TASK_AS_ANIMATION - device.resetFences(*inFlightFences[currentFrame]); - commandBuffers[currentFrame].reset(); + commandBuffers[frameIndex].reset(); recordCommandBuffer(imageIndex); vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); - const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[semaphoreIndex], .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex]}; - graphicsQueue.submit(submitInfo, *inFlightFences[currentFrame]); - - const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex}; + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + graphicsQueue.submit(submitInfo, *inFlightFences[frameIndex]); + + const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex}; result = presentQueue.presentKHR(presentInfoKHR); if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { @@ -1863,8 +1874,7 @@ class VulkanRaytracingApplication { throw std::runtime_error("failed to present swap chain image!"); } - semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); - currentFrame = (currentFrame + 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/en/03_Drawing_a_triangle/00_Setup/01_Instance.adoc b/en/03_Drawing_a_triangle/00_Setup/01_Instance.adoc index fad586ad..e750f205 100644 --- a/en/03_Drawing_a_triangle/00_Setup/01_Instance.adoc +++ b/en/03_Drawing_a_triangle/00_Setup/01_Instance.adoc @@ -150,14 +150,17 @@ Or use the tuple: [,c++] ---- - auto [result, imageIndex] = swapChain->acquireNextImage( UINT64_MAX, **presentCompleteSemaphore[currentFrame], nullptr ); - 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!"); - } + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + + 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!"); + } ---- Those examples are from later parts of our tutorial, this is just an example 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 36a7d27f..45cbec26 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 @@ -60,15 +60,18 @@ The `createSyncObjects` function should be changed to create all the objects: [,c++] ---- void createSyncObjects() { - presentCompleteSemaphores.clear(); - renderFinishedSemaphores.clear(); - inFlightFences.clear(); - - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); - renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); - inFlightFences.emplace_back(device, vk::FenceCreateInfo(vk::FenceCreateFlagBits::eSignaled)); - } + assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty()); + + for (size_t i = 0; i < swapChainImages.size(); i++) + { + renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); + } + + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) + { + presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo()); + inFlightFences.emplace_back(device, vk::FenceCreateInfo{.flags = vk::FenceCreateFlagBits::eSignaled}); + } } ---- @@ -77,7 +80,7 @@ We will use a frame index for that purpose: [,c++] ---- -uint32_t currentFrame = 0; +uint32_t frameIndex 0; ---- The `drawFrame` function can now be modified to use the right objects: @@ -85,27 +88,24 @@ The `drawFrame` function can now be modified to use the right objects: [,c++] ---- void drawFrame() { - while ( vk::Result::eTimeout == device.waitForFences( inFlightFences[currentFrame], vk::True, UINT64_MAX ) ) - ; - auto [result, imageIndex] = swapChain.acquireNextImage( UINT64_MAX, presentCompleteSemaphores[currentFrame], nullptr ); - - device.resetFences( inFlightFences[currentFrame] ); - - ... - - commandBuffers[currentFrame].reset(); - recordCommandBuffer(commandBuffers[currentFrame], imageIndex); - - ... - - vk::PipelineStageFlags waitDestinationStageMask( vk::PipelineStageFlagBits::eColorAttachmentOutput ); - const vk::SubmitInfo submitInfo{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphores[currentFrame], - .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], - .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphores[currentFrame] }; - - ... - - graphicsQueue.submit(submitInfo, inFlightFences[currentFrame]); + while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[frameIndex], vk::True, UINT64_MAX)) + ; + device.resetFences(*inFlightFences[frameIndex]); + + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr); + + commandBuffers[frameIndex].reset(); + recordCommandBuffer(imageIndex); + + vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; + queue.submit(submitInfo, *inFlightFences[frameIndex]); } ---- @@ -116,7 +116,7 @@ Of course, we shouldn't forget to advance to the next frame every time: void drawFrame() { ... - currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; + frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } ---- 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 9904c6b0..705057d1 100644 --- a/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc +++ b/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc @@ -87,7 +87,7 @@ Usually happens after a window resize. [,c++] ---- -auto [result, imageIndex] = swapChain.acquireNextImage( UINT64_MAX, *presentCompleteSemaphores[currentFrame], nullptr ); +auto [result, imageIndex] = swapChain.acquireNextImage( UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr ); if (result == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); @@ -113,7 +113,7 @@ if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptima throw std::runtime_error("failed to present swap chain image!"); } -currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; +frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; ---- The `vkQueuePresentKHR` function returns the same values with the same meaning. @@ -135,10 +135,10 @@ The beginning of `drawFrame` should now look like this: [,c++] ---- -vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX); +vkWaitForFences(device, 1, &inFlightFences[frameIndex], VK_TRUE, UINT64_MAX); uint32_t imageIndex; -VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); +VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[frameIndex], VK_NULL_HANDLE, &imageIndex); if (result == VK_ERROR_OUT_OF_DATE_KHR) { recreateSwapChain(); @@ -148,7 +148,7 @@ if (result == VK_ERROR_OUT_OF_DATE_KHR) { } // Only reset the fence if we are submitting work -vkResetFences(device, 1, &inFlightFences[currentFrame]); +vkResetFences(device, 1, &inFlightFences[frameIndex]); ---- == Handling resizes explicitly diff --git a/en/04_Vertex_buffers/01_Vertex_buffer_creation.adoc b/en/04_Vertex_buffers/01_Vertex_buffer_creation.adoc index e3eba4c9..92b04ef5 100644 --- a/en/04_Vertex_buffers/01_Vertex_buffer_creation.adoc +++ b/en/04_Vertex_buffers/01_Vertex_buffer_creation.adoc @@ -230,11 +230,11 @@ We're going to extend the `recordCommandBuffer` function to do that. [,c++] ---- -commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); +commandBuffers[frameIndex].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); -commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); +commandBuffers[frameIndex].bindVertexBuffers(0, *vertexBuffer, {0}); -commandBuffers[currentFrame].draw(3, 1, 0, 0); +commandBuffers[frameIndex].draw(3, 1, 0, 0); ---- The `vkCmdBindVertexBuffers` function is used to bind vertex buffers to bindings, like the one we set up in the previous chapter. diff --git a/en/04_Vertex_buffers/03_Index_buffer.adoc b/en/04_Vertex_buffers/03_Index_buffer.adoc index bd99c3d3..ff8c3eaf 100644 --- a/en/04_Vertex_buffers/03_Index_buffer.adoc +++ b/en/04_Vertex_buffers/03_Index_buffer.adoc @@ -102,8 +102,8 @@ It's unfortunately not possible to use different indices for each vertex attribu [,c++] ---- -commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); -commandBuffers[currentFrame].bindIndexBuffer( *indexBuffer, 0, vk::IndexType::eUint16 ); +commandBuffers[frameIndex].bindVertexBuffers(0, *vertexBuffer, {0}); +commandBuffers[frameIndex].bindIndexBuffer( *indexBuffer, 0, vk::IndexType::eUint16 ); ---- An index buffer is bound with `vkCmdBindIndexBuffer` which has the index buffer, a byte offset into it, and the type of index data as parameters. @@ -114,7 +114,7 @@ Remove the `vkCmdDraw` line and replace it with `vkCmdDrawIndexed`: [,c++] ---- -commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0); +commandBuffers[frameIndex].drawIndexed(indices.size(), 1, 0, 0, 0); ---- A call to this function is very similar to `vkCmdDraw`. diff --git a/en/05_Uniform_buffers/00_Descriptor_set_layout_and_buffer.adoc b/en/05_Uniform_buffers/00_Descriptor_set_layout_and_buffer.adoc index bc123670..980dd8e2 100644 --- a/en/05_Uniform_buffers/00_Descriptor_set_layout_and_buffer.adoc +++ b/en/05_Uniform_buffers/00_Descriptor_set_layout_and_buffer.adoc @@ -267,13 +267,17 @@ Create a new function `updateUniformBuffer` and add a call to it from the `drawF void drawFrame() { ... - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); ... - const vk::SubmitInfo submitInfo{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*presentCompleteSemaphore[currentFrame], - .pWaitDstStageMask = &waitDestinationStageMask, .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], - .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[currentFrame] }; + const vk::SubmitInfo submitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*commandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; ... } diff --git a/en/05_Uniform_buffers/01_Descriptor_pool_and_sets.adoc b/en/05_Uniform_buffers/01_Descriptor_pool_and_sets.adoc index 0e67ed74..24c7bcd1 100644 --- a/en/05_Uniform_buffers/01_Descriptor_pool_and_sets.adoc +++ b/en/05_Uniform_buffers/01_Descriptor_pool_and_sets.adoc @@ -165,8 +165,8 @@ This needs to be done before the `vkCmdDrawIndexed` call: [,c++] ---- -commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[currentFrame], nullptr); -commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0); +commandBuffers[frameIndex].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[frameIndex], nullptr); +commandBuffers[frameIndex].drawIndexed(indices.size(), 1, 0, 0, 0); ---- Unlike vertex and index buffers, descriptor sets are not unique to graphics pipelines. diff --git a/en/08_Loading_models.adoc b/en/08_Loading_models.adoc index 21ba7bbe..a83a2d81 100644 --- a/en/08_Loading_models.adoc +++ b/en/08_Loading_models.adoc @@ -71,7 +71,7 @@ Remember to also change the `vkCmdBindIndexBuffer` parameter: [,c++] ---- -commandBuffers[currentFrame]->bindIndexBuffer( **indexBuffer, 0, vk::IndexType::eUint32 ); +commandBuffers[frameIndex]->bindIndexBuffer( **indexBuffer, 0, vk::IndexType::eUint32 ); ---- The tinyobjloader library is included in the same way as STB libraries. diff --git a/en/11_Compute_Shader.adoc b/en/11_Compute_Shader.adoc index 55105b70..e7ce6cee 100644 --- a/en/11_Compute_Shader.adoc +++ b/en/11_Compute_Shader.adoc @@ -443,7 +443,7 @@ This image shows the relation between these two in three dimensions: image::/images/compute_space.svg[] -The number of dimensions for work groups (defined by `computeCommandBuffers[currentFrame]->dispatch`) and invocations depends (defined by the local sizes in the compute shader) on how input data is structured. +The number of dimensions for work groups (defined by `computeCommandBuffers[frameIndex]->dispatch`) and invocations depends (defined by the local sizes in the compute shader) on how input data is structured. If you e.g., work on a one-dimensional array, like we do in this chapter, you only have to specify the x dimension for both. @@ -534,27 +534,27 @@ We use this to index into our particle array. === Dispatch Now it's time to actually tell the GPU to do some compute. -This is done by calling `computeCommandBuffers[currentFrame]->dispatch` inside a command buffer. -While not perfectly true, a dispatch is for compute as a draw call like `commandBuffers[currentFrame]->draw` is for graphics. +This is done by calling `computeCommandBuffers[frameIndex]->dispatch` inside a command buffer. +While not perfectly true, a dispatch is for compute as a draw call like `commandBuffers[frameIndex]->draw` is for graphics. This dispatches a given number of compute work items in at max. three dimensions. [,c++] ---- -computeCommandBuffers[currentFrame]->begin({}); +computeCommandBuffers[frameIndex]->begin({}); ... -computeCommandBuffers[currentFrame]->bindPipeline(vk::PipelineBindPoint::eCompute, *computePipeline); -computeCommandBuffers[currentFrame]->bindDescriptorSets(vk::PipelineBindPoint::eCompute, *computePipelineLayout, 0, {computeDescriptorSets[currentFrame]}, {}); +computeCommandBuffers[frameIndex]->bindPipeline(vk::PipelineBindPoint::eCompute, *computePipeline); +computeCommandBuffers[frameIndex]->bindDescriptorSets(vk::PipelineBindPoint::eCompute, *computePipelineLayout, 0, {computeDescriptorSets[frameIndex]}, {}); -computeCommandBuffers[currentFrame]->dispatch( PARTICLE_COUNT / 256, 1, 1 ); +computeCommandBuffers[frameIndex]->dispatch( PARTICLE_COUNT / 256, 1, 1 ); ... -computeCommandBuffers[currentFrame]->end(); +computeCommandBuffers[frameIndex]->end(); ---- -The `computeCommandBuffers[currentFrame]->dispatch` will dispatch `PARTICLE_COUNT / 256` local work groups in the x dimension. +The `computeCommandBuffers[frameIndex]->dispatch` will dispatch `PARTICLE_COUNT / 256` local work groups in the x dimension. As our particle array is linear, we leave the other two dimensions at one, resulting in a one-dimensional dispatch. But why do we divide the number of particles (in our array) by 256? That's because in the previous paragraph, we defined that every compute shader in a work group will do 256 invocations. @@ -574,9 +574,9 @@ As our sample does both compute and graphics operations, we'll be doing two subm [,c++] ---- ... -computeQueue->submit(submitInfo, **computeInFlightFences[currentFrame]); +computeQueue->submit(submitInfo, **computeInFlightFences[frameIndex]); ... -graphicsQueue->submit(submitInfo, **inFlightFences[currentFrame]); +graphicsQueue->submit(submitInfo, **inFlightFences[frameIndex]); ---- The first submit to the compute queue updates the particle positions using the compute shader, and the second submit will then use that updated data to draw the particle system. @@ -623,30 +623,30 @@ We then use these to synchronize the compute buffer submission with the graphics ---- { // Compute submission - while ( vk::Result::eTimeout == device->waitForFences(**computeInFlightFences[currentFrame], vk::True, UINT64_MAX) ) + while ( vk::Result::eTimeout == device->waitForFences(**computeInFlightFences[frameIndex], vk::True, UINT64_MAX) ) ; - updateUniformBuffer(currentFrame); - device->resetFences( **computeInFlightFences[currentFrame] ); - computeCommandBuffers[currentFrame]->reset(); + updateUniformBuffer(frameIndex); + device->resetFences( **computeInFlightFences[frameIndex] ); + computeCommandBuffers[frameIndex]->reset(); recordComputeCommandBuffer(); - const vk::SubmitInfo submitInfo({}, {}, {**computeCommandBuffers[currentFrame]}, { **computeFinishedSemaphores[currentFrame]}); - computeQueue->submit(submitInfo, **computeInFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo({}, {}, {**computeCommandBuffers[frameIndex]}, { **computeFinishedSemaphores[frameIndex]}); + computeQueue->submit(submitInfo, **computeInFlightFences[frameIndex]); } { // Graphics submission - while ( vk::Result::eTimeout == device->waitForFences(**inFlightFences[currentFrame], vk::True, UINT64_MAX)) + while ( vk::Result::eTimeout == device->waitForFences(**inFlightFences[frameIndex], vk::True, UINT64_MAX)) ... - device->resetFences( **inFlightFences[currentFrame] ); - commandBuffers[currentFrame]->reset(); + device->resetFences( **inFlightFences[frameIndex] ); + commandBuffers[frameIndex]->reset(); recordCommandBuffer(imageIndex); - vk::Semaphore waitSemaphores[] = {**presentCompleteSemaphore[currentFrame], **computeFinishedSemaphores[currentFrame]}; + vk::Semaphore waitSemaphores[] = {**presentCompleteSemaphore[frameIndex], **computeFinishedSemaphores[frameIndex]}; vk::PipelineStageFlags waitDestinationStageMask[] = { vk::PipelineStageFlagBits::eVertexInput, vk::PipelineStageFlagBits::eColorAttachmentOutput }; - const vk::SubmitInfo submitInfo( waitSemaphores, waitDestinationStageMask, {**commandBuffers[currentFrame]}, {**renderFinishedSemaphore[currentFrame]} ); - graphicsQueue->submit(submitInfo, **inFlightFences[currentFrame]); + const vk::SubmitInfo submitInfo( waitSemaphores, waitDestinationStageMask, {**commandBuffers[frameIndex]}, {**renderFinishedSemaphore[frameIndex]} ); + graphicsQueue->submit(submitInfo, **inFlightFences[frameIndex]); ---- Similar to the sample in the @@ -724,7 +724,7 @@ vk::SubmitInfo computeSubmitInfo{ .pWaitSemaphores = &*semaphore, .pWaitDstStageMask = waitStages, .commandBufferCount = 1, - .pCommandBuffers = &*computeCommandBuffers[currentFrame], + .pCommandBuffers = &*computeCommandBuffers[frameIndex], .signalSemaphoreCount = 1, .pSignalSemaphores = &*semaphore }; @@ -750,7 +750,7 @@ vk::SubmitInfo graphicsSubmitInfo{ .pWaitSemaphores = &*semaphore, .pWaitDstStageMask = &waitStage, .commandBufferCount = 1, - .pCommandBuffers = &*commandBuffers[currentFrame], + .pCommandBuffers = &*commandBuffers[frameIndex], .signalSemaphoreCount = 1, .pSignalSemaphores = &*semaphore }; @@ -817,9 +817,9 @@ We then bind and draw it like we would with any vertex buffer: [,c++] ---- -commandBuffers[currentFrame]->bindVertexBuffers(0, { *shaderStorageBuffers[currentFrame] }, {0}); +commandBuffers[frameIndex]->bindVertexBuffers(0, { *shaderStorageBuffers[frameIndex] }, {0}); -commandBuffers[currentFrame]->draw( PARTICLE_COUNT, 1, 0, 0 ); +commandBuffers[frameIndex]->draw( PARTICLE_COUNT, 1, 0, 0 ); ---- == Conclusion diff --git a/en/12_Ecosystem_Utilities_and_Compatibility.adoc b/en/12_Ecosystem_Utilities_and_Compatibility.adoc index 87f090af..3ee7c1a4 100644 --- a/en/12_Ecosystem_Utilities_and_Compatibility.adoc +++ b/en/12_Ecosystem_Utilities_and_Compatibility.adoc @@ -449,11 +449,16 @@ if (timelineSemaphoresSupported) { vk::SemaphoreCreateInfo semaphoreInfo{}; vk::FenceCreateInfo fenceInfo{.flags = vk::FenceCreateFlagBits::eSignaled}; - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - imageAvailableSemaphores[i] = device.createSemaphore(semaphoreInfo); + for (size_t i = 0; i < swapChainImages.size(); i++) + { renderFinishedSemaphores[i] = device.createSemaphore(semaphoreInfo); + } + + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) + { + imageAvailableSemaphores[i] = device.createSemaphore(semaphoreInfo); inFlightFences[i] = device.createFence(fenceInfo); - } + } } ---- diff --git a/en/16_Multiple_Objects.adoc b/en/16_Multiple_Objects.adoc index e9f84c99..c84b017e 100644 --- a/en/16_Multiple_Objects.adoc +++ b/en/16_Multiple_Objects.adoc @@ -257,7 +257,7 @@ void updateUniformBuffers() { }; // Copy the UBO data to the mapped memory - memcpy(gameObject.uniformBuffersMapped[currentFrame], &ubo, sizeof(ubo)); + memcpy(gameObject.uniformBuffersMapped[frameIndex], &ubo, sizeof(ubo)); } } ---- @@ -274,22 +274,22 @@ void recordCommandBuffer(uint32_t imageIndex) { // ... (beginning of the method remains the same) // Bind vertex and index buffers (shared by all objects) - commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffers[currentFrame].bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); + commandBuffers[frameIndex].bindVertexBuffers(0, *vertexBuffer, {0}); + commandBuffers[frameIndex].bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint32); // Draw each object with its own descriptor set for (const auto& gameObject : gameObjects) { // Bind the descriptor set for this object - commandBuffers[currentFrame].bindDescriptorSets( + commandBuffers[frameIndex].bindDescriptorSets( vk::PipelineBindPoint::eGraphics, *pipelineLayout, 0, - *gameObject.descriptorSets[currentFrame], + *gameObject.descriptorSets[frameIndex], nullptr ); // Draw the object - commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0); + commandBuffers[frameIndex].drawIndexed(indices.size(), 1, 0, 0, 0); } // ... (end of the method remains the same) diff --git a/en/17_Multithreading.adoc b/en/17_Multithreading.adoc index 45a5b957..40373ece 100644 --- a/en/17_Multithreading.adoc +++ b/en/17_Multithreading.adoc @@ -187,7 +187,7 @@ public: // Bind compute pipeline and descriptor sets cmdBuffer.bindPipeline(vk::PipelineBindPoint::eCompute, *computePipeline); - cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eCompute, *computePipelineLayout, 0, {*computeDescriptorSets[currentFrame]}, {}); + cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eCompute, *computePipelineLayout, 0, {*computeDescriptorSets[frameIndex]}, {}); // Add a push constant to specify the particle range for this thread struct PushConstants { @@ -297,11 +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[currentFrame], vk::True, UINT64_MAX)); - device.resetFences(*inFlightFences[currentFrame]); + while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[frameIndex], vk::True, UINT64_MAX)); + device.resetFences(*inFlightFences[frameIndex]); // Acquire the next image - auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *imageAvailableSemaphores[currentFrame], nullptr); + auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *imageAvailableSemaphores[frameIndex], nullptr); if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { framebufferResized = false; @@ -310,7 +310,7 @@ void drawFrame() { } // Update uniform buffers - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); // Signal worker threads to start recording compute command buffers signalThreadsToWork(); @@ -342,25 +342,23 @@ void drawFrame() { vk::PipelineStageFlags waitStages[] = {vk::PipelineStageFlagBits::eVertexInput}; // Submit graphics work - vk::SubmitInfo graphicsSubmitInfo{ - .waitSemaphoreCount = 1, - .pWaitSemaphores = &*imageAvailableSemaphores[currentFrame], - .pWaitDstStageMask = waitStages, - .commandBufferCount = 1, - .pCommandBuffers = &*graphicsCommandBuffers[currentFrame], - .signalSemaphoreCount = 1, - .pSignalSemaphores = &*renderFinishedSemaphores[currentFrame] - }; + vk::SubmitInfo graphisSubmitInfo{.waitSemaphoreCount = 1, + .pWaitSemaphores = &*imageAvailableSemaphores[frameIndex], + .pWaitDstStageMask = &waitDestinationStageMask, + .commandBufferCount = 1, + .pCommandBuffers = &*graphicsCommandBuffers[frameIndex], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]}; { std::lock_guard lock(queueSubmitMutex); - graphicsQueue.submit(graphicsSubmitInfo, *inFlightFences[currentFrame]); + graphicsQueue.submit(graphicsSubmitInfo, *inFlightFences[frameIndex]); } // Present the image vk::PresentInfoKHR presentInfo{ .waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[currentFrame], + .pWaitSemaphores = &*renderFinishedSemaphores[frameIndex], .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex @@ -375,7 +373,7 @@ void drawFrame() { throw std::runtime_error("failed to present swap chain image!"); } - currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; + frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } ---- diff --git a/en/courses/18_Ray_tracing/01_Dynamic_rendering.adoc b/en/courses/18_Ray_tracing/01_Dynamic_rendering.adoc index e5e27606..c17ba79a 100644 --- a/en/courses/18_Ray_tracing/01_Dynamic_rendering.adoc +++ b/en/courses/18_Ray_tracing/01_Dynamic_rendering.adoc @@ -78,7 +78,7 @@ vk::RenderingInfo renderingInfo = { }; // Note: .beginRendering replaces the previous .beginRenderPass call. -commandBuffers[currentFrame].beginRendering(renderingInfo); +commandBuffers[frameIndex].beginRendering(renderingInfo); ---- For more context, refer to the previous tutorial link:../../03_Drawing_a_triangle/02_Graphics_pipeline_basics/03_Render_passes.adoc[chapter]. diff --git a/en/courses/18_Ray_tracing/04_TLAS_animation.adoc b/en/courses/18_Ray_tracing/04_TLAS_animation.adoc index 5693190d..de134e9d 100644 --- a/en/courses/18_Ray_tracing/04_TLAS_animation.adoc +++ b/en/courses/18_Ray_tracing/04_TLAS_animation.adoc @@ -138,7 +138,7 @@ Verify that the function is called in `drawFrame()` after the model matrix is up [,c{pp}] ---- - updateUniformBuffer(currentFrame); + updateUniformBuffer(frameIndex); // TASK06: Update the TLAS with the current model matrix updateTopLevelAS(ubo.model); ---- diff --git a/en/courses/18_Ray_tracing/05_Shadow_transparency.adoc b/en/courses/18_Ray_tracing/05_Shadow_transparency.adoc index a31f87d1..6f41f125 100644 --- a/en/courses/18_Ray_tracing/05_Shadow_transparency.adoc +++ b/en/courses/18_Ray_tracing/05_Shadow_transparency.adoc @@ -94,9 +94,9 @@ Note how the renderer does not bind separate material textures for each submesh. PushConstant pushConstant = { .materialIndex = sub.materialID < 0 ? 0u : static_cast(sub.materialID), }; - commandBuffers[currentFrame].pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, pushConstant); + commandBuffers[frameIndex].pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, pushConstant); - commandBuffers[currentFrame].drawIndexed(sub.indexCount, 1, sub.indexOffset, 0, 0); + commandBuffers[frameIndex].drawIndexed(sub.indexCount, 1, sub.indexOffset, 0, 0); } ---- diff --git a/en/courses/18_Ray_tracing/06_Reflections.adoc b/en/courses/18_Ray_tracing/06_Reflections.adoc index 99d907d5..45eaa893 100644 --- a/en/courses/18_Ray_tracing/06_Reflections.adoc +++ b/en/courses/18_Ray_tracing/06_Reflections.adoc @@ -40,9 +40,9 @@ PushConstant pushConstant = { .materialIndex = sub.materialID < 0 ? 0u : static_cast(sub.materialID), .reflective = sub.reflective }; -commandBuffers[currentFrame].pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, pushConstant); +commandBuffers[frameIndex].pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, pushConstant); -commandBuffers[currentFrame].drawIndexed(sub.indexCount, 1, sub.indexOffset, 0, 0); +commandBuffers[frameIndex].drawIndexed(sub.indexCount, 1, sub.indexOffset, 0, 0); ---- We will then retrieve this in the fragment shader, before we apply the shadow effect, to call a helper function that will modify the fragment color in-place, based on the reflection ray query: