99#include < utility>
1010
1111#include " impeller/renderer/backend/vulkan/context_vk.h"
12+ #include " impeller/renderer/backend/vulkan/descriptor_pool_vk.h"
1213#include " impeller/renderer/backend/vulkan/resource_manager_vk.h"
1314
1415#include " impeller/renderer/backend/vulkan/vk.h" // IWYU pragma: keep.
@@ -155,10 +156,6 @@ void CommandPoolVK::Destroy() {
155156 collected_buffers_.clear ();
156157}
157158
158- // Associates a resource with a thread and context.
159- using CommandPoolMap =
160- std::unordered_map<uint64_t , std::shared_ptr<CommandPoolVK>>;
161-
162159// CommandPoolVK Lifecycle:
163160// 1. End of frame will reset the command pool (clearing this on a thread).
164161// There will still be references to the command pool from the uncompleted
@@ -169,17 +166,47 @@ using CommandPoolMap =
169166// available for reuse ("recycle").
170167static thread_local std::unique_ptr<CommandPoolMap> tls_command_pool_map;
171168
169+ struct WeakThreadLocalData {
170+ std::weak_ptr<CommandPoolVK> command_pool;
171+ std::weak_ptr<DescriptorPoolVK> descriptor_pool;
172+ };
173+
172174// Map each context to a list of all thread-local command pools associated
173175// with that context.
174176static Mutex g_all_pools_map_mutex;
175- static std::unordered_map<
176- const ContextVK*,
177- std::vector<std::weak_ptr<CommandPoolVK>>> g_all_pools_map
177+ static std::unordered_map<const ContextVK*,
178+ std::vector<WeakThreadLocalData>> g_all_pools_map
178179 IPLR_GUARDED_BY (g_all_pools_map_mutex);
179180
181+ std::shared_ptr<DescriptorPoolVK> CommandPoolRecyclerVK::GetDescriptorPool () {
182+ const auto & strong_context = context_.lock ();
183+ if (!strong_context) {
184+ return nullptr ;
185+ }
186+
187+ // If there is a resource in used for this thread and context, return it.
188+ if (!tls_command_pool_map.get ()) {
189+ tls_command_pool_map.reset (new CommandPoolMap ());
190+ }
191+ CommandPoolMap& pool_map = *tls_command_pool_map.get ();
192+ auto const hash = strong_context->GetHash ();
193+ auto const it = pool_map.find (hash);
194+ if (it != pool_map.end ()) {
195+ return it->second .descriptor_pool ;
196+ }
197+
198+ const auto & result =
199+ InitializeThreadLocalResources (strong_context, pool_map, hash);
200+ if (result.has_value ()) {
201+ return result->descriptor_pool ;
202+ }
203+
204+ return nullptr ;
205+ }
206+
180207// TODO(matanlurey): Return a status_or<> instead of nullptr when we have one.
181208std::shared_ptr<CommandPoolVK> CommandPoolRecyclerVK::Get () {
182- auto const strong_context = context_.lock ();
209+ const auto & strong_context = context_.lock ();
183210 if (!strong_context) {
184211 return nullptr ;
185212 }
@@ -192,25 +219,40 @@ std::shared_ptr<CommandPoolVK> CommandPoolRecyclerVK::Get() {
192219 auto const hash = strong_context->GetHash ();
193220 auto const it = pool_map.find (hash);
194221 if (it != pool_map.end ()) {
195- return it->second ;
222+ return it->second . command_pool ;
196223 }
197224
198- // Otherwise, create a new resource and return it.
225+ const auto & result =
226+ InitializeThreadLocalResources (strong_context, pool_map, hash);
227+ if (result.has_value ()) {
228+ return result->command_pool ;
229+ }
230+
231+ return nullptr ;
232+ }
233+
234+ std::optional<ThreadLocalData>
235+ CommandPoolRecyclerVK::InitializeThreadLocalResources (
236+ const std::shared_ptr<ContextVK>& context,
237+ CommandPoolMap& pool_map,
238+ uint64_t pool_key) {
199239 auto data = Create ();
200240 if (!data || !data->pool ) {
201- return nullptr ;
241+ return std:: nullopt ;
202242 }
203243
204- auto const resource = std::make_shared<CommandPoolVK>(
244+ auto command_pool = std::make_shared<CommandPoolVK>(
205245 std::move (data->pool ), std::move (data->buffers ), context_);
206- pool_map.emplace (hash, resource);
207-
246+ auto descriptor_pool = std::make_shared<DescriptorPoolVK>(context_);
208247 {
209248 Lock all_pools_lock (g_all_pools_map_mutex);
210- g_all_pools_map[strong_context.get ()].push_back (resource);
249+ g_all_pools_map[context.get ()].push_back (WeakThreadLocalData{
250+ .command_pool = command_pool, .descriptor_pool = descriptor_pool});
211251 }
212252
213- return resource;
253+ return pool_map[pool_key] =
254+ ThreadLocalData{.command_pool = std::move (command_pool),
255+ .descriptor_pool = std::move (descriptor_pool)};
214256}
215257
216258// TODO(matanlurey): Return a status_or<> instead of nullopt when we have one.
@@ -293,14 +335,13 @@ void CommandPoolRecyclerVK::DestroyThreadLocalPools(const ContextVK* context) {
293335 Lock all_pools_lock (g_all_pools_map_mutex);
294336 auto found = g_all_pools_map.find (context);
295337 if (found != g_all_pools_map.end ()) {
296- for (auto & weak_pool : found->second ) {
297- auto pool = weak_pool.lock ();
298- if (!pool) {
299- continue ;
338+ for (auto & [command_pool, desc_pool] : found->second ) {
339+ const auto & strong_pool = command_pool.lock ();
340+ if (strong_pool) {
341+ // Delete all objects held by this pool. The destroyed pool will still
342+ // remain in its thread's TLS map until that thread exits.
343+ strong_pool->Destroy ();
300344 }
301- // Delete all objects held by this pool. The destroyed pool will still
302- // remain in its thread's TLS map until that thread exits.
303- pool->Destroy ();
304345 }
305346 g_all_pools_map.erase (found);
306347 }
0 commit comments