diff --git a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp index b2f307a910..b325b1428c 100644 --- a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp @@ -12,6 +12,7 @@ #include "VideoBackends/Vulkan/VulkanContext.h" #include "VideoCommon/Constants.h" +#include "vulkan/vulkan_core.h" namespace Vulkan { @@ -32,9 +33,9 @@ CommandBufferManager::~CommandBufferManager() DestroyCommandBuffers(); } -bool CommandBufferManager::Initialize() +bool CommandBufferManager::Initialize(size_t swapchain_image_count) { - if (!CreateCommandBuffers()) + if (!CreateCommandBuffers(swapchain_image_count)) return false; if (m_use_threaded_submission && !CreateSubmitThread()) @@ -43,7 +44,7 @@ bool CommandBufferManager::Initialize() return true; } -bool CommandBufferManager::CreateCommandBuffers() +bool CommandBufferManager::CreateCommandBuffers(size_t swapchain_image_count) { static constexpr VkSemaphoreCreateInfo semaphore_create_info = { 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); - if (res != VK_SUCCESS) + m_present_semaphores.reserve(swapchain_image_count); + for (uint32_t i = 0; i < swapchain_image_count; i++) { - LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: "); - return false; + VkSemaphore present_semaphore; + 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 @@ -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) @@ -414,7 +424,7 @@ void CommandBufferManager::SubmitCommandBuffer(u32 command_buffer_index, if (present_swap_chain != VK_NULL_HANDLE) { submit_info.signalSemaphoreCount = 1; - submit_info.pSignalSemaphores = &m_present_semaphore; + submit_info.pSignalSemaphores = &m_present_semaphores[present_image_index]; } VkResult res = @@ -433,7 +443,7 @@ void CommandBufferManager::SubmitCommandBuffer(u32 command_buffer_index, VkPresentInfoKHR present_info = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, nullptr, 1, - &m_present_semaphore, + &m_present_semaphores[present_image_index], 1, &present_swap_chain, &present_image_index, diff --git a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.h b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.h index bcf310f5a6..90e62bb805 100644 --- a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.h +++ b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.h @@ -21,7 +21,7 @@ public: explicit CommandBufferManager(bool use_threaded_submission); ~CommandBufferManager(); - bool Initialize(); + bool Initialize(size_t swapchain_image_count); // These command buffers are allocated per-frame. They are valid until the command buffer // is submitted, after that you should call these functions again. @@ -94,7 +94,7 @@ public: void DeferImageViewDestruction(VkImageView object); private: - bool CreateCommandBuffers(); + bool CreateCommandBuffers(size_t swapchain_image_count); void DestroyCommandBuffers(); bool CreateSubmitThread(); @@ -153,7 +153,7 @@ private: u32 command_buffer_index; }; Common::WorkQueueThreadSP m_submit_thread; - VkSemaphore m_present_semaphore = VK_NULL_HANDLE; + std::vector m_present_semaphores = {}; Common::Flag m_last_present_failed; VkResult m_last_present_result = VK_SUCCESS; bool m_use_threaded_submission = false; diff --git a/Source/Core/VideoBackends/Vulkan/VKMain.cpp b/Source/Core/VideoBackends/Vulkan/VKMain.cpp index e5ecd5a4de..6338e52e3d 100644 --- a/Source/Core/VideoBackends/Vulkan/VKMain.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKMain.cpp @@ -187,15 +187,6 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi) UpdateActiveConfig(); - // Create command buffers. We do this separately because the other classes depend on it. - g_command_buffer_mgr = std::make_unique(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. g_object_cache = std::make_unique(); 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(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()) { PanicAlertFmt("Failed to create state tracker"); diff --git a/Source/Core/VideoBackends/Vulkan/VKSwapChain.h b/Source/Core/VideoBackends/Vulkan/VKSwapChain.h index 5f173185a0..17334dbf97 100644 --- a/Source/Core/VideoBackends/Vulkan/VKSwapChain.h +++ b/Source/Core/VideoBackends/Vulkan/VKSwapChain.h @@ -39,6 +39,7 @@ public: u32 GetHeight() const { return m_height; } u32 GetCurrentImageIndex() const { return m_current_swap_chain_image_index; } bool IsCurrentImageValid() const { return m_current_swap_chain_image_is_valid; } + size_t GetSwapChainImageCount() const { return m_swap_chain_images.size(); } VkImage GetCurrentImage() const { return m_swap_chain_images[m_current_swap_chain_image_index].image;