| 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
5 #include "impeller/renderer/backend/vulkan/descriptor_pool_vk.h"
6
7 #include <optional>
8
9 #include "impeller/base/validation.h"
10
11 namespace impeller {
12
13 struct DescriptorPoolSize {
14 size_t buffer_bindings;
15 size_t texture_bindings;
16 size_t storage_bindings;
17 size_t subpass_bindings;
18 };
19
20 /// Descriptor pools are always allocated with the following sizes.
21 static const constexpr DescriptorPoolSize kDefaultBindingSize =
22 DescriptorPoolSize{
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
43 DescriptorPoolVK::~DescriptorPoolVK() {
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
111 void DescriptorPoolRecyclerVK::Reclaim(
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,
152 kDefaultBindingSize.texture_bindings},
153 vk::DescriptorPoolSize{vk::DescriptorType::eUniformBuffer,
154 kDefaultBindingSize.buffer_bindings},
155 vk::DescriptorPoolSize{vk::DescriptorType::eStorageBuffer,
156 kDefaultBindingSize.storage_bindings},
157 vk::DescriptorPoolSize{vk::DescriptorType::eInputAttachment,
158 kDefaultBindingSize.subpass_bindings}};
159 vk::DescriptorPoolCreateInfo pool_info;
160 pool_info.setMaxSets(kDefaultBindingSize.texture_bindings +
161 kDefaultBindingSize.buffer_bindings +
162 kDefaultBindingSize.storage_bindings +
163 kDefaultBindingSize.subpass_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>
174 DescriptorPoolRecyclerVK::GetDescriptorPool() {
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
impeller::ContextVK
Definition: context_vk.h:66
impeller::ContextVK::GetDevice
const vk::Device & GetDevice() const
Definition: context_vk.cc:592
impeller::ContextVK::GetDescriptorPoolRecycler
std::shared_ptr< DescriptorPoolRecyclerVK > GetDescriptorPoolRecycler() const
Definition: context_vk.cc:646
impeller::DescriptorPoolRecyclerVK::GetDescriptorPool
std::shared_ptr< DescriptorPoolVK > GetDescriptorPool()
Definition: descriptor_pool_vk.cc:174
impeller::DescriptorPoolRecyclerVK::Reclaim
void Reclaim(DescriptorCacheMap descriptor_sets, std::vector< vk::UniqueDescriptorPool > pools)
Definition: descriptor_pool_vk.cc:111
impeller::DescriptorPoolRecyclerVK::Get
vk::UniqueDescriptorPool Get()
Gets a descriptor pool.
Definition: descriptor_pool_vk.cc:138
impeller::DescriptorPoolRecyclerVK::kMaxRecycledPools
static constexpr size_t kMaxRecycledPools
The maximum number of descriptor pools this recycler will hold onto.
Definition: descriptor_pool_vk.h:76
impeller::DescriptorPoolVK::DescriptorPoolVK
DescriptorPoolVK(std::weak_ptr< const ContextVK > context)
Definition: descriptor_pool_vk.cc:29
impeller::DescriptorPoolVK::AllocateDescriptorSets
fml::StatusOr< vk::DescriptorSet > AllocateDescriptorSets(const vk::DescriptorSetLayout &layout, PipelineKey pipeline_key, const ContextVK &context_vk)
Definition: descriptor_pool_vk.cc:60
impeller::DescriptorPoolVK::~DescriptorPoolVK
~DescriptorPoolVK()
Definition: descriptor_pool_vk.cc:43
impeller::Lock
Definition: thread.h:72
descriptor_pool_vk.h
impeller
Definition: allocation.cc:12
impeller::DescriptorCacheMap
std::unordered_map< PipelineKey, DescriptorCache > DescriptorCacheMap
Definition: descriptor_pool_vk.h:23
impeller::PipelineKey
int64_t PipelineKey
Definition: pipeline.h:22
impeller::kDefaultBindingSize
static constexpr const DescriptorPoolSize kDefaultBindingSize
Descriptor pools are always allocated with the following sizes.
Definition: descriptor_pool_vk.cc:21
std
Definition: comparable.h:95
impeller::DescriptorCache
Used and un-used descriptor sets.
Definition: descriptor_pool_vk.h:18
impeller::DescriptorPoolSize
Definition: descriptor_pool_vk.cc:13
impeller::DescriptorPoolSize::buffer_bindings
size_t buffer_bindings
Definition: descriptor_pool_vk.cc:14
impeller::DescriptorPoolSize::subpass_bindings
size_t subpass_bindings
Definition: descriptor_pool_vk.cc:17
impeller::DescriptorPoolSize::storage_bindings
size_t storage_bindings
Definition: descriptor_pool_vk.cc:16
impeller::DescriptorPoolSize::texture_bindings
size_t texture_bindings
Definition: descriptor_pool_vk.cc:15
validation.h
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:91