@@ -36,58 +36,111 @@ avoid this by using dynamic state for the viewports and scissor rectangles.
3636Finally, the framebuffers and command buffers also directly depend on the swap
3737chain 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