15 #include "vulkan/vulkan_enums.hpp"
16 #include "vulkan/vulkan_handles.hpp"
17 #include "vulkan/vulkan_structs.hpp"
31 vk::UniqueCommandPool&& pool,
32 std::vector<vk::UniqueCommandBuffer>&& buffers,
34 std::weak_ptr<CommandPoolRecyclerVK> recycler)
35 : pool_(
std::move(pool)),
36 buffers_(
std::move(buffers)),
37 unused_count_(unused_count),
38 recycler_(
std::move(recycler)) {}
41 auto const recycler = recycler_.lock();
53 recycler->Reclaim(std::move(pool_), std::move(buffers_),
62 vk::UniqueCommandPool pool_;
67 std::vector<vk::UniqueCommandBuffer> buffers_;
68 const size_t unused_count_;
69 std::weak_ptr<CommandPoolRecyclerVK> recycler_;
77 auto const context = context_.lock();
81 auto const recycler = context->GetCommandPoolRecycler();
87 size_t unused_count = unused_command_buffers_.size();
88 for (
auto i = 0u; i < unused_command_buffers_.size(); i++) {
89 collected_buffers_.push_back(std::move(unused_command_buffers_[i]));
91 unused_command_buffers_.clear();
94 std::move(pool_), std::move(collected_buffers_), unused_count, recycler);
97 context->GetResourceManager(), std::move(reset_pool_when_dropped));
102 auto const context = context_.lock();
107 Lock lock(pool_mutex_);
111 if (!unused_command_buffers_.empty()) {
112 vk::UniqueCommandBuffer buffer = std::move(unused_command_buffers_.back());
113 unused_command_buffers_.pop_back();
117 auto const device = context->GetDevice();
118 vk::CommandBufferAllocateInfo info;
119 info.setCommandPool(pool_.get());
120 info.setCommandBufferCount(1u);
121 info.setLevel(vk::CommandBufferLevel::ePrimary);
122 auto [result, buffers] = device.allocateCommandBuffersUnique(info);
123 if (result != vk::Result::eSuccess) {
126 return std::move(buffers[0]);
130 Lock lock(pool_mutex_);
137 collected_buffers_.push_back(std::move(buffer));
141 Lock lock(pool_mutex_);
146 for (
auto& buffer : collected_buffers_) {
149 for (
auto& buffer : unused_command_buffers_) {
152 unused_command_buffers_.clear();
153 collected_buffers_.clear();
158 std::unordered_map<uint64_t, std::shared_ptr<CommandPoolVK>>;
173 static std::unordered_map<
175 std::vector<std::weak_ptr<CommandPoolVK>>> g_all_pools_map
180 auto const strong_context = context_.lock();
181 if (!strong_context) {
190 auto const hash = strong_context->GetHash();
191 auto const it = pool_map.find(hash);
192 if (it != pool_map.end()) {
197 auto data = Create();
202 auto const resource = std::make_shared<CommandPoolVK>(
203 std::move(
data->pool), std::move(
data->buffers), context_);
204 pool_map.emplace(hash, resource);
208 g_all_pools_map[strong_context.get()].push_back(resource);
215 std::optional<CommandPoolRecyclerVK::RecycledData>
216 CommandPoolRecyclerVK::Create() {
218 if (
auto data = Reuse()) {
223 auto context = context_.lock();
227 vk::CommandPoolCreateInfo info;
228 info.setQueueFamilyIndex(context->GetGraphicsQueue()->GetIndex().family);
229 info.setFlags(vk::CommandPoolCreateFlagBits::eTransient);
231 auto device = context->GetDevice();
232 auto [result, pool] = device.createCommandPoolUnique(info);
233 if (result != vk::Result::eSuccess) {
236 return CommandPoolRecyclerVK::RecycledData{.pool = std::move(pool),
240 std::optional<CommandPoolRecyclerVK::RecycledData>
241 CommandPoolRecyclerVK::Reuse() {
243 Lock recycled_lock(recycled_mutex_);
244 if (recycled_.empty()) {
249 auto data = std::move(recycled_.back());
250 recycled_.pop_back();
251 return std::move(
data);
255 vk::UniqueCommandPool&& pool,
256 std::vector<vk::UniqueCommandBuffer>&& buffers,
259 auto strong_context = context_.lock();
260 if (!strong_context) {
263 auto device = strong_context->GetDevice();
266 device.resetCommandPool(pool.get(),
267 vk::CommandPoolResetFlagBits::eReleaseResources);
269 device.resetCommandPool(pool.get(), {});
273 Lock recycled_lock(recycled_mutex_);
299 auto found = g_all_pools_map.find(context);
300 if (found != g_all_pools_map.end()) {
301 for (
auto& weak_pool : found->second) {
302 auto pool = weak_pool.lock();
310 g_all_pools_map.erase(found);
BackgroundCommandPoolVK(BackgroundCommandPoolVK &&)=default
BackgroundCommandPoolVK(vk::UniqueCommandPool &&pool, std::vector< vk::UniqueCommandBuffer > &&buffers, size_t unused_count, std::weak_ptr< CommandPoolRecyclerVK > recycler)
static constexpr size_t kUnusedCommandBufferLimit
~BackgroundCommandPoolVK()
void Dispose()
Clears all recycled command pools to let them be reclaimed.
std::shared_ptr< CommandPoolVK > Get()
Gets a command pool for the current thread.
static void DestroyThreadLocalPools(const ContextVK *context)
Clean up resources held by all per-thread command pools associated with the given context.
void Reclaim(vk::UniqueCommandPool &&pool, std::vector< vk::UniqueCommandBuffer > &&buffers, bool should_trim=false)
Returns a command pool to be reset on a background thread.
void CollectCommandBuffer(vk::UniqueCommandBuffer &&buffer)
Collects the given |vk::CommandBuffer| to be retained.
void Destroy()
Delete all Vulkan objects in this command pool.
vk::UniqueCommandBuffer CreateCommandBuffer()
Creates and returns a new |vk::CommandBuffer|.
A unique handle to a resource which will be reclaimed by the specified resource manager.
static Mutex g_all_pools_map_mutex
static thread_local std::unique_ptr< CommandPoolMap > tls_command_pool_map
std::unordered_map< uint64_t, std::shared_ptr< CommandPoolVK > > CommandPoolMap
static std::unordered_map< const ContextVK *, std::vector< std::weak_ptr< CommandPoolVK > > > g_all_pools_map IPLR_GUARDED_BY(g_all_pools_map_mutex)
A unique command pool and zero or more recycled command buffers.
vk::UniqueCommandPool pool
std::shared_ptr< const fml::Mapping > data