Flutter Impeller
descriptor_pool_vk.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #include <optional>
8 
10 
11 namespace impeller {
12 
18 };
19 
20 /// Descriptor pools are always allocated with the following sizes.
21 static const constexpr DescriptorPoolSize kDefaultBindingSize =
23  .buffer_bindings = 512u, // Buffer Bindings
24  .texture_bindings = 256u, // Texture Bindings
25  .storage_bindings = 32,
26  .subpass_bindings = 4u // Subpass Bindings
27  };
28 
29 DescriptorPoolVK::DescriptorPoolVK(std::weak_ptr<const ContextVK> context)
30  : context_(std::move(context)) {}
31 
32 void DescriptorPoolVK::Destroy() {
33  pools_.clear();
34 }
35 
36 DescriptorPoolVK::DescriptorPoolVK(std::weak_ptr<const ContextVK> context,
37  DescriptorCacheMap descriptor_sets,
38  std::vector<vk::UniqueDescriptorPool> pools)
39  : context_(std::move(context)),
40  descriptor_sets_(std::move(descriptor_sets)),
41  pools_(std::move(pools)) {}
42 
44  if (pools_.empty()) {
45  return;
46  }
47 
48  auto const context = context_.lock();
49  if (!context) {
50  return;
51  }
52  auto const recycler = context->GetDescriptorPoolRecycler();
53  if (!recycler) {
54  return;
55  }
56 
57  recycler->Reclaim(std::move(descriptor_sets_), std::move(pools_));
58 }
59 
60 fml::StatusOr<vk::DescriptorSet> DescriptorPoolVK::AllocateDescriptorSets(
61  const vk::DescriptorSetLayout& layout,
62  PipelineKey pipeline_key,
63  const ContextVK& context_vk) {
64  DescriptorCacheMap::iterator existing = descriptor_sets_.find(pipeline_key);
65  if (existing != descriptor_sets_.end() && !existing->second.unused.empty()) {
66  auto descriptor_set = existing->second.unused.back();
67  existing->second.unused.pop_back();
68  existing->second.used.push_back(descriptor_set);
69  return descriptor_set;
70  }
71 
72  if (pools_.empty()) {
73  CreateNewPool(context_vk);
74  }
75 
76  vk::DescriptorSetAllocateInfo set_info;
77  set_info.setDescriptorPool(pools_.back().get());
78  set_info.setPSetLayouts(&layout);
79  set_info.setDescriptorSetCount(1);
80 
81  vk::DescriptorSet set;
82  auto result = context_vk.GetDevice().allocateDescriptorSets(&set_info, &set);
83  if (result == vk::Result::eErrorOutOfPoolMemory) {
84  // If the pool ran out of memory, we need to create a new pool.
85  CreateNewPool(context_vk);
86  set_info.setDescriptorPool(pools_.back().get());
87  result = context_vk.GetDevice().allocateDescriptorSets(&set_info, &set);
88  }
89  auto lookup_result =
90  descriptor_sets_.try_emplace(pipeline_key, DescriptorCache{});
91  lookup_result.first->second.used.push_back(set);
92 
93  if (result != vk::Result::eSuccess) {
94  VALIDATION_LOG << "Could not allocate descriptor sets: "
95  << vk::to_string(result);
96  return fml::Status(fml::StatusCode::kUnknown, "");
97  }
98  return set;
99 }
100 
101 fml::Status DescriptorPoolVK::CreateNewPool(const ContextVK& context_vk) {
102  auto new_pool = context_vk.GetDescriptorPoolRecycler()->Get();
103  if (!new_pool) {
104  return fml::Status(fml::StatusCode::kUnknown,
105  "Failed to create descriptor pool");
106  }
107  pools_.emplace_back(std::move(new_pool));
108  return fml::Status();
109 }
110 
112  DescriptorCacheMap descriptor_sets,
113  std::vector<vk::UniqueDescriptorPool> pools) {
114  // Reset the pool on a background thread.
115  auto strong_context = context_.lock();
116  if (!strong_context) {
117  return;
118  }
119 
120  for (auto& [_, cache] : descriptor_sets) {
121  cache.unused.insert(cache.unused.end(), cache.used.begin(),
122  cache.used.end());
123  cache.used.clear();
124  }
125 
126  // Move the pool to the recycled list. If more than 32 pool are
127  // cached then delete the newest entry.
128  Lock recycled_lock(recycled_mutex_);
129  while (recycled_.size() >= kMaxRecycledPools) {
130  auto& back_entry = recycled_.back();
131  back_entry->Destroy();
132  recycled_.pop_back();
133  }
134  recycled_.push_back(std::make_shared<DescriptorPoolVK>(
135  context_, std::move(descriptor_sets), std::move(pools)));
136 }
137 
138 vk::UniqueDescriptorPool DescriptorPoolRecyclerVK::Get() {
139  // Recycle a pool with a matching minumum capcity if it is available.
140  return Create();
141 }
142 
143 vk::UniqueDescriptorPool DescriptorPoolRecyclerVK::Create() {
144  auto strong_context = context_.lock();
145  if (!strong_context) {
146  VALIDATION_LOG << "Unable to create a descriptor pool";
147  return {};
148  }
149 
150  std::vector<vk::DescriptorPoolSize> pools = {
151  vk::DescriptorPoolSize{vk::DescriptorType::eCombinedImageSampler,
153  vk::DescriptorPoolSize{vk::DescriptorType::eUniformBuffer,
155  vk::DescriptorPoolSize{vk::DescriptorType::eStorageBuffer,
157  vk::DescriptorPoolSize{vk::DescriptorType::eInputAttachment,
159  vk::DescriptorPoolCreateInfo pool_info;
160  pool_info.setMaxSets(kDefaultBindingSize.texture_bindings +
164  pool_info.setPoolSizes(pools);
165  auto [result, pool] =
166  strong_context->GetDevice().createDescriptorPoolUnique(pool_info);
167  if (result != vk::Result::eSuccess) {
168  VALIDATION_LOG << "Unable to create a descriptor pool";
169  }
170  return std::move(pool);
171 }
172 
173 std::shared_ptr<DescriptorPoolVK>
175  {
176  Lock recycled_lock(recycled_mutex_);
177  if (!recycled_.empty()) {
178  auto result = recycled_.back();
179  recycled_.pop_back();
180  return result;
181  }
182  }
183  return std::make_shared<DescriptorPoolVK>(context_);
184 }
185 
186 } // namespace impeller
const vk::Device & GetDevice() const
Definition: context_vk.cc:589
std::shared_ptr< DescriptorPoolRecyclerVK > GetDescriptorPoolRecycler() const
Definition: context_vk.cc:643
std::shared_ptr< DescriptorPoolVK > GetDescriptorPool()
void Reclaim(DescriptorCacheMap descriptor_sets, std::vector< vk::UniqueDescriptorPool > pools)
vk::UniqueDescriptorPool Get()
Gets a descriptor pool.
static constexpr size_t kMaxRecycledPools
The maximum number of descriptor pools this recycler will hold onto.
DescriptorPoolVK(std::weak_ptr< const ContextVK > context)
fml::StatusOr< vk::DescriptorSet > AllocateDescriptorSets(const vk::DescriptorSetLayout &layout, PipelineKey pipeline_key, const ContextVK &context_vk)
std::unordered_map< PipelineKey, DescriptorCache > DescriptorCacheMap
int64_t PipelineKey
Definition: pipeline.h:21
static constexpr const DescriptorPoolSize kDefaultBindingSize
Descriptor pools are always allocated with the following sizes.
Definition: comparable.h:95
Used and un-used descriptor sets.
#define VALIDATION_LOG
Definition: validation.h:91