Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4ce5e2e

Browse files
committed
Add proper synchronization of in-flight frames
1 parent f01adc3 commit 4ce5e2e

14 files changed

Lines changed: 476 additions & 224 deletions

code/15_hello_triangle.cpp

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
const int WIDTH = 800;
1414
const int HEIGHT = 600;
1515

16+
const int MAX_FRAMES_IN_FLIGHT = 2;
17+
1618
const std::vector<const char*> validationLayers = {
1719
"VK_LAYER_LUNARG_standard_validation"
1820
};
@@ -94,8 +96,10 @@ class HelloTriangleApplication {
9496
VkCommandPool commandPool;
9597
std::vector<VkCommandBuffer> commandBuffers;
9698

97-
VkSemaphore imageAvailableSemaphore;
98-
VkSemaphore renderFinishedSemaphore;
99+
std::vector<VkSemaphore> imageAvailableSemaphores;
100+
std::vector<VkSemaphore> renderFinishedSemaphores;
101+
std::vector<VkFence> inFlightFences;
102+
size_t currentFrame = 0;
99103

100104
void initWindow() {
101105
glfwInit();
@@ -119,7 +123,7 @@ class HelloTriangleApplication {
119123
createFramebuffers();
120124
createCommandPool();
121125
createCommandBuffers();
122-
createSemaphores();
126+
createSyncObjects();
123127
}
124128

125129
void mainLoop() {
@@ -132,8 +136,11 @@ class HelloTriangleApplication {
132136
}
133137

134138
void cleanup() {
135-
vkDestroySemaphore(device, renderFinishedSemaphore, nullptr);
136-
vkDestroySemaphore(device, imageAvailableSemaphore, nullptr);
139+
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
140+
vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);
141+
vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
142+
vkDestroyFence(device, inFlightFences[i], nullptr);
143+
}
137144

138145
vkDestroyCommandPool(device, commandPool, nullptr);
139146

@@ -597,25 +604,38 @@ class HelloTriangleApplication {
597604
}
598605
}
599606

600-
void createSemaphores() {
607+
void createSyncObjects() {
608+
imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
609+
renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
610+
inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
611+
601612
VkSemaphoreCreateInfo semaphoreInfo = {};
602613
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
603614

604-
if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphore) != VK_SUCCESS ||
605-
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphore) != VK_SUCCESS) {
615+
VkFenceCreateInfo fenceInfo = {};
616+
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
617+
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
606618

607-
throw std::runtime_error("failed to create semaphores!");
619+
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
620+
if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS ||
621+
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS ||
622+
vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) {
623+
throw std::runtime_error("failed to create synchronization objects for a frame!");
624+
}
608625
}
609626
}
610627

611628
void drawFrame() {
629+
vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, std::numeric_limits<uint64_t>::max());
630+
vkResetFences(device, 1, &inFlightFences[currentFrame]);
631+
612632
uint32_t imageIndex;
613-
vkAcquireNextImageKHR(device, swapChain, std::numeric_limits<uint64_t>::max(), imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
633+
vkAcquireNextImageKHR(device, swapChain, std::numeric_limits<uint64_t>::max(), imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
614634

615635
VkSubmitInfo submitInfo = {};
616636
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
617637

618-
VkSemaphore waitSemaphores[] = {imageAvailableSemaphore};
638+
VkSemaphore waitSemaphores[] = {imageAvailableSemaphores[currentFrame]};
619639
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
620640
submitInfo.waitSemaphoreCount = 1;
621641
submitInfo.pWaitSemaphores = waitSemaphores;
@@ -624,11 +644,11 @@ class HelloTriangleApplication {
624644
submitInfo.commandBufferCount = 1;
625645
submitInfo.pCommandBuffers = &commandBuffers[imageIndex];
626646

627-
VkSemaphore signalSemaphores[] = {renderFinishedSemaphore};
647+
VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[currentFrame]};
628648
submitInfo.signalSemaphoreCount = 1;
629649
submitInfo.pSignalSemaphores = signalSemaphores;
630650

631-
if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) {
651+
if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]) != VK_SUCCESS) {
632652
throw std::runtime_error("failed to submit draw command buffer!");
633653
}
634654

@@ -646,9 +666,7 @@ class HelloTriangleApplication {
646666

647667
vkQueuePresentKHR(presentQueue, &presentInfo);
648668

649-
if (enableValidationLayers) {
650-
vkQueueWaitIdle(presentQueue);
651-
}
669+
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
652670
}
653671

