Skip to content

Commit eede873

Browse files
committed
Recreate semaphores on swapchain resize and improve attachment transitions for dynamic rendering.
1 parent 040f4a5 commit eede873

File tree

2 files changed

+127
-70
lines changed

2 files changed

+127
-70
lines changed

attachments/33_vulkan_profiles.cpp

Lines changed: 75 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ class HelloTriangleApplication {
162162
void initWindow() {
163163
glfwInit();
164164
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
165+
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
166+
165167
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan Profiles Demo", nullptr, nullptr);
166168
glfwSetWindowUserPointer(window, this);
167169
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
@@ -221,23 +223,11 @@ class HelloTriangleApplication {
221223
}
222224

223225
void cleanupSwapChain() {
224-
colorImageView = nullptr;
225-
colorImage = nullptr;
226-
colorImageMemory = nullptr;
227-
228-
depthImageView = nullptr;
229-
depthImage = nullptr;
230-
depthImageMemory = nullptr;
231-
232-
for (auto& framebuffer : swapChainFramebuffers) {
233-
framebuffer = nullptr;
234-
}
226+
swapChainFramebuffers.clear();
227+
swapChainImageViews.clear();
235228

236-
for (auto& imageView : swapChainImageViews) {
237-
imageView = nullptr;
238-
}
239-
240-
swapChain = nullptr;
229+
// Semaphores tied to swapchain image indices need to be rebuilt on resize
230+
presentCompleteSemaphore.clear();
241231
}
242232

243233
void cleanup() {
@@ -268,6 +258,13 @@ class HelloTriangleApplication {
268258

269259
createColorResources();
270260
createDepthResources();
261+
262+
// Recreate per-swapchain-image present semaphores after resize
263+
presentCompleteSemaphore.reserve(swapChainImages.size());
264+
vk::SemaphoreCreateInfo semaphoreInfo{};
265+
for (size_t i = 0; i < swapChainImages.size(); ++i) {
266+
presentCompleteSemaphore.push_back(device.createSemaphore(semaphoreInfo));
267+
}
271268
}
272269

273270
void createInstance() {
@@ -1338,8 +1335,45 @@ class HelloTriangleApplication {
13381335
void recordCommandBuffer(uint32_t imageIndex) {
13391336
commandBuffers[currentFrame].begin({});
13401337

1341-
// Transition the swapchain image to the correct layout for rendering
1342-
vk::ImageMemoryBarrier imageBarrier{
1338+
// Transition the attachments to the correct layouts for dynamic rendering
1339+
// 1) Multisampled color attachment image -> ColorAttachmentOptimal
1340+
vk::ImageMemoryBarrier colorAttachmentBarrier{
1341+
.srcAccessMask = vk::AccessFlagBits::eNone,
1342+
.dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite,
1343+
.oldLayout = vk::ImageLayout::eUndefined,
1344+
.newLayout = vk::ImageLayout::eColorAttachmentOptimal,
1345+
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
1346+
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
1347+
.image = *colorImage,
1348+
.subresourceRange = {
1349+
.aspectMask = vk::ImageAspectFlagBits::eColor,
1350+
.baseMipLevel = 0,
1351+
.levelCount = 1,
1352+
.baseArrayLayer = 0,
1353+
.layerCount = 1
1354+
}
1355+
};
1356+
1357+
// 2) Depth attachment image -> DepthStencilAttachmentOptimal
1358+
vk::ImageMemoryBarrier depthAttachmentBarrier{
1359+
.srcAccessMask = vk::AccessFlagBits::eNone,
1360+
.dstAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite,
1361+
.oldLayout = vk::ImageLayout::eUndefined,
1362+
.newLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal,
1363+
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
1364+
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
1365+
.image = *depthImage,
1366+
.subresourceRange = {
1367+
.aspectMask = vk::ImageAspectFlagBits::eDepth,
1368+
.baseMipLevel = 0,
1369+
.levelCount = 1,
1370+
.baseArrayLayer = 0,
1371+
.layerCount = 1
1372+
}
1373+
};
1374+
1375+
// 3) Resolve (swapchain) image -> ColorAttachmentOptimal
1376+
vk::ImageMemoryBarrier swapchainResolveBarrier{
13431377
.srcAccessMask = vk::AccessFlagBits::eNone,
13441378
.dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite,
13451379
.oldLayout = vk::ImageLayout::eUndefined,
@@ -1358,11 +1392,11 @@ class HelloTriangleApplication {
13581392

13591393
commandBuffers[currentFrame].pipelineBarrier(
13601394
vk::PipelineStageFlagBits::eTopOfPipe,
1361-
vk::PipelineStageFlagBits::eColorAttachmentOutput,
1395+
vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests,
13621396
vk::DependencyFlagBits::eByRegion,
13631397
std::array<vk::MemoryBarrier, 0>{},
13641398
std::array<vk::BufferMemoryBarrier, 0>{},
1365-
std::array<vk::ImageMemoryBarrier, 1>{imageBarrier}
1399+
std::array<vk::ImageMemoryBarrier, 3>{colorAttachmentBarrier, depthAttachmentBarrier, swapchainResolveBarrier}
13661400
);
13671401

13681402
// Clear values for color and depth
@@ -1548,28 +1582,29 @@ class HelloTriangleApplication {
15481582
};
15491583
queue.submit(submitInfo, *inFlightFences[currentFrame]);
15501584

1551-
const vk::PresentInfoKHR presentInfoKHR{
1552-
.waitSemaphoreCount = 1,
1553-
.pWaitSemaphores = &*presentCompleteSemaphore[imageIndex],
1554-
.swapchainCount = 1,
1555-
.pSwapchains = &*swapChain,
1556-
.pImageIndices = &imageIndex
1557-
};
1558-
1559-
vk::Result result;
15601585
try {
1561-
result = queue.presentKHR(presentInfoKHR);
1562-
} catch (vk::OutOfDateKHRError&) {
1563-
result = vk::Result::eErrorOutOfDateKHR;
1564-
}
1565-
1566-
if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) {
1567-
framebufferResized = false;
1568-
recreateSwapChain();
1569-
} else if (result != vk::Result::eSuccess) {
1570-
throw std::runtime_error("failed to present swap chain image!");
1586+
const vk::PresentInfoKHR presentInfoKHR{
1587+
.waitSemaphoreCount = 1,
1588+
.pWaitSemaphores = &*presentCompleteSemaphore[imageIndex],
1589+
.swapchainCount = 1,
1590+
.pSwapchains = &*swapChain,
1591+
.pImageIndices = &imageIndex
1592+
};
1593+
auto result = queue.presentKHR(presentInfoKHR);
1594+
if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) {
1595+
framebufferResized = false;
1596+
recreateSwapChain();
1597+
} else if (result != vk::Result::eSuccess) {
1598+
throw std::runtime_error("failed to present swap chain image!");
1599+
}
1600+
} catch (const vk::SystemError& e) {
1601+
if (e.code().value() == static_cast<int>(vk::Result::eErrorOutOfDateKHR)) {
1602+
recreateSwapChain();
1603+
return;
1604+
} else {
1605+
throw;
1606+
}
15711607
}
1572-
15731608
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
15741609
}
15751610

attachments/34_android.cpp

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ class HelloTriangleApplication {
243243
glfwInit();
244244
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
245245
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
246+
246247
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan Cross-Platform", nullptr, nullptr);
247248
glfwSetWindowUserPointer(window, this);
248249
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
@@ -1177,7 +1178,7 @@ class HelloTriangleApplication {
11771178
// Create synchronization objects
11781179
void createSyncObjects() {
11791180
imageAvailableSemaphores.reserve(MAX_FRAMES_IN_FLIGHT);
1180-
renderFinishedSemaphores.reserve(MAX_FRAMES_IN_FLIGHT);
1181+
renderFinishedSemaphores.reserve(swapChainImages.size());
11811182
inFlightFences.reserve(MAX_FRAMES_IN_FLIGHT);
11821183

11831184
vk::SemaphoreCreateInfo semaphoreInfo{};
@@ -1187,22 +1188,21 @@ class HelloTriangleApplication {
11871188

11881189
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
11891190
imageAvailableSemaphores.push_back(device.createSemaphore(semaphoreInfo));
1190-
renderFinishedSemaphores.push_back(device.createSemaphore(semaphoreInfo));
11911191
inFlightFences.push_back(device.createFence(fenceInfo));
11921192
}
1193+
1194+
for (size_t i = 0; i < swapChainImages.size(); i++) {
1195+
renderFinishedSemaphores.push_back(device.createSemaphore(semaphoreInfo));
1196+
}
11931197
}
11941198

11951199
// Clean up swap chain
11961200
void cleanupSwapChain() {
1197-
for (auto& framebuffer : swapChainFramebuffers) {
1198-
framebuffer = nullptr;
1199-
}
1201+
swapChainFramebuffers.clear();
1202+
swapChainImageViews.clear();
12001203

1201-
for (auto& imageView : swapChainImageViews) {
1202-
imageView = nullptr;
1203-
}
1204-
1205-
swapChain = nullptr;
1204+
// Semaphores tied to swapchain image indices need to be rebuilt on resize
1205+
renderFinishedSemaphores.clear();
12061206
}
12071207

12081208
// Record command buffer
@@ -1281,47 +1281,69 @@ class HelloTriangleApplication {
12811281
.commandBufferCount = 1,
12821282
.pCommandBuffers = &*commandBuffers[currentFrame],
12831283
.signalSemaphoreCount = 1,
1284-
.pSignalSemaphores = &*renderFinishedSemaphores[currentFrame]
1284+
.pSignalSemaphores = &*renderFinishedSemaphores[imageIndex]
12851285
};
12861286
queue.submit(submitInfo, *inFlightFences[currentFrame]);
12871287

1288-
const vk::PresentInfoKHR presentInfoKHR{
1289-
.waitSemaphoreCount = 1,
1290-
.pWaitSemaphores = &*renderFinishedSemaphores[currentFrame],
1291-
.swapchainCount = 1,
1292-
.pSwapchains = &*swapChain,
1293-
.pImageIndices = &imageIndex
1294-
};
1295-
1296-
vk::Result result;
12971288
try {
1298-
result = queue.presentKHR(presentInfoKHR);
1299-
} catch (vk::OutOfDateKHRError&) {
1300-
result = vk::Result::eErrorOutOfDateKHR;
1301-
}
1289+
const vk::PresentInfoKHR presentInfoKHR{
1290+
.waitSemaphoreCount = 1,
1291+
.pWaitSemaphores = &*renderFinishedSemaphores[imageIndex],
1292+
.swapchainCount = 1,
1293+
.pSwapchains = &*swapChain,
1294+
.pImageIndices = &imageIndex
1295+
};
13021296

1303-
if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) {
1304-
framebufferResized = false;
1305-
recreateSwapChain();
1306-
} else if (result != vk::Result::eSuccess) {
1307-
throw std::runtime_error("Failed to present swap chain image");
1297+
vk::Result result = queue.presentKHR(presentInfoKHR);
1298+
1299+
if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) {
1300+
framebufferResized = false;
1301+
recreateSwapChain();
1302+
} else if (result != vk::Result::eSuccess) {
1303+
throw std::runtime_error("Failed to present swap chain image");
1304+
}
1305+
} catch (const vk::SystemError& e) {
1306+
if (e.code().value() == static_cast<int>(vk::Result::eErrorOutOfDateKHR)) {
1307+
recreateSwapChain();
1308+
return;
1309+
} else {
1310+
throw;
1311+
}
13081312
}
13091313

13101314
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
13111315
}
13121316

13131317
// Recreate swap chain
13141318
void recreateSwapChain() {
1319+
#if !PLATFORM_ANDROID
1320+
// On desktop, wait until the framebuffer has a non-zero size (e.g., when window is minimized)
1321+
int width = 0, height = 0;
1322+
if (window) {
1323+
glfwGetFramebufferSize(window, &width, &height);
1324+
while (width == 0 || height == 0) {
1325+
glfwGetFramebufferSize(window, &width, &height);
1326+
glfwWaitEvents();
1327+
}
1328+
}
1329+
#endif
13151330
// Wait for device to finish operations
13161331
device.waitIdle();
13171332

13181333
// Clean up old swap chain
13191334
cleanupSwapChain();
13201335

1321-
// Create new swap chain
1336+
// Create new swap chain and dependent resources
13221337
createSwapChain();
13231338
createImageViews();
13241339
createFramebuffers();
1340+
1341+
// Recreate per-swapchain-image present semaphores for presenting
1342+
renderFinishedSemaphores.reserve(swapChainImages.size());
1343+
vk::SemaphoreCreateInfo semaphoreInfo{};
1344+
for (size_t i = 0; i < swapChainImages.size(); ++i) {
1345+
renderFinishedSemaphores.push_back(device.createSemaphore(semaphoreInfo));
1346+
}
13251347
}
13261348

13271349
// Get required extensions

0 commit comments

Comments
 (0)