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

Skip to content

Commit d6503bc

Browse files
committed
Add explicit window resize handling for platforms that don't trigger VK_ERROR_OUT_OF_DATE_KHR
1 parent 0af8995 commit d6503bc

14 files changed

Lines changed: 204 additions & 15 deletions

03_Drawing_a_triangle/04_Swap_chain_recreation.md

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,67 @@ currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
182182

183183
The `vkQueuePresentKHR` function returns the same values with the same meaning.
184184
In this case we will also recreate the swap chain if it is suboptimal, because
185-
we want the best possible result. Try to run it and resize the window to see if
186-
the framebuffer is indeed resized properly with the window.
185+
we want the best possible result.
186+
187+
## Handling resizes explicitly
188+
189+
Although many drivers and platforms trigger `VK_ERROR_OUT_OF_DATE_KHR` automatically after a window resize, it is not guaranteed to happen. That's why we'll add some extra code to also handle resizes explicitly. First add a new member variable that flags that a resize has happened:
190+
191+
```c++
192+
std::vector<VkFence> inFlightFences;
193+
size_t currentFrame = 0;
194+
195+
bool framebufferResized = false;
196+
```
197+
198+
The `drawFrame` function should then be modified to also check for this flag:
199+
200+
```c++
201+
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
202+
framebufferResized = false;
203+
recreateSwapChain();
204+
} else if (result != VK_SUCCESS) {
205+
...
206+
}
207+
```
208+
209+
Now to actually detect resizes we can use the `glfwSetFramebufferSizeCallback` function in the GLFW framework to set up a callback:
210+
211+
```c++
212+
void initWindow() {
213+
glfwInit();
214+
215+
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
216+
217+
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
218+
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
219+
}
220+
221+
static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {
222+
223+
}
224+
```
225+
226+
The reason that we're creating a `static` function as a callback is because GLFW does not know how to properly call a member function with the right `this` pointer to our `HelloTriangleApplication` instance.
227+
228+
However, we do get a reference to the `GLFWwindow` in the callback and there is another GLFW function that allows you to store an arbitrary pointer inside of it: `glfwSetWindowUserPointer`:
229+
230+
```c++
231+
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
232+
glfwSetWindowUserPointer(window, this);
233+
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
234+
```
235+
236+
This value can now be retrieved from within the callback with `glfwGetWindowUserPointer` to properly set the flag:
237+
238+
```c++
239+
static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {
240+
auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));
241+
app->framebufferResized = true;
242+
}
243+
```
244+
245+
Now try to run the program and resize the window to see if the framebuffer is indeed resized properly with the window.
187246
188247
## Handling minimization
189248

code/16_swap_chain_recreation.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,21 @@ class HelloTriangleApplication {
101101
std::vector<VkFence> inFlightFences;
102102
size_t currentFrame = 0;
103103

104+
bool framebufferResized = false;
105+
104106
void initWindow() {
105107
glfwInit();
106108

107109
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
108110

109111
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
112+
glfwSetWindowUserPointer(window, this);
113+
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
114+
}
115+
116+
static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {
117+
auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));
118+
app->framebufferResized = true;
110119
}
111120

