vk_resource_manager: Implement a command buffer pool with VKFencedPool
This commit is contained in:
		| @@ -13,8 +13,55 @@ | ||||
| namespace Vulkan { | ||||
|  | ||||
| // TODO(Rodrigo): Fine tune these numbers. | ||||
| constexpr std::size_t COMMAND_BUFFER_POOL_SIZE = 0x1000; | ||||
| constexpr std::size_t FENCES_GROW_STEP = 0x40; | ||||
|  | ||||
| class CommandBufferPool final : public VKFencedPool { | ||||
| public: | ||||
|     CommandBufferPool(const VKDevice& device) | ||||
|         : VKFencedPool(COMMAND_BUFFER_POOL_SIZE), device{device} {} | ||||
|  | ||||
|     void Allocate(std::size_t begin, std::size_t end) { | ||||
|         const auto dev = device.GetLogical(); | ||||
|         const auto& dld = device.GetDispatchLoader(); | ||||
|         const u32 graphics_family = device.GetGraphicsFamily(); | ||||
|  | ||||
|         auto pool = std::make_unique<Pool>(); | ||||
|  | ||||
|         // Command buffers are going to be commited, recorded, executed every single usage cycle. | ||||
|         // They are also going to be reseted when commited. | ||||
|         const auto pool_flags = vk::CommandPoolCreateFlagBits::eTransient | | ||||
|                                 vk::CommandPoolCreateFlagBits::eResetCommandBuffer; | ||||
|         const vk::CommandPoolCreateInfo cmdbuf_pool_ci(pool_flags, graphics_family); | ||||
|         pool->handle = dev.createCommandPoolUnique(cmdbuf_pool_ci, nullptr, dld); | ||||
|  | ||||
|         const vk::CommandBufferAllocateInfo cmdbuf_ai(*pool->handle, | ||||
|                                                       vk::CommandBufferLevel::ePrimary, | ||||
|                                                       static_cast<u32>(COMMAND_BUFFER_POOL_SIZE)); | ||||
|         pool->cmdbufs = | ||||
|             dev.allocateCommandBuffersUnique<std::allocator<UniqueCommandBuffer>>(cmdbuf_ai, dld); | ||||
|  | ||||
|         pools.push_back(std::move(pool)); | ||||
|     } | ||||
|  | ||||
|     vk::CommandBuffer Commit(VKFence& fence) { | ||||
|         const std::size_t index = CommitResource(fence); | ||||
|         const auto pool_index = index / COMMAND_BUFFER_POOL_SIZE; | ||||
|         const auto sub_index = index % COMMAND_BUFFER_POOL_SIZE; | ||||
|         return *pools[pool_index]->cmdbufs[sub_index]; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     struct Pool { | ||||
|         UniqueCommandPool handle; | ||||
|         std::vector<UniqueCommandBuffer> cmdbufs; | ||||
|     }; | ||||
|  | ||||
|     const VKDevice& device; | ||||
|  | ||||
|     std::vector<std::unique_ptr<Pool>> pools; | ||||
| }; | ||||
|  | ||||
| VKResource::VKResource() = default; | ||||
|  | ||||
| VKResource::~VKResource() = default; | ||||
| @@ -174,6 +221,7 @@ void VKFencedPool::Grow() { | ||||
|  | ||||
| VKResourceManager::VKResourceManager(const VKDevice& device) : device{device} { | ||||
|     GrowFences(FENCES_GROW_STEP); | ||||
|     command_buffer_pool = std::make_unique<CommandBufferPool>(device); | ||||
| } | ||||
|  | ||||
| VKResourceManager::~VKResourceManager() = default; | ||||
| @@ -217,6 +265,10 @@ VKFence& VKResourceManager::CommitFence() { | ||||
|     return *found_fence; | ||||
| } | ||||
|  | ||||
| vk::CommandBuffer VKResourceManager::CommitCommandBuffer(VKFence& fence) { | ||||
|     return command_buffer_pool->Commit(fence); | ||||
| } | ||||
|  | ||||
| void VKResourceManager::GrowFences(std::size_t new_fences_count) { | ||||
|     const auto dev = device.GetLogical(); | ||||
|     const auto& dld = device.GetDispatchLoader(); | ||||
|   | ||||
| @@ -15,6 +15,8 @@ class VKDevice; | ||||
| class VKFence; | ||||
| class VKResourceManager; | ||||
|  | ||||
| class CommandBufferPool; | ||||
|  | ||||
| /// Interface for a Vulkan resource | ||||
| class VKResource { | ||||
| public: | ||||
| @@ -162,6 +164,9 @@ public: | ||||
|     /// Commits a fence. It has to be sent to a queue and released. | ||||
|     VKFence& CommitFence(); | ||||
|  | ||||
|     /// Commits an unused command buffer and protects it with a fence. | ||||
|     vk::CommandBuffer CommitCommandBuffer(VKFence& fence); | ||||
|  | ||||
| private: | ||||
|     /// Allocates new fences. | ||||
|     void GrowFences(std::size_t new_fences_count); | ||||
| @@ -169,6 +174,7 @@ private: | ||||
|     const VKDevice& device;          ///< Device handler. | ||||
|     std::size_t fences_iterator = 0; ///< Index where a free fence is likely to be found. | ||||
|     std::vector<std::unique_ptr<VKFence>> fences;           ///< Pool of fences. | ||||
|     std::unique_ptr<CommandBufferPool> command_buffer_pool; ///< Pool of command buffers. | ||||
| }; | ||||
|  | ||||
| } // namespace Vulkan | ||||
|   | ||||
		Reference in New Issue
	
	Block a user