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

Skip to content

Commit 4682b42

Browse files
committed
Remove VDeleter from swap chain recreation chapter
1 parent e15039a commit 4682b42

2 files changed

Lines changed: 174 additions & 143 deletions

File tree

03_Drawing_a_triangle/04_Swap_chain_recreation.md

Lines changed: 86 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -36,58 +36,111 @@ avoid this by using dynamic state for the viewports and scissor rectangles.
3636
Finally, the framebuffers and command buffers also directly depend on the swap
3737
chain images.
3838

39-
Because of our handy `VDeleter` construct, most of the functions will work fine
40-
for recreation and will automatically clean up the old objects. However, the
41-
`createSwapChain` and `createCommandBuffers` functions still need some
42-
adjustments.
39+
To make sure that the old versions of these objects are cleaned up before
40+
recreating them, we should move some of the cleanup code to a separate function
41+
that we can call from the `recreateSwapChain` function. Let's call it
42+
`cleanupSwapChainDependents`:
4343

4444
```c++
45-
VkSwapchainKHR oldSwapChain = swapChain;
46-
createInfo.oldSwapchain = oldSwapChain;
47-
48-
VkSwapchainKHR newSwapChain;
49-
if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &newSwapChain) != VK_SUCCESS) {
50-
throw std::runtime_error("failed to create swap chain!");
45+
void cleanupSwapChainDependents() {
46+
5147
}
5248

53-
swapChain = newSwapChain;
49+
void recreateSwapChain() {
50+
vkDeviceWaitIdle(device);
51+
52+
cleanupSwapChainDependents();
53+
54+
createSwapChain();
55+
createImageViews();
56+
createRenderPass();
57+
createGraphicsPipeline();
58+
createFramebuffers();
59+
createCommandBuffers();
60+
}
5461
```
5562

56-
We need to pass the previous swap chain object in the `oldSwapchain` parameter
57-
of `VkSwapchainCreateInfoKHR` to indicate that we intend to replace it. The old
58-
swap chain needs to stick around until after the new swap chain has been
59-
created, which means that we can't directly write the new handle to `swapChain`.
60-
The `VDeleter` would clear the old object before `vkCreateSwapchainKHR` has a
61-
chance to execute. That's why we use the temporary `newSwapChain` variable.
63+
we'll move the cleanup code of all objects that are recreated after a swap chain
64+
renewal from `cleanup` to `cleanupSwapChainDependents`:
6265

6366
```c++
64-
swapChain = newSwapChain;
67+
void cleanupSwapChainDependents() {
68+
for (size_t i = 0; i < swapChainFramebuffers.size(); i++) {
69+
vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr);
70+
}
71+
72+
vkFreeCommandBuffers(device, commandPool, static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());
73+
74+
vkDestroyPipeline(device, graphicsPipeline, nullptr);
75+
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
76+
vkDestroyRenderPass(device, renderPass, nullptr);
77+
78+
for (size_t i = 0; i < swapChainImageViews.size(); i++) {
79+
vkDestroyImageView(device, swapChainImageViews[i], nullptr);
80+
}
81+
}
82+
83+
void cleanup() {
84+
cleanupSwapChainDependents();
85+
86+
vkDestroySemaphore(device, renderFinishedSemaphore, nullptr);
87+
vkDestroySemaphore(device, imageAvailableSemaphore, nullptr);
88+
89+
vkDestroyCommandPool(device, commandPool, nullptr);
90+
91+
vkDestroySwapchainKHR(device, swapChain, nullptr);
92+
vkDestroyDevice(device, nullptr);
93+
DestroyDebugReportCallbackEXT(instance, callback, nullptr);
94+
vkDestroySurfaceKHR(instance, surface, nullptr);
95+
vkDestroyInstance(instance, nullptr);
96+
97+
glfwDestroyWindow(window);
98+
99+
glfwTerminate();
100+
}
65101
```
66102

67-
This line will actually destroy the old swap chain and replace the handle with
68-
the handle of the new swap chain.
103+
We could recreate the command pool from scratch, but that is rather wasteful.
104+
Instead I've opted to clean up the existing command buffers with the
105+
`vkFreeCommandBuffers` function. This way we can reuse the existing pool to
106+
allocate the new command buffers.
107+
108+
So why aren't we also destroying the swap chain itself in this function? Vulkan
109+
requires us to keep the old swap chain around until after the new one has been
110+
created. We're now going to use a new field in the `VkSwapchainCreateInfoKHR`
111+
struct called `oldSwapChain`:
69112

70-
The problem with `createCommandBuffers` is that it doesn't free the old command
71-
buffers. There are two ways to solve this:
113+
```c++
114+
createInfo.oldSwapchain = swapChain;
72115

73-
* Call `createCommandPool` as well, which will automatically free the old
74-
command buffers
75-
* Extend `createCommandBuffers` to free any previous command buffers
116+
if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
117+
throw std::runtime_error("failed to create swap chain!");
118+
}
119+
```
76120

77-
As there isn't really a need to recreate the command pool itself, I've chosen to
78-
go for the second solution in this tutorial.
121+
We need to pass the previous swap chain object in the `oldSwapchain` parameter
122+
of `VkSwapchainCreateInfoKHR` to indicate that we intend to replace it. After
123+
the new swap chain has been successfully created, we can destroy the old one:
79124

80125
```c++
81-
if (commandBuffers.size() > 0) {
82-
vkFreeCommandBuffers(device, commandPool, commandBuffers.size(), commandBuffers.data());
126+
if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
127+
throw std::runtime_error("failed to create swap chain!");
83128
}
84129

85-
commandBuffers.resize(swapChainFramebuffers.size());
130+
if (createInfo.oldSwapchain != VK_NULL_HANDLE) {
131+
vkDestroySwapchainKHR(device, createInfo.oldSwapchain, nullptr);
132+
}
133+
```
134+
135+
To make sure that the old swap chain is set to `VK_NULL_HANDLE` when the program
136+
has just started, make sure that the class member variable is properly
137+
initialized:
138+
139+
```c++
140+
VkSwapchainKHR swapChain = VK_NULL_HANDLE;
86141
```
87142

88-
The `createCommandBuffers` function now first checks if the `commandBuffers`
89-
vector already contains previous command buffers, and if so, frees them. That's
90-
all it takes to recreate the swap chain!
143+
That's all it takes to recreate the swap chain!
91144

92145
## Window resizing
93146

0 commit comments

Comments
 (0)