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.
This commit is contained in:
parent
017ab71fcf
commit
3c92b35422
|
@ -33,14 +33,10 @@ CommandBufferManager::~CommandBufferManager()
|
||||||
vkDeviceWaitIdle(g_vulkan_context->GetDevice());
|
vkDeviceWaitIdle(g_vulkan_context->GetDevice());
|
||||||
|
|
||||||
DestroyCommandBuffers();
|
DestroyCommandBuffers();
|
||||||
DestroyCommandPool();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandBufferManager::Initialize()
|
bool CommandBufferManager::Initialize()
|
||||||
{
|
{
|
||||||
if (!CreateCommandPool())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!CreateCommandBuffers())
|
if (!CreateCommandBuffers())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -50,48 +46,31 @@ bool CommandBufferManager::Initialize()
|
||||||
return true;
|
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()
|
bool CommandBufferManager::CreateCommandBuffers()
|
||||||
{
|
{
|
||||||
VkDevice device = g_vulkan_context->GetDevice();
|
VkDevice device = g_vulkan_context->GetDevice();
|
||||||
|
VkResult res;
|
||||||
|
|
||||||
for (FrameResources& resources : m_frame_resources)
|
for (FrameResources& resources : m_frame_resources)
|
||||||
{
|
{
|
||||||
resources.init_command_buffer_used = false;
|
resources.init_command_buffer_used = false;
|
||||||
resources.needs_fence_wait = false;
|
resources.needs_fence_wait = false;
|
||||||
|
|
||||||
VkCommandBufferAllocateInfo allocate_info = {
|
VkCommandPoolCreateInfo pool_info = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, nullptr, 0,
|
||||||
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, nullptr, m_command_pool,
|
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<uint32_t>(resources.command_buffers.size())};
|
VK_COMMAND_BUFFER_LEVEL_PRIMARY, static_cast<uint32_t>(resources.command_buffers.size())};
|
||||||
|
|
||||||
VkResult res =
|
res = vkAllocateCommandBuffers(device, &buffer_info, resources.command_buffers.data());
|
||||||
vkAllocateCommandBuffers(device, &allocate_info, resources.command_buffers.data());
|
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, "vkAllocateCommandBuffers failed: ");
|
LOG_VULKAN_ERROR(res, "vkAllocateCommandBuffers failed: ");
|
||||||
|
@ -157,12 +136,17 @@ void CommandBufferManager::DestroyCommandBuffers()
|
||||||
}
|
}
|
||||||
if (resources.command_buffers[0] != VK_NULL_HANDLE)
|
if (resources.command_buffers[0] != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
vkFreeCommandBuffers(device, m_command_pool,
|
vkFreeCommandBuffers(device, resources.command_pool,
|
||||||
static_cast<u32>(resources.command_buffers.size()),
|
static_cast<u32>(resources.command_buffers.size()),
|
||||||
resources.command_buffers.data());
|
resources.command_buffers.data());
|
||||||
|
|
||||||
resources.command_buffers.fill(VK_NULL_HANDLE);
|
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)
|
if (res != VK_SUCCESS)
|
||||||
LOG_VULKAN_ERROR(res, "vkResetFences failed: ");
|
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,
|
VkCommandBufferBeginInfo begin_info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr,
|
||||||
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, nullptr};
|
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, nullptr};
|
||||||
resources.init_command_buffer_used = false;
|
|
||||||
for (VkCommandBuffer command_buffer : resources.command_buffers)
|
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);
|
res = vkBeginCommandBuffer(command_buffer, &begin_info);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
LOG_VULKAN_ERROR(res, "vkBeginCommandBuffer failed: ");
|
LOG_VULKAN_ERROR(res, "vkBeginCommandBuffer failed: ");
|
||||||
|
@ -431,6 +415,9 @@ void CommandBufferManager::ActivateCommandBuffer()
|
||||||
res = vkResetDescriptorPool(g_vulkan_context->GetDevice(), resources.descriptor_pool, 0);
|
res = vkResetDescriptorPool(g_vulkan_context->GetDevice(), resources.descriptor_pool, 0);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
LOG_VULKAN_ERROR(res, "vkResetDescriptorPool failed: ");
|
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)
|
void CommandBufferManager::ExecuteCommandBuffer(bool submit_off_thread, bool wait_for_completion)
|
||||||
|
|
|
@ -33,7 +33,6 @@ public:
|
||||||
|
|
||||||
bool Initialize();
|
bool Initialize();
|
||||||
|
|
||||||
VkCommandPool GetCommandPool() const { return m_command_pool; }
|
|
||||||
// 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.
|
||||||
VkCommandBuffer GetCurrentInitCommandBuffer()
|
VkCommandBuffer GetCurrentInitCommandBuffer()
|
||||||
|
@ -100,9 +99,6 @@ public:
|
||||||
void RemoveFencePointCallback(const void* key);
|
void RemoveFencePointCallback(const void* key);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool CreateCommandPool();
|
|
||||||
void DestroyCommandPool();
|
|
||||||
|
|
||||||
bool CreateCommandBuffers();
|
bool CreateCommandBuffers();
|
||||||
void DestroyCommandBuffers();
|
void DestroyCommandBuffers();
|
||||||
|
|
||||||
|
@ -113,11 +109,10 @@ private:
|
||||||
|
|
||||||
void OnCommandBufferExecuted(size_t index);
|
void OnCommandBufferExecuted(size_t index);
|
||||||
|
|
||||||
VkCommandPool m_command_pool = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
struct FrameResources
|
struct FrameResources
|
||||||
{
|
{
|
||||||
// [0] - Init (upload) command buffer, [1] - draw command buffer
|
// [0] - Init (upload) command buffer, [1] - draw command buffer
|
||||||
|
VkCommandPool command_pool;
|
||||||
std::array<VkCommandBuffer, 2> command_buffers;
|
std::array<VkCommandBuffer, 2> command_buffers;
|
||||||
VkDescriptorPool descriptor_pool;
|
VkDescriptorPool descriptor_pool;
|
||||||
VkFence fence;
|
VkFence fence;
|
||||||
|
|
Loading…
Reference in New Issue