Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
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
11namespace impeller {
12
19
20/// Descriptor pools are always allocated with the following sizes.
23 .buffer_bindings = 512u, // Buffer Bindings
24 .texture_bindings = 256u, // Texture Bindings
25 .storage_bindings = 32,
26 .subpass_bindings = 4u // Subpass Bindings
27 };
28
29DescriptorPoolVK::DescriptorPoolVK(std::weak_ptr<const ContextVK> context)
30 : context_(std::move(context)) {}
31
32void DescriptorPoolVK::Destroy() {
33 pools_.clear();
34}
35
36DescriptorPoolVK::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
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 // FragmentedPool == OutOfMemory AND most likely due to fragmentation
85 result == vk::Result::eErrorFragmentedPool) {
86 // If the pool ran out of memory, we need to create a new pool.
87 CreateNewPool(context_vk);
88 set_info.setDescriptorPool(pools_.back().get());
89 result = context_vk.GetDevice().allocateDescriptorSets(&set_info, &set);
90 }
91 auto lookup_result =
92 descriptor_sets_.try_emplace(pipeline_key, DescriptorCache{});
93 lookup_result.first->second.used.push_back(set);
94
95 if (result != vk::Result::eSuccess) {
96 VALIDATION_LOG << "Could not allocate descriptor sets: "
97 << vk::to_string(result);
99 }
100 return set;
101}
102
103fml::Status DescriptorPoolVK::CreateNewPool(const ContextVK& context_vk) {
104 auto new_pool = context_vk.GetDescriptorPoolRecycler()->Get();
105 if (!new_pool) {
107 "Failed to create descriptor pool");
108 }
109 pools_.emplace_back(std::move(new_pool));
110 return fml::Status();
111}
112
114 DescriptorCacheMap descriptor_sets,
115 std::vector<vk::UniqueDescriptorPool> pools) {
116 // Reset the pool on a background thread.
117 auto strong_context = context_.lock();
118 if (!strong_context) {
119 return;
120 }
121
122 for (auto& [_, cache] : descriptor_sets) {
123 cache.unused.insert(cache.unused.end(), cache.used.begin(),
124 cache.used.end());
125 cache.used.clear();
126 }
127
128 // Move the pool to the recycled list. If more than 32 pool are
129 // cached then delete the newest entry.
130 Lock recycled_lock(recycled_mutex_);
131 while (recycled_.size() >= kMaxRecycledPools) {
132 auto& back_entry = recycled_.back();
133 back_entry->Destroy();
134 recycled_.pop_back();
135 }
136 recycled_.push_back(std::make_shared<DescriptorPoolVK>(
137 context_, std::move(descriptor_sets), std::move(pools)));
138}
139
140vk::UniqueDescriptorPool DescriptorPoolRecyclerVK::Get() {
141 // Recycle a pool with a matching minumum capcity if it is available.
142 return Create();
143}
144
145vk::UniqueDescriptorPool DescriptorPoolRecyclerVK::Create() {
146 auto strong_context = context_.lock();
147 if (!strong_context) {
148 VALIDATION_LOG << "Unable to create a descriptor pool";
149 return {};
150 }
151
152 std::vector<vk::DescriptorPoolSize> pools = {
153 vk::DescriptorPoolSize{vk::DescriptorType::eCombinedImageSampler,
155 vk::DescriptorPoolSize{vk::DescriptorType::eUniformBuffer,
157 vk::DescriptorPoolSize{vk::DescriptorType::eStorageBuffer,
159 vk::DescriptorPoolSize{vk::DescriptorType::eInputAttachment,
161 vk::DescriptorPoolCreateInfo pool_info;
162 pool_info.setMaxSets(kDefaultBindingSize.texture_bindings +
166 pool_info.setPoolSizes(pools);
167 auto [result, pool] =
168 strong_context->GetDevice().createDescriptorPoolUnique(pool_info);
169 if (result != vk::Result::eSuccess) {
170 VALIDATION_LOG << "Unable to create a descriptor pool";
171 }
172 return std::move(pool);
173}
174
175std::shared_ptr<DescriptorPoolVK>
177 {
178 Lock recycled_lock(recycled_mutex_);
179 if (!recycled_.empty()) {
180 auto result = recycled_.back();
181 recycled_.pop_back();
182 return result;
183 }
184 }
185 return std::make_shared<DescriptorPoolVK>(context_);
186}
187
188} // namespace impeller
const vk::Device & GetDevice() const
std::shared_ptr< DescriptorPoolRecyclerVK > GetDescriptorPoolRecycler() const
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:22
static const constexpr DescriptorPoolSize kDefaultBindingSize
Descriptor pools are always allocated with the following sizes.
Definition ref_ptr.h:261
std::shared_ptr< ContextGLES > context
Used and un-used descriptor sets.
#define VALIDATION_LOG
Definition validation.h:91