Merge pull request #13805 from SuperSamus/vulkan-present-sempahore-reuse-fix

Vulkan: Fix present semaphores reuse
This commit is contained in:
Tilka
2025-07-22 03:03:04 +01:00
committed by GitHub
4 changed files with 35 additions and 22 deletions

View File

@ -12,6 +12,7 @@
#include "VideoBackends/Vulkan/VulkanContext.h" #include "VideoBackends/Vulkan/VulkanContext.h"
#include "VideoCommon/Constants.h" #include "VideoCommon/Constants.h"
#include "vulkan/vulkan_core.h"
namespace Vulkan namespace Vulkan
{ {
@ -32,9 +33,9 @@ CommandBufferManager::~CommandBufferManager()
DestroyCommandBuffers(); DestroyCommandBuffers();
} }
bool CommandBufferManager::Initialize() bool CommandBufferManager::Initialize(size_t swapchain_image_count)
{ {
if (!CreateCommandBuffers()) if (!CreateCommandBuffers(swapchain_image_count))
return false; return false;
if (m_use_threaded_submission && !CreateSubmitThread()) if (m_use_threaded_submission && !CreateSubmitThread())
@ -43,7 +44,7 @@ bool CommandBufferManager::Initialize()
return true; return true;
} }
bool CommandBufferManager::CreateCommandBuffers() bool CommandBufferManager::CreateCommandBuffers(size_t swapchain_image_count)
{ {
static constexpr VkSemaphoreCreateInfo semaphore_create_info = { static constexpr VkSemaphoreCreateInfo semaphore_create_info = {
VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0}; VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0};
@ -95,11 +96,17 @@ bool CommandBufferManager::CreateCommandBuffers()
} }
} }
res = vkCreateSemaphore(device, &semaphore_create_info, nullptr, &m_present_semaphore); m_present_semaphores.reserve(swapchain_image_count);
if (res != VK_SUCCESS) for (uint32_t i = 0; i < swapchain_image_count; i++)
{ {
LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: "); VkSemaphore present_semaphore;
return false; res = vkCreateSemaphore(device, &semaphore_create_info, nullptr, &present_semaphore);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: ");
return false;
}
m_present_semaphores.push_back(present_semaphore);
} }
// Activate the first command buffer. BeginCommandBuffer moves forward, so start with the last // Activate the first command buffer. BeginCommandBuffer moves forward, so start with the last
@ -140,7 +147,10 @@ void CommandBufferManager::DestroyCommandBuffers()
} }
} }
vkDestroySemaphore(device, m_present_semaphore, nullptr); for (VkSemaphore present_semaphore : m_present_semaphores)
{
vkDestroySemaphore(device, present_semaphore, nullptr);
}
} }
VkDescriptorPool CommandBufferManager::CreateDescriptorPool(u32 max_descriptor_sets) VkDescriptorPool CommandBufferManager::CreateDescriptorPool(u32 max_descriptor_sets)
@ -414,7 +424,7 @@ void CommandBufferManager::SubmitCommandBuffer(u32 command_buffer_index,
if (present_swap_chain != VK_NULL_HANDLE) if (present_swap_chain != VK_NULL_HANDLE)
{ {
submit_info.signalSemaphoreCount = 1; submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &m_present_semaphore; submit_info.pSignalSemaphores = &m_present_semaphores[present_image_index];
} }
VkResult res = VkResult res =
@ -433,7 +443,7 @@ void CommandBufferManager::SubmitCommandBuffer(u32 command_buffer_index,
VkPresentInfoKHR present_info = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, VkPresentInfoKHR present_info = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
nullptr, nullptr,
1, 1,
&m_present_semaphore, &m_present_semaphores[present_image_index],
1, 1,
&present_swap_chain, &present_swap_chain,
&present_image_index, &present_image_index,

View File

@ -21,7 +21,7 @@ public:
explicit CommandBufferManager(bool use_threaded_submission); explicit CommandBufferManager(bool use_threaded_submission);
~CommandBufferManager(); ~CommandBufferManager();
bool Initialize(); bool Initialize(size_t swapchain_image_count);
// These command buffers are allocated per-frame. They are valid until the command buffer // These command buffers are allocated per-frame. They are valid until the command buffer
// is submitted, after that you should call these functions again. // is submitted, after that you should call these functions again.
@ -94,7 +94,7 @@ public:
void DeferImageViewDestruction(VkImageView object); void DeferImageViewDestruction(VkImageView object);
private: private:
bool CreateCommandBuffers(); bool CreateCommandBuffers(size_t swapchain_image_count);
void DestroyCommandBuffers(); void DestroyCommandBuffers();
bool CreateSubmitThread(); bool CreateSubmitThread();
@ -153,7 +153,7 @@ private:
u32 command_buffer_index; u32 command_buffer_index;
}; };
Common::WorkQueueThreadSP<PendingCommandBufferSubmit> m_submit_thread; Common::WorkQueueThreadSP<PendingCommandBufferSubmit> m_submit_thread;
VkSemaphore m_present_semaphore = VK_NULL_HANDLE; std::vector<VkSemaphore> m_present_semaphores = {};
Common::Flag m_last_present_failed; Common::Flag m_last_present_failed;
VkResult m_last_present_result = VK_SUCCESS; VkResult m_last_present_result = VK_SUCCESS;
bool m_use_threaded_submission = false; bool m_use_threaded_submission = false;

View File

@ -187,15 +187,6 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
UpdateActiveConfig(); UpdateActiveConfig();
// Create command buffers. We do this separately because the other classes depend on it.
g_command_buffer_mgr = std::make_unique<CommandBufferManager>(g_Config.bBackendMultithreading);
if (!g_command_buffer_mgr->Initialize())
{
PanicAlertFmt("Failed to create Vulkan command buffers");
Shutdown();
return false;
}
// Remaining classes are also dependent on object cache. // Remaining classes are also dependent on object cache.
g_object_cache = std::make_unique<ObjectCache>(); g_object_cache = std::make_unique<ObjectCache>();
if (!g_object_cache->Initialize()) if (!g_object_cache->Initialize())
@ -218,6 +209,17 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
} }
} }
// Create command buffers. We do this separately because the other classes depend on it.
g_command_buffer_mgr = std::make_unique<CommandBufferManager>(g_Config.bBackendMultithreading);
size_t swapchain_image_count =
surface != VK_NULL_HANDLE ? swap_chain->GetSwapChainImageCount() : 0;
if (!g_command_buffer_mgr->Initialize(swapchain_image_count))
{
PanicAlertFmt("Failed to create Vulkan command buffers");
Shutdown();
return false;
}
if (!StateTracker::CreateInstance()) if (!StateTracker::CreateInstance())
{ {
PanicAlertFmt("Failed to create state tracker"); PanicAlertFmt("Failed to create state tracker");

View File

@ -39,6 +39,7 @@ public:
u32 GetHeight() const { return m_height; } u32 GetHeight() const { return m_height; }
u32 GetCurrentImageIndex() const { return m_current_swap_chain_image_index; } u32 GetCurrentImageIndex() const { return m_current_swap_chain_image_index; }
bool IsCurrentImageValid() const { return m_current_swap_chain_image_is_valid; } bool IsCurrentImageValid() const { return m_current_swap_chain_image_is_valid; }
size_t GetSwapChainImageCount() const { return m_swap_chain_images.size(); }
VkImage GetCurrentImage() const VkImage GetCurrentImage() const
{ {
return m_swap_chain_images[m_current_swap_chain_image_index].image; return m_swap_chain_images[m_current_swap_chain_image_index].image;