Proper semaphore setup
For details see https://docs.vulkan.org/guide/latest/swapchain_semaphore_reuse.html Fixes #1217
This commit is contained in:
parent
d92eee9b8b
commit
d7903488eb
2 changed files with 34 additions and 34 deletions
|
|
@ -110,9 +110,8 @@ public:
|
||||||
std::array<VkCommandBuffer, MAX_CONCURRENT_FRAMES> commandBuffers{};
|
std::array<VkCommandBuffer, MAX_CONCURRENT_FRAMES> commandBuffers{};
|
||||||
std::array<VkFence, MAX_CONCURRENT_FRAMES> waitFences{};
|
std::array<VkFence, MAX_CONCURRENT_FRAMES> waitFences{};
|
||||||
|
|
||||||
// To select the correct sync and command objects, we need to keep track of the current frame and (swapchain) image index
|
// To select the correct sync and command objects, we need to keep track of the current frame
|
||||||
uint32_t currentFrame{ 0 };
|
uint32_t currentFrame{ 0 };
|
||||||
uint32_t currentSemaphore{ 0 };
|
|
||||||
|
|
||||||
VulkanExample() : VulkanExampleBase()
|
VulkanExample() : VulkanExampleBase()
|
||||||
{
|
{
|
||||||
|
|
@ -189,16 +188,19 @@ public:
|
||||||
// Fence used to ensure that command buffer has completed exection before using it again
|
// Fence used to ensure that command buffer has completed exection before using it again
|
||||||
VK_CHECK_RESULT(vkCreateFence(device, &fenceCI, nullptr, &waitFences[i]));
|
VK_CHECK_RESULT(vkCreateFence(device, &fenceCI, nullptr, &waitFences[i]));
|
||||||
}
|
}
|
||||||
// Semaphores are per swapchain image
|
// Semaphores are used for correct command ordering within a queue
|
||||||
presentCompleteSemaphores.resize(swapChain.images.size());
|
// Used to ensure that image presentation is complete before starting to submit again
|
||||||
renderCompleteSemaphores.resize(swapChain.images.size());
|
presentCompleteSemaphores.resize(MAX_CONCURRENT_FRAMES);
|
||||||
for (size_t i = 0; i < swapChain.images.size(); i++) {
|
for (auto& semaphore : presentCompleteSemaphores) {
|
||||||
// Semaphores are used for correct command ordering within a queue
|
|
||||||
VkSemaphoreCreateInfo semaphoreCI{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
|
VkSemaphoreCreateInfo semaphoreCI{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
|
||||||
// Semaphore used to ensure that image presentation is complete before starting to submit again
|
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore));
|
||||||
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &presentCompleteSemaphores[i]));
|
}
|
||||||
// Semaphore used to ensure that all commands submitted have been finished before submitting the image to the queue
|
// Render completion
|
||||||
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &renderCompleteSemaphores[i]));
|
// Semaphore used to ensure that all commands submitted have been finished before submitting the image to the queue
|
||||||
|
renderCompleteSemaphores.resize(swapChain.images.size());
|
||||||
|
for (auto& semaphore : renderCompleteSemaphores) {
|
||||||
|
VkSemaphoreCreateInfo semaphoreCI{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
|
||||||
|
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -915,7 +917,7 @@ public:
|
||||||
// Get the next swap chain image from the implementation
|
// Get the next swap chain image from the implementation
|
||||||
// Note that the implementation is free to return the images in any order, so we must use the acquire function and can't just cycle through the images/imageIndex on our own
|
// Note that the implementation is free to return the images in any order, so we must use the acquire function and can't just cycle through the images/imageIndex on our own
|
||||||
uint32_t imageIndex;
|
uint32_t imageIndex;
|
||||||
VkResult result = vkAcquireNextImageKHR(device, swapChain.swapChain, UINT64_MAX, presentCompleteSemaphores[currentSemaphore], VK_NULL_HANDLE, &imageIndex);
|
VkResult result = vkAcquireNextImageKHR(device, swapChain.swapChain, UINT64_MAX, presentCompleteSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
|
||||||
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
|
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||||
windowResize();
|
windowResize();
|
||||||
return;
|
return;
|
||||||
|
|
@ -1011,10 +1013,10 @@ public:
|
||||||
submitInfo.commandBufferCount = 1; // We submit a single command buffer
|
submitInfo.commandBufferCount = 1; // We submit a single command buffer
|
||||||
|
|
||||||
// Semaphore to wait upon before the submitted command buffer starts executing
|
// Semaphore to wait upon before the submitted command buffer starts executing
|
||||||
submitInfo.pWaitSemaphores = &presentCompleteSemaphores[currentSemaphore];
|
submitInfo.pWaitSemaphores = &presentCompleteSemaphores[currentFrame];
|
||||||
submitInfo.waitSemaphoreCount = 1;
|
submitInfo.waitSemaphoreCount = 1;
|
||||||
// Semaphore to be signaled when command buffers have completed
|
// Semaphore to be signaled when command buffers have completed
|
||||||
submitInfo.pSignalSemaphores = &renderCompleteSemaphores[currentSemaphore];
|
submitInfo.pSignalSemaphores = &renderCompleteSemaphores[imageIndex];
|
||||||
submitInfo.signalSemaphoreCount = 1;
|
submitInfo.signalSemaphoreCount = 1;
|
||||||
|
|
||||||
// Submit to the graphics queue passing a wait fence
|
// Submit to the graphics queue passing a wait fence
|
||||||
|
|
@ -1027,7 +1029,7 @@ public:
|
||||||
VkPresentInfoKHR presentInfo{};
|
VkPresentInfoKHR presentInfo{};
|
||||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||||
presentInfo.waitSemaphoreCount = 1;
|
presentInfo.waitSemaphoreCount = 1;
|
||||||
presentInfo.pWaitSemaphores = &renderCompleteSemaphores[currentSemaphore];
|
presentInfo.pWaitSemaphores = &renderCompleteSemaphores[imageIndex];
|
||||||
presentInfo.swapchainCount = 1;
|
presentInfo.swapchainCount = 1;
|
||||||
presentInfo.pSwapchains = &swapChain.swapChain;
|
presentInfo.pSwapchains = &swapChain.swapChain;
|
||||||
presentInfo.pImageIndices = &imageIndex;
|
presentInfo.pImageIndices = &imageIndex;
|
||||||
|
|
@ -1042,8 +1044,6 @@ public:
|
||||||
|
|
||||||
// Select the next frame to render to, based on the max. no. of concurrent frames
|
// Select the next frame to render to, based on the max. no. of concurrent frames
|
||||||
currentFrame = (currentFrame + 1) % MAX_CONCURRENT_FRAMES;
|
currentFrame = (currentFrame + 1) % MAX_CONCURRENT_FRAMES;
|
||||||
// Similar for the semaphores, which need to be unique to the swapchain images
|
|
||||||
currentSemaphore = (currentSemaphore + 1) % swapChain.imageCount;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,9 +95,8 @@ public:
|
||||||
VkCommandPool commandPool{ VK_NULL_HANDLE };
|
VkCommandPool commandPool{ VK_NULL_HANDLE };
|
||||||
std::array<VkCommandBuffer, MAX_CONCURRENT_FRAMES> commandBuffers{};
|
std::array<VkCommandBuffer, MAX_CONCURRENT_FRAMES> commandBuffers{};
|
||||||
|
|
||||||
// To select the correct sync and command objects, we need to keep track of the current frame and (swapchain) image index
|
// To select the correct sync and command objects, we need to keep track of the current frame
|
||||||
uint32_t currentFrame{ 0 };
|
uint32_t currentFrame{ 0 };
|
||||||
uint32_t currentSemaphore{ 0 };
|
|
||||||
|
|
||||||
VkPhysicalDeviceVulkan13Features enabledFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES };
|
VkPhysicalDeviceVulkan13Features enabledFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES };
|
||||||
|
|
||||||
|
|
@ -182,16 +181,19 @@ public:
|
||||||
fenceCI.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
fenceCI.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||||
VK_CHECK_RESULT(vkCreateFence(device, &fenceCI, nullptr, &waitFences[i]));
|
VK_CHECK_RESULT(vkCreateFence(device, &fenceCI, nullptr, &waitFences[i]));
|
||||||
}
|
}
|
||||||
// Semaphores are per swapchain image
|
// Semaphores are used for correct command ordering within a queue
|
||||||
presentCompleteSemaphores.resize(swapChain.images.size());
|
// Used to ensure that image presentation is complete before starting to submit again
|
||||||
renderCompleteSemaphores.resize(swapChain.images.size());
|
presentCompleteSemaphores.resize(MAX_CONCURRENT_FRAMES);
|
||||||
for (size_t i = 0; i < swapChain.images.size(); i++) {
|
for (auto& semaphore : presentCompleteSemaphores) {
|
||||||
// Semaphores are used for correct command ordering within a queue
|
|
||||||
VkSemaphoreCreateInfo semaphoreCI{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
|
VkSemaphoreCreateInfo semaphoreCI{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
|
||||||
// Semaphore used to ensure that image presentation is complete before starting to submit again
|
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore));
|
||||||
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &presentCompleteSemaphores[i]));
|
}
|
||||||
// Semaphore used to ensure that all commands submitted have been finished before submitting the image to the queue
|
// Render completion
|
||||||
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &renderCompleteSemaphores[i]));
|
// Semaphore used to ensure that all commands submitted have been finished before submitting the image to the queue
|
||||||
|
renderCompleteSemaphores.resize(swapChain.images.size());
|
||||||
|
for (auto& semaphore : renderCompleteSemaphores) {
|
||||||
|
VkSemaphoreCreateInfo semaphoreCI{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
|
||||||
|
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -701,7 +703,7 @@ public:
|
||||||
// Get the next swap chain image from the implementation
|
// Get the next swap chain image from the implementation
|
||||||
// Note that the implementation is free to return the images in any order, so we must use the acquire function and can't just cycle through the images/imageIndex on our own
|
// Note that the implementation is free to return the images in any order, so we must use the acquire function and can't just cycle through the images/imageIndex on our own
|
||||||
uint32_t imageIndex{ 0 };
|
uint32_t imageIndex{ 0 };
|
||||||
VkResult result = vkAcquireNextImageKHR(device, swapChain.swapChain, UINT64_MAX, presentCompleteSemaphores[currentSemaphore], VK_NULL_HANDLE, &imageIndex);
|
VkResult result = vkAcquireNextImageKHR(device, swapChain.swapChain, UINT64_MAX, presentCompleteSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
|
||||||
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
|
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||||
windowResize();
|
windowResize();
|
||||||
return;
|
return;
|
||||||
|
|
@ -788,10 +790,10 @@ public:
|
||||||
submitInfo.commandBufferCount = 1; // We submit a single command buffer
|
submitInfo.commandBufferCount = 1; // We submit a single command buffer
|
||||||
|
|
||||||
// Semaphore to wait upon before the submitted command buffer starts executing
|
// Semaphore to wait upon before the submitted command buffer starts executing
|
||||||
submitInfo.pWaitSemaphores = &presentCompleteSemaphores[currentSemaphore];
|
submitInfo.pWaitSemaphores = &presentCompleteSemaphores[currentFrame];
|
||||||
submitInfo.waitSemaphoreCount = 1;
|
submitInfo.waitSemaphoreCount = 1;
|
||||||
// Semaphore to be signaled when command buffers have completed
|
// Semaphore to be signaled when command buffers have completed
|
||||||
submitInfo.pSignalSemaphores = &renderCompleteSemaphores[currentSemaphore];
|
submitInfo.pSignalSemaphores = &renderCompleteSemaphores[imageIndex];
|
||||||
submitInfo.signalSemaphoreCount = 1;
|
submitInfo.signalSemaphoreCount = 1;
|
||||||
|
|
||||||
// Submit to the graphics queue passing a wait fence
|
// Submit to the graphics queue passing a wait fence
|
||||||
|
|
@ -802,7 +804,7 @@ public:
|
||||||
// This ensures that the image is not presented to the windowing system until all commands have been submitted
|
// This ensures that the image is not presented to the windowing system until all commands have been submitted
|
||||||
VkPresentInfoKHR presentInfo{ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
|
VkPresentInfoKHR presentInfo{ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
|
||||||
presentInfo.waitSemaphoreCount = 1;
|
presentInfo.waitSemaphoreCount = 1;
|
||||||
presentInfo.pWaitSemaphores = &renderCompleteSemaphores[currentSemaphore];
|
presentInfo.pWaitSemaphores = &renderCompleteSemaphores[imageIndex];
|
||||||
presentInfo.swapchainCount = 1;
|
presentInfo.swapchainCount = 1;
|
||||||
presentInfo.pSwapchains = &swapChain.swapChain;
|
presentInfo.pSwapchains = &swapChain.swapChain;
|
||||||
presentInfo.pImageIndices = &imageIndex;
|
presentInfo.pImageIndices = &imageIndex;
|
||||||
|
|
@ -815,8 +817,6 @@ public:
|
||||||
|
|
||||||
// Select the next frame to render to, based on the max. no. of concurrent frames
|
// Select the next frame to render to, based on the max. no. of concurrent frames
|
||||||
currentFrame = (currentFrame + 1) % MAX_CONCURRENT_FRAMES;
|
currentFrame = (currentFrame + 1) % MAX_CONCURRENT_FRAMES;
|
||||||
// Similar for the semaphores, which need to be unique to the swapchain images
|
|
||||||
currentSemaphore = (currentSemaphore + 1) % swapChain.imageCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override these as otherwise the base class would generate frame buffers and render passes
|
// Override these as otherwise the base class would generate frame buffers and render passes
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue