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 
11 #include "vulkan/vulkan_enums.hpp"
12 #include "vulkan/vulkan_handles.hpp"
13 
14 namespace impeller {
15 
21 };
22 
23 /// Descriptor pools are always allocated with the following sizes.
24 static const constexpr DescriptorPoolSize kDefaultBindingSize =
26  .buffer_bindings = 512u, // Buffer Bindings
27  .texture_bindings = 256u, // Texture Bindings
28  .storage_bindings = 32,
29  .subpass_bindings = 4u // Subpass Bindings
30  };
31 
32 // Holds the command pool in a background thread, recyling it when not in use.
34  public:
36 
38  vk::UniqueDescriptorPool&& pool,
39  std::weak_ptr<DescriptorPoolRecyclerVK> recycler)
40  : pool_(std::move(pool)), recycler_(std::move(recycler)) {}
41 
43  auto const recycler = recycler_.lock();
44 
45  // Not only does this prevent recycling when the context is being destroyed,
46  // but it also prevents the destructor from effectively being called twice;
47  // once for the original BackgroundCommandPoolVK() and once for the moved
48  // BackgroundCommandPoolVK().
49  if (!recycler) {
50  return;
51  }
52 
53  recycler->Reclaim(std::move(pool_));
54  }
55 
56  private:
58 
60  delete;
61 
62  vk::UniqueDescriptorPool pool_;
63  uint32_t allocated_capacity_;
64  std::weak_ptr<DescriptorPoolRecyclerVK> recycler_;
65 };
66 
67 DescriptorPoolVK::DescriptorPoolVK(std::weak_ptr<const ContextVK> context)
68  : context_(std::move(context)) {}
69 
71  if (pools_.empty()) {
72  return;
73  }
74 
75  auto const context = context_.lock();
76  if (!context) {
77  return;
78  }
79  auto const recycler = context->GetDescriptorPoolRecycler();
80  if (!recycler) {
81  return;
82  }
83 
84  for (auto i = 0u; i < pools_.size(); i++) {
85  auto reset_pool_when_dropped =
86  BackgroundDescriptorPoolVK(std::move(pools_[i]), recycler);
87 
89  context->GetResourceManager(), std::move(reset_pool_when_dropped));
90  }
91  pools_.clear();
92 }
93 
94 fml::StatusOr<vk::DescriptorSet> DescriptorPoolVK::AllocateDescriptorSets(
95  const vk::DescriptorSetLayout& layout,
96  const ContextVK& context_vk) {
97  if (pools_.empty()) {
98  CreateNewPool(context_vk);
99  }
100 
101  vk::DescriptorSetAllocateInfo set_info;
102  set_info.setDescriptorPool(pools_.back().get());
103  set_info.setPSetLayouts(&layout);
104  set_info.setDescriptorSetCount(1);
105 
106  vk::DescriptorSet set;
107  auto result = context_vk.GetDevice().allocateDescriptorSets(&set_info, &set);
108  if (result == vk::Result::eErrorOutOfPoolMemory) {
109  // If the pool ran out of memory, we need to create a new pool.
110  CreateNewPool(context_vk);
111  set_info.setDescriptorPool(pools_.back().get());
112  result = context_vk.GetDevice().allocateDescriptorSets(&set_info, &set);
113  }
114 
115  if (result != vk::Result::eSuccess) {
116  VALIDATION_LOG << "Could not allocate descriptor sets: "
117  << vk::to_string(result);
118  return fml::Status(fml::StatusCode::kUnknown, "");
119  }
120  return set;
121 }
122 
123 fml::Status DescriptorPoolVK::CreateNewPool(const ContextVK& context_vk) {
124  auto new_pool = context_vk.GetDescriptorPoolRecycler()->Get();
125  if (!new_pool) {
126  return fml::Status(fml::StatusCode::kUnknown,
127  "Failed to create descriptor pool");
128  }
129  pools_.emplace_back(std::move(new_pool));
130  return fml::Status();
131 }
132 
133 void DescriptorPoolRecyclerVK::Reclaim(vk::UniqueDescriptorPool&& pool) {
134  // Reset the pool on a background thread.
135  auto strong_context = context_.lock();
136  if (!strong_context) {
137  return;
138  }
139  auto device = strong_context->GetDevice();
140  device.resetDescriptorPool(pool.get());
141 
142  // Move the pool to the recycled list.
143  Lock recycled_lock(recycled_mutex_);
144 
145  if (recycled_.size() < kMaxRecycledPools) {
146  recycled_.push_back(std::move(pool));
147  return;
148  }
149 }
150 
151 vk::UniqueDescriptorPool DescriptorPoolRecyclerVK::Get() {
152  // Recycle a pool with a matching minumum capcity if it is available.
153  auto recycled_pool = Reuse();
154  if (recycled_pool.has_value()) {
155  return std::move(recycled_pool.value());
156  }
157  return Create();
158 }
159 
160 vk::UniqueDescriptorPool DescriptorPoolRecyclerVK::Create() {
161  auto strong_context = context_.lock();
162  if (!strong_context) {
163  VALIDATION_LOG << "Unable to create a descriptor pool";
164  return {};
165  }
166 
167  std::vector<vk::DescriptorPoolSize> pools = {
168  vk::DescriptorPoolSize{vk::DescriptorType::eCombinedImageSampler,
170  vk::DescriptorPoolSize{vk::DescriptorType::eUniformBuffer,
172  vk::DescriptorPoolSize{vk::DescriptorType::eStorageBuffer,
174  vk::DescriptorPoolSize{vk::DescriptorType::eInputAttachment,
176  vk::DescriptorPoolCreateInfo pool_info;
177  pool_info.setMaxSets(kDefaultBindingSize.texture_bindings +
181  pool_info.setPoolSizes(pools);
182  auto [result, pool] =
183  strong_context->GetDevice().createDescriptorPoolUnique(pool_info);
184  if (result != vk::Result::eSuccess) {
185  VALIDATION_LOG << "Unable to create a descriptor pool";
186  }
187  return std::move(pool);
188 }
189 
190 std::optional<vk::UniqueDescriptorPool> DescriptorPoolRecyclerVK::Reuse() {
191  Lock lock(recycled_mutex_);
192  if (recycled_.empty()) {
193  return std::nullopt;
194  }
195 
196  auto recycled = std::move(recycled_[recycled_.size() - 1]);
197  recycled_.pop_back();
198  return recycled;
199 }
200 
201 } // namespace impeller
impeller::DescriptorPoolRecyclerVK::Reclaim
void Reclaim(vk::UniqueDescriptorPool &&pool)
Returns the descriptor pool to be reset on a background thread.
Definition: descriptor_pool_vk.cc:133
impeller::DescriptorPoolVK::DescriptorPoolVK
DescriptorPoolVK(std::weak_ptr< const ContextVK > context)
Definition: descriptor_pool_vk.cc:67
impeller::UniqueResourceVKT
A unique handle to a resource which will be reclaimed by the specified resource manager.
Definition: resource_manager_vk.h:145
impeller::DescriptorPoolVK::~DescriptorPoolVK
~DescriptorPoolVK()
Definition: descriptor_pool_vk.cc:70
impeller::Lock
Definition: thread.h:75
impeller::BackgroundDescriptorPoolVK::BackgroundDescriptorPoolVK
BackgroundDescriptorPoolVK(BackgroundDescriptorPoolVK &&)=default
validation.h
impeller::DescriptorPoolSize::buffer_bindings
size_t buffer_bindings
Definition: descriptor_pool_vk.cc:17
impeller::DescriptorPoolRecyclerVK::kMaxRecycledPools
static constexpr size_t kMaxRecycledPools
The maximum number of descriptor pools this recycler will hold onto.
Definition: descriptor_pool_vk.h:57
impeller::DescriptorPoolSize::subpass_bindings
size_t subpass_bindings
Definition: descriptor_pool_vk.cc:20
impeller::BackgroundDescriptorPoolVK::~BackgroundDescriptorPoolVK
~BackgroundDescriptorPoolVK()
Definition: descriptor_pool_vk.cc:42
impeller::ContextVK::GetDescriptorPoolRecycler
std::shared_ptr< DescriptorPoolRecyclerVK > GetDescriptorPoolRecycler() const
Definition: context_vk.cc:573
impeller::DescriptorPoolRecyclerVK::Get
vk::UniqueDescriptorPool Get()
Gets a descriptor pool.
Definition: descriptor_pool_vk.cc:151
impeller::ContextVK
Definition: context_vk.h:42
impeller::DescriptorPoolSize
Definition: descriptor_pool_vk.cc:16
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:73
impeller::BackgroundDescriptorPoolVK::BackgroundDescriptorPoolVK
BackgroundDescriptorPoolVK(vk::UniqueDescriptorPool &&pool, std::weak_ptr< DescriptorPoolRecyclerVK > recycler)
Definition: descriptor_pool_vk.cc:37
impeller::DescriptorPoolSize::storage_bindings
size_t storage_bindings
Definition: descriptor_pool_vk.cc:19
resource_manager_vk.h
std
Definition: comparable.h:95
impeller::ContextVK::GetDevice
const vk::Device & GetDevice() const
Definition: context_vk.cc:514
descriptor_pool_vk.h
impeller::DescriptorPoolVK::AllocateDescriptorSets
fml::StatusOr< vk::DescriptorSet > AllocateDescriptorSets(const vk::DescriptorSetLayout &layout, const ContextVK &context_vk)
Definition: descriptor_pool_vk.cc:94
impeller::DescriptorPoolSize::texture_bindings
size_t texture_bindings
Definition: descriptor_pool_vk.cc:18
impeller
Definition: aiks_blur_unittests.cc:20
impeller::BackgroundDescriptorPoolVK
Definition: descriptor_pool_vk.cc:33
impeller::kDefaultBindingSize
static const constexpr DescriptorPoolSize kDefaultBindingSize
Descriptor pools are always allocated with the following sizes.
Definition: descriptor_pool_vk.cc:24