From f6015c9f46cde7c86bd99408e892bf15eeb54046 Mon Sep 17 00:00:00 2001 From: Max Van den Eynde Date: Fri, 2 Oct 2026 07:55:16 +0200 Subject: [PATCH 1/2] Fix Vulkan presentation semaphore reuse --- src/command_buffer.cpp | 13 ++++++------- src/vulkan/vulkan_image.cpp | 15 +++++++++++++++ src/vulkan/vulkan_state.cpp | 9 --------- src/vulkan/vulkan_state.h | 2 +- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/command_buffer.cpp b/src/command_buffer.cpp index f43cad9..8e7fc18 100644 --- a/src/command_buffer.cpp +++ b/src/command_buffer.cpp @@ -1260,16 +1260,12 @@ void CommandBuffer::start() { auto &state = vulkan::commandBufferState(this); auto &deviceState = vulkan::deviceState(device); - if (state.imageAvailableSemaphore == VK_NULL_HANDLE || - state.renderFinishedSemaphore == VK_NULL_HANDLE) { + if (state.imageAvailableSemaphore == VK_NULL_HANDLE) { VkSemaphoreCreateInfo semaphoreInfo{}; semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; VULKAN_GUARD(vkCreateSemaphore(deviceState.device, &semaphoreInfo, nullptr, &state.imageAvailableSemaphore), "Failed to create Vulkan image available semaphore"); - VULKAN_GUARD(vkCreateSemaphore(deviceState.device, &semaphoreInfo, - nullptr, &state.renderFinishedSemaphore), - "Failed to create Vulkan render finished semaphore"); } if (state.inFlightFence == VK_NULL_HANDLE) { @@ -2114,7 +2110,10 @@ void CommandBuffer::commit() { VkSemaphoreSubmitInfo signalInfo{}; signalInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO; - signalInfo.semaphore = state.renderFinishedSemaphore; + signalInfo.semaphore = state.needsPresent + ? contextState.renderFinishedSemaphores.at( + state.imageIndex) + : VK_NULL_HANDLE; signalInfo.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; @@ -2142,7 +2141,7 @@ void CommandBuffer::commit() { VkPresentInfoKHR presentInfo{}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.waitSemaphoreCount = 1; - presentInfo.pWaitSemaphores = &state.renderFinishedSemaphore; + presentInfo.pWaitSemaphores = &signalInfo.semaphore; presentInfo.swapchainCount = 1; presentInfo.pSwapchains = &contextState.swapchain; presentInfo.pImageIndices = &state.imageIndex; diff --git a/src/vulkan/vulkan_image.cpp b/src/vulkan/vulkan_image.cpp index 3944448..ca72952 100644 --- a/src/vulkan/vulkan_image.cpp +++ b/src/vulkan/vulkan_image.cpp @@ -154,10 +154,19 @@ void createSwapchainImages(ContextState &contextState, contextState.swapchainImages.data()); contextState.swapchainImageViews.resize(swapchainImageCount); + contextState.renderFinishedSemaphores.resize(swapchainImageCount, + VK_NULL_HANDLE); contextState.swapchainImageLayouts.resize(swapchainImageCount, VK_IMAGE_LAYOUT_UNDEFINED); for (size_t i = 0; i < swapchainImageCount; i++) { + VkSemaphoreCreateInfo semaphoreInfo{}; + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + VULKAN_GUARD( + vkCreateSemaphore(deviceState.device, &semaphoreInfo, nullptr, + &contextState.renderFinishedSemaphores[i]), + "Failed to create Vulkan presentation semaphore"); + VkImageViewCreateInfo viewInfo{}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = contextState.swapchainImages[i]; @@ -190,6 +199,12 @@ void destroySwapchain(ContextState &contextState, DeviceState &deviceState) { vkDestroyImageView(deviceState.device, imageView, nullptr); } } + for (VkSemaphore semaphore : contextState.renderFinishedSemaphores) { + if (semaphore != VK_NULL_HANDLE) { + vkDestroySemaphore(deviceState.device, semaphore, nullptr); + } + } + contextState.renderFinishedSemaphores.clear(); contextState.swapchainImageViews.clear(); contextState.swapchainImages.clear(); contextState.swapchainImageLayouts.clear(); diff --git a/src/vulkan/vulkan_state.cpp b/src/vulkan/vulkan_state.cpp index fe71831..adc4a94 100644 --- a/src/vulkan/vulkan_state.cpp +++ b/src/vulkan/vulkan_state.cpp @@ -308,11 +308,6 @@ void releaseDeviceState(Device *device) { commandState.imageAvailableSemaphore, nullptr); } - if (commandState.renderFinishedSemaphore != VK_NULL_HANDLE) { - vkDestroySemaphore(state.device, - commandState.renderFinishedSemaphore, - nullptr); - } if (commandState.inFlightFence != VK_NULL_HANDLE) { vkDestroyFence(state.device, commandState.inFlightFence, nullptr); @@ -361,10 +356,6 @@ void releaseCommandBufferState(CommandBuffer *commandBuffer) { vkDestroySemaphore(state.device, state.imageAvailableSemaphore, nullptr); } - if (state.renderFinishedSemaphore != VK_NULL_HANDLE) { - vkDestroySemaphore(state.device, state.renderFinishedSemaphore, - nullptr); - } if (state.inFlightFence != VK_NULL_HANDLE) { vkDestroyFence(state.device, state.inFlightFence, nullptr); } diff --git a/src/vulkan/vulkan_state.h b/src/vulkan/vulkan_state.h index 6a93241..76220e2 100644 --- a/src/vulkan/vulkan_state.h +++ b/src/vulkan/vulkan_state.h @@ -64,6 +64,7 @@ struct ContextState { std::vector swapchainImages; std::vector swapchainImageViews; + std::vector renderFinishedSemaphores; uint32_t currentSwapchainImageIndex = UINT32_MAX; @@ -155,7 +156,6 @@ struct CommandBufferState { bool submitted = false; VkSemaphore imageAvailableSemaphore = VK_NULL_HANDLE; - VkSemaphore renderFinishedSemaphore = VK_NULL_HANDLE; VkFence inFlightFence = VK_NULL_HANDLE; bool clearColorPending = false; From 64ae82f73e1ff57bd20e16ec2b3c696f7a465f13 Mon Sep 17 00:00:00 2001 From: Max Van den Eynde Date: Fri, 2 Oct 2026 07:55:51 +0200 Subject: [PATCH 2/2] Wait only for submitted Vulkan command buffers --- src/command_buffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/command_buffer.cpp b/src/command_buffer.cpp index 8e7fc18..fac7f9d 100644 --- a/src/command_buffer.cpp +++ b/src/command_buffer.cpp @@ -2184,7 +2184,7 @@ void CommandBuffer::waitForSubmittedWork() { state.inFlightResources.clear(); #elif defined(VULKAN) auto &state = vulkan::commandBufferState(this); - if (state.inFlightFence == VK_NULL_HANDLE) { + if (state.inFlightFence == VK_NULL_HANDLE || !state.submitted) { return; }