Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions attachments/17_swap_chain_recreation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,8 @@ class HelloTriangleApplication
{
auto &commandBuffer = commandBuffers[frameIndex];
commandBuffer.begin({});
// Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL

// Before starting rendering, transition the swapchain image to vk::ImageLayout::eColorAttachmentOptimal
transition_image_layout(
imageIndex,
vk::ImageLayout::eUndefined,
Expand Down Expand Up @@ -453,7 +454,8 @@ class HelloTriangleApplication
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

// After rendering, transition the swapchain image to vk::ImageLayout::ePresentSrcKHR
transition_image_layout(
imageIndex,
vk::ImageLayout::eColorAttachmentOptimal,
Expand Down Expand Up @@ -535,7 +537,7 @@ class HelloTriangleApplication
}
// On other success codes than eSuccess and eSuboptimalKHR we just throw an exception.
// On any error code, aquireNextImage already threw an exception.
else if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR)
if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR)
{
assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady);
throw std::runtime_error("failed to acquire swap chain image!");
Expand Down
42 changes: 22 additions & 20 deletions en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@ Create a new `recreateSwapChain` function that calls `createSwapChain` and all t

[,c++]
----
void recreateSwapChain() {
void recreateSwapChain()
{
device.waitIdle();

createSwapChain();
createImageViews();
}
----

We first call `vkDeviceWaitIdle`, because just like in the last chapter, we shouldn't touch resources that may still be in use.
We first call `vk::raii::Device::waitIdle`, because just like in the last chapter, we shouldn't touch resources that may still be in use.
Obviously, we'll have to recreate the swap chain itself.
The image views need to be recreated because they are based directly on the swap chain images.

Expand All @@ -32,11 +33,12 @@ Let's call it `cleanupSwapChain`:

[,c++]
----
void cleanupSwapChain() {

void cleanupSwapChain()
{
}

void recreateSwapChain() {
void recreateSwapChain()
{
device.waitIdle();

cleanupSwapChain();
Expand All @@ -55,12 +57,14 @@ We'll move the cleanup code of all objects that are recreated as part of a swap

[,c++]
----
void cleanupSwapChain() {
void cleanupSwapChain()
{
swapChainImageViews.clear();
swapChain = nullptr;
}

void cleanup() {
void cleanup()
{
cleanupSwapChain();

glfwDestroyWindow(window);
Expand All @@ -73,7 +77,7 @@ Note that in `chooseSwapExtent` we already query the new window resolution to ma
That's all it takes to recreate the swap chain!
However, the disadvantage of this approach is that we need to stop all renderings before creating the new swap chain.
It is possible to create a new swap chain while drawing commands on an image from the old swap chain are still in-flight.
You need to pass the previous swap chain to the `oldSwapchain` field in the `VkSwapchainCreateInfoKHR` struct and destroy the old swap chain as soon as you've finished using it.
You need to pass the previous swap chain to the `oldSwapchain` field in the `vk::SwapchainCreateInfoKHR` struct and destroy the old swap chain as soon as you've finished using it.

== Suboptimal or out-of-date swap chain

Expand Down Expand Up @@ -120,8 +124,6 @@ else
// There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception.
assert(result == vk::Result::eSuccess);
}

frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT;
----

The `vk::raii::Queue::presentKHR` function returns the same values with the same meaning.
Expand All @@ -135,9 +137,8 @@ const vk::PresentInfoKHR presentInfoKHR{.waitSemaphoreCount = 1,
.pSwapchains = &*swapChain,
.pImageIndices = &imageIndex};
result = queue.presentKHR(presentInfoKHR);
if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized)
if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR))
{
framebufferResized = false;
recreateSwapChain();
}
else
Expand Down Expand Up @@ -176,7 +177,7 @@ if (result == vk::Result::eErrorOutOfDateKHR)
recreateSwapChain();
return;
}
else if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR)
if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR)
{
assert(result == vk::Result::eTimeout || result == vk::Result::eNotReady);
throw std::runtime_error("failed to acquire swap chain image!");
Expand All @@ -194,16 +195,15 @@ First, add a new member variable that flags that a resize has happened:

[,c++]
----
std::vector<vk::raii::Fence> inFlightFences;

bool framebufferResized = false;
----

The `drawFrame` function should then be modified to also check for this flag:

[,c++]
----
if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) {
if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized)
{
framebufferResized = false;
recreateSwapChain();
}
Expand All @@ -218,7 +218,8 @@ Now, to actually detect resizes, we can use the `glfwSetFramebufferSizeCallback`

[,c++]
----
void initWindow() {
void initWindow()
{
glfwInit();

glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
Expand All @@ -227,8 +228,8 @@ void initWindow() {
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
}

static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {

static void framebufferResizeCallback(GLFWwindow* window, int width, int height)
{
}
----

Expand All @@ -247,7 +248,8 @@ This value can now be retrieved from within the callback with `glfwGetWindowUser

[,c++]
----
static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {
static void framebufferResizeCallback(GLFWwindow* window, int width, int height)
{
auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));
app->framebufferResized = true;
}
Expand Down
Loading