654672
VkShaderModule createShaderModule(const std::vector<char>& code) {

code/16_swap_chain_recreation.cpp

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
const int WIDTH = 800;
1414
const int HEIGHT = 600;
1515

16+
const int MAX_FRAMES_IN_FLIGHT = 2;
17+
1618
const std::vector<const char*> validationLayers = {
1719
"VK_LAYER_LUNARG_standard_validation"
1820
};
@@ -94,8 +96,10 @@ class HelloTriangleApplication {
9496
VkCommandPool commandPool;
9597
std::vector<VkCommandBuffer> commandBuffers;
9698

97-
VkSemaphore imageAvailableSemaphore;
98-
VkSemaphore renderFinishedSemaphore;
99+
std::vector<VkSemaphore> imageAvailableSemaphores;
100+
std::vector<VkSemaphore> renderFinishedSemaphores;
101+
std::vector<VkFence> inFlightFences;
102+
size_t currentFrame = 0;
99103

100104
void initWindow() {
101105
glfwInit();
@@ -118,7 +122,7 @@ class HelloTriangleApplication {
118122
createFramebuffers();
119123
createCommandPool();
120124
createCommandBuffers();
121-
createSemaphores();
125+
createSyncObjects();
122126
}
123127

124128
void mainLoop() {
@@ -151,8 +155,11 @@ class HelloTriangleApplication {
151155
void cleanup() {
152156
cleanupSwapChain();
153157

154-
vkDestroySemaphore(device, renderFinishedSemaphore, nullptr);
155-
vkDestroySemaphore(device, imageAvailableSemaphore, nullptr);
158+
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
159+
vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);
160+
vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
161+
vkDestroyFence(device, inFlightFences[i], nullptr);
162+
}
156163

157164
vkDestroyCommandPool(device, commandPool, nullptr);
158165

@@ -618,20 +625,33 @@ class HelloTriangleApplication {
618625
}
619626
}
620627

621-
void createSemaphores() {
628+
void createSyncObjects() {
629+
imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
630+
renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
631+
inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
632+
622633
VkSemaphoreCreateInfo semaphoreInfo = {};
623634
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
624635

625-
if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphore) != VK_SUCCESS ||
626-
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphore) != VK_SUCCESS) {
636+
VkFenceCreateInfo fenceInfo = {};
637+
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
638+
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
627639

628-
throw std::runtime_error("failed to create semaphores!");
640+
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
641+
if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS ||
642+
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS ||
643+
vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) {
644+
throw std::runtime_error("failed to create synchronization objects for a frame!");
645+
}
629646
}
630647
}
631648

632649
void drawFrame() {
650+
vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, std::numeric_limits<uint64_t>::max());
651+
vkResetFences(device, 1, &inFlightFences[currentFrame]);
652+
633653
uint32_t imageIndex;
634-
VkResult result = vkAcquireNextImageKHR(device, swapChain, std::numeric_limits<uint64_t>::max(), imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
654+
VkResult result = vkAcquireNextImageKHR(device, swapChain, std::numeric_limits<uint64_t>::max(), imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
635655

636656
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
637657
recreateSwapChain();
@@ -643,7 +663,7 @@ class HelloTriangleApplication {
643663
VkSubmitInfo submitInfo = {};
644664
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
645665

646-
VkSemaphore waitSemaphores[] = {imageAvailableSemaphore};
666+
VkSemaphore waitSemaphores[] = {imageAvailableSemaphores[currentFrame]};
647667
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
648668
submitInfo.waitSemaphoreCount = 1;
649669
submitInfo.pWaitSemaphores = waitSemaphores;
@@ -652,11 +672,11 @@ class HelloTriangleApplication {
652672
submitInfo.commandBufferCount = 1;
653673
submitInfo.pCommandBuffers = &commandBuffers[imageIndex];
654674

655-
VkSemaphore signalSemaphores[] = {renderFinishedSemaphore};
675+
VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[currentFrame]};
656676
submitInfo.signalSemaphoreCount = 1;
657677
submitInfo.pSignalSemaphores = signalSemaphores;
658678

659-
if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) {
679+
if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]) != VK_SUCCESS) {
660680
throw std::runtime_error("failed to submit draw command buffer!");
661681
}
662682

@@ -680,9 +700,7 @@ class HelloTriangleApplication {
680700
throw std::runtime_error("failed to present swap chain image!");
681701
}
682702

683-
if (enableValidationLayers) {
684-
vkQueueWaitIdle(presentQueue);
685-
}
703+
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
686704
}
687705

