From 3c92b354222c092fa48825b7f96c81ba9473c061 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Thu, 3 Nov 2016 23:42:41 +1100 Subject: [PATCH] Vulkan: Use multiple command pools, one per frame Instead of resetting two command buffers, now we only have to call vkResetCommandPool once at the start of a frame. NV's recommends using one pool per frame/thread. May offer a very small boost in performance on some systems. --- .../Vulkan/CommandBufferManager.cpp | 71 ++++++++----------- .../Vulkan/CommandBufferManager.h | 7 +- 2 files changed, 30 insertions(+), 48 deletions(-) diff --git a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp index 202c3f6777..27a3976b83 100644 --- a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp @@ -33,14 +33,10 @@ CommandBufferManager::~CommandBufferManager() vkDeviceWaitIdle(g_vulkan_context->GetDevice()); DestroyCommandBuffers(); - DestroyCommandPool(); } bool CommandBufferManager::Initialize() { - if (!CreateCommandPool()) - return false; - if (!CreateCommandBuffers()) return false; @@ -50,48 +46,31 @@ bool CommandBufferManager::Initialize() return true; } -bool CommandBufferManager::CreateCommandPool() -{ - VkCommandPoolCreateInfo info = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, nullptr, - VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | - VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, - g_vulkan_context->GetGraphicsQueueFamilyIndex()}; - - VkResult res = - vkCreateCommandPool(g_vulkan_context->GetDevice(), &info, nullptr, &m_command_pool); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateCommandPool failed: "); - return false; - } - - return true; -} - -void CommandBufferManager::DestroyCommandPool() -{ - if (m_command_pool) - { - vkDestroyCommandPool(g_vulkan_context->GetDevice(), m_command_pool, nullptr); - m_command_pool = VK_NULL_HANDLE; - } -} - bool CommandBufferManager::CreateCommandBuffers() { VkDevice device = g_vulkan_context->GetDevice(); + VkResult res; for (FrameResources& resources : m_frame_resources) { resources.init_command_buffer_used = false; resources.needs_fence_wait = false; - VkCommandBufferAllocateInfo allocate_info = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, nullptr, m_command_pool, + VkCommandPoolCreateInfo pool_info = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, nullptr, 0, + g_vulkan_context->GetGraphicsQueueFamilyIndex()}; + res = vkCreateCommandPool(g_vulkan_context->GetDevice(), &pool_info, nullptr, + &resources.command_pool); + if (res != VK_SUCCESS) + { + LOG_VULKAN_ERROR(res, "vkCreateCommandPool failed: "); + return false; + } + + VkCommandBufferAllocateInfo buffer_info = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, nullptr, resources.command_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, static_cast(resources.command_buffers.size())}; - VkResult res = - vkAllocateCommandBuffers(device, &allocate_info, resources.command_buffers.data()); + res = vkAllocateCommandBuffers(device, &buffer_info, resources.command_buffers.data()); if (res != VK_SUCCESS) { LOG_VULKAN_ERROR(res, "vkAllocateCommandBuffers failed: "); @@ -157,12 +136,17 @@ void CommandBufferManager::DestroyCommandBuffers() } if (resources.command_buffers[0] != VK_NULL_HANDLE) { - vkFreeCommandBuffers(device, m_command_pool, + vkFreeCommandBuffers(device, resources.command_pool, static_cast(resources.command_buffers.size()), resources.command_buffers.data()); resources.command_buffers.fill(VK_NULL_HANDLE); } + if (resources.command_pool != VK_NULL_HANDLE) + { + vkDestroyCommandPool(device, resources.command_pool, nullptr); + resources.command_pool = VK_NULL_HANDLE; + } } } @@ -412,16 +396,16 @@ void CommandBufferManager::ActivateCommandBuffer() if (res != VK_SUCCESS) LOG_VULKAN_ERROR(res, "vkResetFences failed: "); - // Reset command buffer to beginning since we can re-use the memory now + // Reset command pools to beginning since we can re-use the memory now + res = vkResetCommandPool(g_vulkan_context->GetDevice(), resources.command_pool, 0); + if (res != VK_SUCCESS) + LOG_VULKAN_ERROR(res, "vkResetCommandPool failed: "); + + // Enable commands to be recorded to the two buffers again. VkCommandBufferBeginInfo begin_info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, nullptr}; - resources.init_command_buffer_used = false; for (VkCommandBuffer command_buffer : resources.command_buffers) { - res = vkResetCommandBuffer(command_buffer, 0); - if (res != VK_SUCCESS) - LOG_VULKAN_ERROR(res, "vkResetCommandBuffer failed: "); - res = vkBeginCommandBuffer(command_buffer, &begin_info); if (res != VK_SUCCESS) LOG_VULKAN_ERROR(res, "vkBeginCommandBuffer failed: "); @@ -431,6 +415,9 @@ void CommandBufferManager::ActivateCommandBuffer() res = vkResetDescriptorPool(g_vulkan_context->GetDevice(), resources.descriptor_pool, 0); if (res != VK_SUCCESS) LOG_VULKAN_ERROR(res, "vkResetDescriptorPool failed: "); + + // Reset upload command buffer state + resources.init_command_buffer_used = false; } void CommandBufferManager::ExecuteCommandBuffer(bool submit_off_thread, bool wait_for_completion) diff --git a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.h b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.h index 96b09b1bde..67266b69b9 100644 --- a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.h +++ b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.h @@ -33,7 +33,6 @@ public: bool Initialize(); - VkCommandPool GetCommandPool() const { return m_command_pool; } // These command buffers are allocated per-frame. They are valid until the command buffer // is submitted, after that you should call these functions again. VkCommandBuffer GetCurrentInitCommandBuffer() @@ -100,9 +99,6 @@ public: void RemoveFencePointCallback(const void* key); private: - bool CreateCommandPool(); - void DestroyCommandPool(); - bool CreateCommandBuffers(); void DestroyCommandBuffers(); @@ -113,11 +109,10 @@ private: void OnCommandBufferExecuted(size_t index); - VkCommandPool m_command_pool = VK_NULL_HANDLE; - struct FrameResources { // [0] - Init (upload) command buffer, [1] - draw command buffer + VkCommandPool command_pool; std::array command_buffers; VkDescriptorPool descriptor_pool; VkFence fence;