From 55c371a081842fe7ecfec63b9283e67964062059 Mon Sep 17 00:00:00 2001 From: sammifs Date: Fri, 3 Apr 2026 19:32:25 +0200 Subject: [PATCH] Fix invalid swapchain semaphore reuse by making present-finish semaphores per swapchain image Use a separate semaphore for each swapchain image instead of reusing present-wait semaphores per frame in flight. Signal and present using readyPresentSemaphores[imageIndex] so a semaphore is only reused after its swapchain image has been reacquired. Also rename renderFinishedSemaphores to readyPresentSemaphores for clarity. --- src/lve_swap_chain.cpp | 16 +++++++++++----- src/lve_swap_chain.hpp | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/lve_swap_chain.cpp b/src/lve_swap_chain.cpp index fb55fdc..2bf4a0b 100644 --- a/src/lve_swap_chain.cpp +++ b/src/lve_swap_chain.cpp @@ -57,10 +57,12 @@ LveSwapChain::~LveSwapChain() { // cleanup synchronization objects for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - vkDestroySemaphore(device.device(), renderFinishedSemaphores[i], nullptr); vkDestroySemaphore(device.device(), imageAvailableSemaphores[i], nullptr); vkDestroyFence(device.device(), inFlightFences[i], nullptr); } + for (size_t i = 0; i < imageCount(); i++) { + vkDestroySemaphore(device.device(), readyPresentSemaphores[i], nullptr); + } } VkResult LveSwapChain::acquireNextImage(uint32_t *imageIndex) { @@ -100,7 +102,7 @@ VkResult LveSwapChain::submitCommandBuffers(const VkCommandBuffer *buffers, uint submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = buffers; - VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[currentFrame]}; + VkSemaphore signalSemaphores[] = {readyPresentSemaphores[*imageIndex]}; submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = signalSemaphores; @@ -348,7 +350,7 @@ void LveSwapChain::createDepthResources() { void LveSwapChain::createSyncObjects() { imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT); - renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT); + readyPresentSemaphores.resize(imageCount()); inFlightFences.resize(MAX_FRAMES_IN_FLIGHT); imagesInFlight.resize(imageCount(), VK_NULL_HANDLE); @@ -362,12 +364,16 @@ void LveSwapChain::createSyncObjects() { for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { if (vkCreateSemaphore(device.device(), &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS || - vkCreateSemaphore(device.device(), &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != - VK_SUCCESS || vkCreateFence(device.device(), &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) { throw std::runtime_error("failed to create synchronization objects for a frame!"); } } + for (size_t i = 0; i < imageCount(); i++) { + if (vkCreateSemaphore(device.device(), &semaphoreInfo, nullptr, &readyPresentSemaphores[i]) != + VK_SUCCESS) { + throw std::runtime_error("failed to create synchronization objects for a frame!"); + } + } } VkSurfaceFormatKHR LveSwapChain::chooseSwapSurfaceFormat( diff --git a/src/lve_swap_chain.hpp b/src/lve_swap_chain.hpp index 0a1cb63..b7e574c 100644 --- a/src/lve_swap_chain.hpp +++ b/src/lve_swap_chain.hpp @@ -83,7 +83,7 @@ class LveSwapChain { std::shared_ptr oldSwapChain; std::vector imageAvailableSemaphores; - std::vector renderFinishedSemaphores; + std::vector readyPresentSemaphores; std::vector inFlightFences; std::vector imagesInFlight; size_t currentFrame = 0;