Skip to content

Commit 6cf1473

Browse files
committed
Handle framebuffer resize with swapchain recreation
- Add `framebufferResizeCallback` to monitor window resize events. - Implement `recreateSwapChain` to handle swapchain rebuild during resize scenarios. - Adjust `drawFrame` logic to manage `ErrorOutOfDateKHR` and `SuboptimalKHR` results robustly.
1 parent eede873 commit 6cf1473

File tree

1 file changed

+54
-4
lines changed

1 file changed

+54
-4
lines changed

attachments/37_multithreading.cpp

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ class MultithreadedApplication {
189189

190190
double lastFrameTime = 0.0;
191191

192-
// Removed resize-related variables and FSM state management as per simplification request
192+
bool framebufferResized = false;
193193

194194
double lastTime = 0.0f;
195195

@@ -240,7 +240,7 @@ class MultithreadedApplication {
240240
[]( const auto & format ) { return format.format == vk::Format::eB8G8R8A8Srgb && format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear; } );
241241
return formatIt != availableFormats.end() ? *formatIt : availableFormats[0];
242242
}
243-
243+
244244
static vk::PresentModeKHR chooseSwapPresentMode(const std::vector<vk::PresentModeKHR>& availablePresentModes) {
245245
assert(std::ranges::any_of(availablePresentModes, [](auto presentMode){ return presentMode == vk::PresentModeKHR::eFifo; }));
246246
return std::ranges::any_of(availablePresentModes,
@@ -282,14 +282,22 @@ class MultithreadedApplication {
282282
glfwInit();
283283

284284
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
285-
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
285+
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
286286

287287
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan Multithreading", nullptr, nullptr);
288288
glfwSetWindowUserPointer(window, this);
289+
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
289290

290291
lastTime = glfwGetTime();
291292
}
292293

294+
static void framebufferResizeCallback(GLFWwindow* window, int, int) {
295+
auto app = reinterpret_cast<MultithreadedApplication*>(glfwGetWindowUserPointer(window));
296+
if (app) {
297+
app->framebufferResized = true;
298+
}
299+
}
300+
293301
void initVulkan() {
294302
createInstance();
295303
createSurface();
@@ -439,6 +447,28 @@ class MultithreadedApplication {
439447
swapChain = nullptr;
440448
}
441449

450+
void recreateSwapChain() {
451+
int width = 0, height = 0;
452+
glfwGetFramebufferSize(window, &width, &height);
453+
while (width == 0 || height == 0) {
454+
glfwGetFramebufferSize(window, &width, &height);
455+
glfwWaitEvents();
456+
}
457+
device.waitIdle();
458+
459+
cleanupSwapChain();
460+
461+
createSwapChain();
462+
createImageViews();
463+
createComputeDescriptorSetLayout();
464+
createGraphicsPipeline();
465+
createComputePipeline();
466+
createShaderStorageBuffers();
467+
createUniformBuffers();
468+
createDescriptorPool();
469+
createComputeDescriptorSets();
470+
}
471+
442472
void stopThreads() {
443473
shouldExit.store(true, std::memory_order_release);
444474

@@ -1075,10 +1105,22 @@ class MultithreadedApplication {
10751105
// Wait for the previous frame to finish
10761106
while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX))
10771107
;
1078-
device.resetFences(*inFlightFences[currentFrame]);
1108+
1109+
// If the framebuffer was resized, rebuild the swap chain before acquiring a new image
1110+
if (framebufferResized) {
1111+
recreateSwapChain();
1112+
framebufferResized = false;
1113+
return;
1114+
}
10791115

10801116
// Acquire the next image
10811117
auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *imageAvailableSemaphores[currentFrame], nullptr);
1118+
if (result == vk::Result::eErrorOutOfDateKHR) {
1119+
recreateSwapChain();
1120+
return;
1121+
} else if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) {
1122+
throw std::runtime_error("failed to acquire swap chain image!");
1123+
}
10821124

10831125
// Update timeline values for synchronization
10841126
uint64_t computeWaitValue = timelineValue;
@@ -1168,6 +1210,7 @@ class MultithreadedApplication {
11681210
// Submit graphics work
11691211
{
11701212
std::lock_guard<std::mutex> lock(queueSubmitMutex);
1213+
device.resetFences(*inFlightFences[currentFrame]);
11711214
queue.submit(graphicsSubmitInfo, *inFlightFences[currentFrame]);
11721215
}
11731216

@@ -1194,6 +1237,13 @@ class MultithreadedApplication {
11941237
};
11951238

11961239
result = queue.presentKHR(presentInfo);
1240+
if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) {
1241+
framebufferResized = false;
1242+
recreateSwapChain();
1243+
return;
1244+
} else if (result != vk::Result::eSuccess) {
1245+
throw std::runtime_error("failed to present swap chain image!");
1246+
}
11971247

11981248
// Move to the next frame
11991249
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;

0 commit comments

Comments
 (0)