688706
VkShaderModule createShaderModule(const std::vector<char>& code) {

code/17_vertex_input.cpp

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
const int WIDTH = 800;
1717
const int HEIGHT = 600;
1818

19+
const int MAX_FRAMES_IN_FLIGHT = 2;
20+
1921
const std::vector<const char*> validationLayers = {
2022
"VK_LAYER_LUNARG_standard_validation"
2123
};
@@ -133,8 +135,10 @@ class HelloTriangleApplication {
133135
VkCommandPool commandPool;
134136
std::vector<VkCommandBuffer> commandBuffers;
135137

136-
VkSemaphore imageAvailableSemaphore;
137-
VkSemaphore renderFinishedSemaphore;
138+
std::vector<VkSemaphore> imageAvailableSemaphores;
139+
std::vector<VkSemaphore> renderFinishedSemaphores;
140+
std::vector<VkFence> inFlightFences;
141+
size_t currentFrame = 0;
138142

139143
void initWindow() {
140144
glfwInit();
@@ -157,7 +161,7 @@ class HelloTriangleApplication {
157161
createFramebuffers();
158162
createCommandPool();
159163
createCommandBuffers();
160-
createSemaphores();
164+
createSyncObjects();
161165
}
162166

163167
void mainLoop() {
@@ -190,8 +194,11 @@ class HelloTriangleApplication {
190194
void cleanup() {
191195
cleanupSwapChain();
192196

193-
vkDestroySemaphore(device, renderFinishedSemaphore, nullptr);
194-
vkDestroySemaphore(device, imageAvailableSemaphore, nullptr);
197+
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
198+
vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);
199+
vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
200+
vkDestroyFence(device, inFlightFences[i], nullptr);
201+
}
195202

196203
vkDestroyCommandPool(device, commandPool, nullptr);
197204

@@ -663,20 +670,33 @@ class HelloTriangleApplication {
663670
}
664671
}
665672

666-
void createSemaphores() {
673+
void createSyncObjects() {
674+
imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
675+
renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
676+
inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
677+
667678
VkSemaphoreCreateInfo semaphoreInfo = {};
668679
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
669680

670-
if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphore) != VK_SUCCESS ||
671-
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphore) != VK_SUCCESS) {
681+
VkFenceCreateInfo fenceInfo = {};
682+
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
683+
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
672684

673-
throw std::runtime_error("failed to create semaphores!");
685+
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
686+
if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS ||
687+
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS ||
688+
vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) {
689+
throw std::runtime_error("failed to create synchronization objects for a frame!");
690+
}
674691
}
675692
}
676693

677694
void drawFrame() {
695+
vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, std::numeric_limits<uint64_t>::max());
696+
vkResetFences(device, 1, &inFlightFences[currentFrame]);
697+
678698
uint32_t imageIndex;
679-
VkResult result = vkAcquireNextImageKHR(device, swapChain, std::numeric_limits<uint64_t>::max(), imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
699+
VkResult result = vkAcquireNextImageKHR(device, swapChain, std::numeric_limits<uint64_t>::max(), imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
680700

681701
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
682702
recreateSwapChain();
@@ -688,7 +708,7 @@ class HelloTriangleApplication {
688708
VkSubmitInfo submitInfo = {};
689709
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
690710

691-
VkSemaphore waitSemaphores[] = {imageAvailableSemaphore};
711+
VkSemaphore waitSemaphores[] = {imageAvailableSemaphores[currentFrame]};
692712
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
693713
submitInfo.waitSemaphoreCount = 1;
694714
submitInfo.pWaitSemaphores = waitSemaphores;
@@ -697,11 +717,11 @@ class HelloTriangleApplication {
697717
submitInfo.commandBufferCount = 1;
698718
submitInfo.pCommandBuffers = &commandBuffers[imageIndex];
699719

700-
VkSemaphore signalSemaphores[] = {renderFinishedSemaphore};
720+
VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[currentFrame]};
701721
submitInfo.signalSemaphoreCount = 1;
702722
submitInfo.pSignalSemaphores = signalSemaphores;
703723

704-
if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) {
724+
if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]) != VK_SUCCESS) {
705725
throw std::runtime_error("failed to submit draw command buffer!");
706726
}
707727

@@ -725,9 +745,7 @@ class HelloTriangleApplication {
725745
throw std::runtime_error("failed to present swap chain image!");
726746
}
727747

728-
if (enableValidationLayers) {
729-
vkQueueWaitIdle(presentQueue);
730-
}
748+
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
731749
}
732750

733751
VkShaderModule createShaderModule(const std::vector<char>& code) {

0 commit comments

Comments
 (0)