Skip to content

Commit

Permalink
Merge pull request dolphin-emu#4416 from stenzek/vulkan-cmdpool
Browse files Browse the repository at this point in the history
Vulkan: Use multiple command pools, one per frame
  • Loading branch information
degasus committed Nov 16, 2016
2 parents 71be84e + 3c92b35 commit 6c16f1b
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 48 deletions.
71 changes: 29 additions & 42 deletions Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp
Expand Up @@ -33,14 +33,10 @@ CommandBufferManager::~CommandBufferManager()
vkDeviceWaitIdle(g_vulkan_context->GetDevice());

DestroyCommandBuffers();
DestroyCommandPool();
}

bool CommandBufferManager::Initialize()
{
if (!CreateCommandPool())
return false;

if (!CreateCommandBuffers())
return false;

Expand All @@ -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<uint32_t>(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: ");
Expand Down Expand Up @@ -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<u32>(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;
}
}
}

Expand Down Expand Up @@ -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: ");
Expand All @@ -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)
Expand Down
7 changes: 1 addition & 6 deletions Source/Core/VideoBackends/Vulkan/CommandBufferManager.h
Expand Up @@ -33,7 +33,6 @@ class CommandBufferManager

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()
Expand Down Expand Up @@ -100,9 +99,6 @@ class CommandBufferManager
void RemoveFencePointCallback(const void* key);

private:
bool CreateCommandPool();
void DestroyCommandPool();

bool CreateCommandBuffers();
void DestroyCommandBuffers();

Expand All @@ -113,11 +109,10 @@ class CommandBufferManager

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<VkCommandBuffer, 2> command_buffers;
VkDescriptorPool descriptor_pool;
VkFence fence;
Expand Down

0 comments on commit 6c16f1b

Please sign in to comment.