112121
void initVulkan() {
@@ -696,7 +705,8 @@ class HelloTriangleApplication {
696705

697706
result = vkQueuePresentKHR(presentQueue, &presentInfo);
698707

699-
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
708+
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
709+
framebufferResized = false;
700710
recreateSwapChain();
701711
} else if (result != VK_SUCCESS) {
702712
throw std::runtime_error("failed to present swap chain image!");

code/17_vertex_input.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,21 @@ class HelloTriangleApplication {
140140
std::vector<VkFence> inFlightFences;
141141
size_t currentFrame = 0;
142142

143+
bool framebufferResized = false;
144+
143145
void initWindow() {
144146
glfwInit();
145147

146148
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
147149

148150
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
151+
glfwSetWindowUserPointer(window, this);
152+
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
153+
}
154+
155+
static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {
156+
auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));
157+
app->framebufferResized = true;
149158
}
150159

151160
void initVulkan() {
@@ -741,7 +750,8 @@ class HelloTriangleApplication {
741750

742751
result = vkQueuePresentKHR(presentQueue, &presentInfo);
743752

744-
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
753+
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
754+
framebufferResized = false;
745755
recreateSwapChain();
746756
} else if (result != VK_SUCCESS) {
747757
throw std::runtime_error("failed to present swap chain image!");

code/18_vertex_buffer.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,21 @@ class HelloTriangleApplication {
144144
std::vector<VkFence> inFlightFences;
145145
size_t currentFrame = 0;
146146

147+
bool framebufferResized = false;
148+
147149
void initWindow() {
148150
glfwInit();
149151

150152
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
151153

152154
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
155+
glfwSetWindowUserPointer(window, this);
156+
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
157+
}
158+
159+
static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {
160+
auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));
161+
app->framebufferResized = true;
153162
}
154163

155164
void initVulkan() {
@@ -797,7 +806,8 @@ class HelloTriangleApplication {
797806

798807
result = vkQueuePresentKHR(presentQueue, &presentInfo);
799808

800-
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
809+
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
810+
framebufferResized = false;
801811
recreateSwapChain();
802812
} else if (result != VK_SUCCESS) {
803813
throw std::runtime_error("failed to present swap chain image!");

code/19_staging_buffer.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,21 @@ class HelloTriangleApplication {
144144
std::vector<VkFence> inFlightFences;
145145
size_t currentFrame = 0;
146146

147+
bool framebufferResized = false;
148+
147149
void initWindow() {
148150
glfwInit();
149151

150152
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
151153

152154
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
155+
glfwSetWindowUserPointer(window, this);
156+
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
157+
}
158+
159+
static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {
160+
auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));
161+
app->framebufferResized = true;
153162
}
154163

155164
void initVulkan() {
@@ -845,7 +854,8 @@ class HelloTriangleApplication {
845854

846855
result = vkQueuePresentKHR(presentQueue, &presentInfo);
847856

848-
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
857+
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
858+
framebufferResized = false;
849859
recreateSwapChain();
850860
} else if (result != VK_SUCCESS) {
851861
throw std::runtime_error("failed to present swap chain image!");

code/20_index_buffer.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,21 @@ class HelloTriangleApplication {
151151
std::vector<VkFence> inFlightFences;
152152
size_t currentFrame = 0;
153153

154+
bool framebufferResized = false;
155+
154156
void initWindow() {
155157
glfwInit();
156158

157159
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
158160

159161
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
162+
glfwSetWindowUserPointer(window, this);
163+
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
164+
}
165+
166+
static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {
167+
auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));
168+
app->framebufferResized = true;
160169
}
161170

162171
void initVulkan() {
@@ -878,7 +887,8 @@ class HelloTriangleApplication {
878887

879888
result = vkQueuePresentKHR(presentQueue, &presentInfo);
880889

881-
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
890+
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
891+
framebufferResized = false;
882892
recreateSwapChain();
883893
} else if (result != VK_SUCCESS) {
884894
throw std::runtime_error("failed to present swap chain image!");

code/21_descriptor_layout.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,12 +164,21 @@ class HelloTriangleApplication {
164164
std::vector<VkFence> inFlightFences;
165165
size_t currentFrame = 0;
166166

167+
bool framebufferResized = false;
168+
167169
void initWindow() {
168170
glfwInit();
169171

170172
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
171173

172174
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
175+
glfwSetWindowUserPointer(window, this);
176+
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
177+
}
178+
179+
static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {
180+
auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));
181+
app->framebufferResized = true;
173182
}
174183

175184
void initVulkan() {
@@ -949,7 +958,8 @@ class HelloTriangleApplication {
949958

950959
result = vkQueuePresentKHR(presentQueue, &presentInfo);
951960

952-
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
961+
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
962+
framebufferResized = false;
953963
recreateSwapChain();
954964
} else if (result != VK_SUCCESS) {
955965
throw std::runtime_error("failed to present swap chain image!");

code/22_descriptor_sets.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,12 +167,21 @@ class HelloTriangleApplication {
167167
std::vector<VkFence> inFlightFences;
168168
size_t currentFrame = 0;
169169

170+
bool framebufferResized = false;
171+
170172
void initWindow() {
171173
glfwInit();
172174

173175
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
174176

175177
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
178+
glfwSetWindowUserPointer(window, this);
179+
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
180+
}
181+
182+
static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {
183+
auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));
184+
app->framebufferResized = true;
176185
}
177186

178187
void initVulkan() {
@@ -1006,7 +1015,8 @@ class HelloTriangleApplication {
10061015

10071016
result = vkQueuePresentKHR(presentQueue, &presentInfo);
10081017

1009-
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
1018+
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
1019+
framebufferResized = false;
10101020
recreateSwapChain();
10111021
} else if (result != VK_SUCCESS) {
10121022
throw std::runtime_error("failed to present swap chain image!");

code/23_texture_image.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,12 +173,21 @@ class HelloTriangleApplication {
173173
std::vector<VkFence> inFlightFences;
174174
size_t currentFrame = 0;
175175

176+
bool framebufferResized = false;
177+
176178
void initWindow() {
177179
glfwInit();
178180

179181
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
180182

181183
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
184+
glfwSetWindowUserPointer(window, this);
185+
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
186+
}
187+
188+
static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {
189+
auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));
190+
app->framebufferResized = true;
182191
}
183192

184193
void initVulkan() {
@@ -1161,7 +1170,8 @@ class HelloTriangleApplication {
11611170

11621171
result = vkQueuePresentKHR(presentQueue, &presentInfo);
11631172

1164-
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
1173+
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
1174+
framebufferResized = false;
11651175
recreateSwapChain();
11661176
} else if (result != VK_SUCCESS) {
11671177
throw std::runtime_error("failed to present swap chain image!");

code/24_sampler.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,21 @@ class HelloTriangleApplication {
175175
std::vector<VkFence> inFlightFences;
176176
size_t currentFrame = 0;
177177

178+
bool framebufferResized = false;
179+
178180
void initWindow() {
179181
glfwInit();
180182

181183
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
182184

183185
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
186+
glfwSetWindowUserPointer(window, this);
187+
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
188+
}
189+
190+
static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {
191+
auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));
192+
app->framebufferResized = true;
184193
}
185194

186195
void initVulkan() {
@@ -1197,7 +1206,8 @@ class HelloTriangleApplication {
11971206

11981207
result = vkQueuePresentKHR(presentQueue, &presentInfo);
11991208

1200-
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
1209+
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
1210+
framebufferResized = false;
12011211
recreateSwapChain();
12021212
} else if (result != VK_SUCCESS) {
12031213
throw std::runtime_error("failed to present swap chain image!");

0 commit comments

Comments
 (0)