Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
pipeline_library_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 <cstdint>
8
17
18namespace impeller {
19
20PipelineLibraryVK::PipelineLibraryVK(
21 const std::shared_ptr<DeviceHolderVK>& device_holder,
22 std::shared_ptr<const Capabilities> caps,
23 fml::UniqueFD cache_directory,
24 std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner)
25 : device_holder_(device_holder),
26 pso_cache_(std::make_shared<PipelineCacheVK>(std::move(caps),
27 device_holder,
28 std::move(cache_directory))),
29 worker_task_runner_(std::move(worker_task_runner)),
30 compile_queue_(PipelineCompileQueue::Create(worker_task_runner_)) {
31 FML_DCHECK(worker_task_runner_);
32 if (!pso_cache_->IsValid() || !worker_task_runner_) {
33 return;
34 }
35
36 is_valid_ = true;
37}
38
39PipelineLibraryVK::~PipelineLibraryVK() = default;
40
41// |PipelineLibrary|
42bool PipelineLibraryVK::IsValid() const {
43 return is_valid_;
44}
45
46std::unique_ptr<ComputePipelineVK> PipelineLibraryVK::CreateComputePipeline(
47 const ComputePipelineDescriptor& desc,
48 PipelineKey pipeline_key) {
49 TRACE_EVENT0("flutter", __FUNCTION__);
50 vk::ComputePipelineCreateInfo pipeline_info;
51
52 //----------------------------------------------------------------------------
53 /// Shader Stage
54 ///
55 const auto entrypoint = desc.GetStageEntrypoint();
56 if (!entrypoint) {
57 VALIDATION_LOG << "Compute shader is missing an entrypoint.";
58 return nullptr;
59 }
60
61 std::shared_ptr<DeviceHolderVK> strong_device = device_holder_.lock();
62 if (!strong_device) {
63 return nullptr;
64 }
65 auto device_properties = strong_device->GetPhysicalDevice().getProperties();
66 auto max_wg_size = device_properties.limits.maxComputeWorkGroupSize;
67
68 // Specialization constant 0 carries the workgroup size. Set it to the device
69 // maximum. This only affects shaders that declare their size with
70 // `local_size_x_id = 0`. A shader with a literal `local_size` has no such
71 // constant, so Vulkan ignores this and uses the size baked into the module.
72 vk::SpecializationMapEntry specialization_map_entry[1];
73
74 uint32_t workgroup_size_x = max_wg_size[0];
75 specialization_map_entry[0].constantID = 0;
76 specialization_map_entry[0].offset = 0;
77 specialization_map_entry[0].size = sizeof(uint32_t);
78
79 vk::SpecializationInfo specialization_info;
80 specialization_info.mapEntryCount = 1;
81 specialization_info.pMapEntries = &specialization_map_entry[0];
82 specialization_info.dataSize = sizeof(uint32_t);
83 specialization_info.pData = &workgroup_size_x;
84
85 vk::PipelineShaderStageCreateInfo info;
86 info.setStage(vk::ShaderStageFlagBits::eCompute);
87 info.setPName("main");
88 info.setModule(ShaderFunctionVK::Cast(entrypoint.get())->GetModule());
89 info.setPSpecializationInfo(&specialization_info);
90 pipeline_info.setStage(info);
91
92 //----------------------------------------------------------------------------
93 /// Pipeline Layout a.k.a the descriptor sets and uniforms.
94 ///
95 std::vector<vk::DescriptorSetLayoutBinding> desc_bindings;
96
97 for (auto layout : desc.GetDescriptorSetLayouts()) {
98 auto vk_desc_layout = ToVKDescriptorSetLayoutBinding(layout);
99 desc_bindings.push_back(vk_desc_layout);
100 }
101
102 vk::DescriptorSetLayoutCreateInfo descs_layout_info;
103 descs_layout_info.setBindings(desc_bindings);
104
105 auto [descs_result, descs_layout] =
106 strong_device->GetDevice().createDescriptorSetLayoutUnique(
107 descs_layout_info);
108 if (descs_result != vk::Result::eSuccess) {
109 VALIDATION_LOG << "unable to create uniform descriptors";
110 return nullptr;
111 }
112
113 ContextVK::SetDebugName(strong_device->GetDevice(), descs_layout.get(),
114 "Descriptor Set Layout " + desc.GetLabel());
115
116 //----------------------------------------------------------------------------
117 /// Create the pipeline layout.
118 ///
119 vk::PipelineLayoutCreateInfo pipeline_layout_info;
120 pipeline_layout_info.setSetLayouts(descs_layout.get());
121 auto pipeline_layout = strong_device->GetDevice().createPipelineLayoutUnique(
122 pipeline_layout_info);
123 if (pipeline_layout.result != vk::Result::eSuccess) {
124 VALIDATION_LOG << "Could not create pipeline layout for pipeline "
125 << desc.GetLabel() << ": "
126 << vk::to_string(pipeline_layout.result);
127 return nullptr;
128 }
129 pipeline_info.setLayout(pipeline_layout.value.get());
130
131 //----------------------------------------------------------------------------
132 /// Finally, all done with the setup info. Create the pipeline itself.
133 ///
134 auto pipeline = pso_cache_->CreatePipeline(pipeline_info);
135 if (!pipeline) {
136 VALIDATION_LOG << "Could not create graphics pipeline: " << desc.GetLabel();
137 return nullptr;
138 }
139
140 ContextVK::SetDebugName(strong_device->GetDevice(), *pipeline_layout.value,
141 "Pipeline Layout " + desc.GetLabel());
142 ContextVK::SetDebugName(strong_device->GetDevice(), *pipeline,
143 "Pipeline " + desc.GetLabel());
144
145 return std::make_unique<ComputePipelineVK>(
146 device_holder_,
147 weak_from_this(), //
148 desc, //
149 std::move(pipeline), //
150 std::move(pipeline_layout.value), //
151 std::move(descs_layout), //
152 pipeline_key);
153}
154
155// |PipelineLibrary|
156PipelineFuture<PipelineDescriptor> PipelineLibraryVK::GetPipeline(
157 PipelineDescriptor descriptor,
158 bool async,
159 bool threadsafe) {
160 Lock lock(pipelines_mutex_);
161 if (auto found = pipelines_.find(descriptor); found != pipelines_.end()) {
162 return found->second;
163 }
164
165 cache_dirty_ = true;
166 if (!IsValid()) {
167 return {
168 descriptor,
169 RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(nullptr)};
170 }
171
172 auto promise = std::make_shared<
173 NoExceptionPromise<std::shared_ptr<Pipeline<PipelineDescriptor>>>>();
174 auto pipeline_future =
175 PipelineFuture<PipelineDescriptor>{descriptor, promise->get_future()};
176 pipelines_[descriptor] = pipeline_future;
177
178 auto weak_this = weak_from_this();
179
180 PipelineKey next_key = pipeline_key_++;
181 auto generation_task = [descriptor, weak_this, promise, next_key]() {
182 auto thiz = weak_this.lock();
183 if (!thiz) {
184 promise->set_value(nullptr);
185 return;
186 }
187
188 promise->set_value(PipelineVK::Create(
189 descriptor, //
190 PipelineLibraryVK::Cast(*thiz).device_holder_.lock(), //
191 weak_this, //
192 next_key //
193 ));
194 };
195
196 if (async) {
197 compile_queue_->PostJobForDescriptor(descriptor,
198 std::move(generation_task));
199 } else {
200 generation_task();
201 }
202
203 return pipeline_future;
204}
205
206// |PipelineLibrary|
207PipelineFuture<ComputePipelineDescriptor> PipelineLibraryVK::GetPipeline(
208 ComputePipelineDescriptor descriptor,
209 bool async) {
210 Lock lock(pipelines_mutex_);
211 if (auto found = compute_pipelines_.find(descriptor);
212 found != compute_pipelines_.end()) {
213 return found->second;
214 }
215
216 cache_dirty_ = true;
217 if (!IsValid()) {
218 return {
219 descriptor,
220 RealizedFuture<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>(
221 nullptr)};
222 }
223
224 auto promise = std::make_shared<
225 std::promise<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>>();
226 auto pipeline_future = PipelineFuture<ComputePipelineDescriptor>{
227 descriptor, promise->get_future()};
228 compute_pipelines_[descriptor] = pipeline_future;
229
230 auto weak_this = weak_from_this();
231
232 PipelineKey next_key = pipeline_key_++;
233 auto generation_task = [descriptor, weak_this, promise, next_key]() {
234 auto self = weak_this.lock();
235 if (!self) {
236 promise->set_value(nullptr);
237 VALIDATION_LOG << "Pipeline library was collected before the pipeline "
238 "could be created.";
239 return;
240 }
241
242 auto pipeline = PipelineLibraryVK::Cast(*self).CreateComputePipeline(
243 descriptor, next_key);
244 if (!pipeline) {
245 promise->set_value(nullptr);
246 VALIDATION_LOG << "Could not create pipeline: " << descriptor.GetLabel();
247 return;
248 }
249
250 promise->set_value(std::move(pipeline));
251 };
252
253 if (async) {
254 worker_task_runner_->PostTask(generation_task);
255 } else {
256 generation_task();
257 }
258
259 return pipeline_future;
260}
261
262// |PipelineLibrary|
263bool PipelineLibraryVK::HasPipeline(const PipelineDescriptor& descriptor) {
264 Lock lock(pipelines_mutex_);
265 return pipelines_.find(descriptor) != pipelines_.end();
266}
267
268// |PipelineLibrary|
269void PipelineLibraryVK::RemovePipelinesWithEntryPoint(
270 std::shared_ptr<const ShaderFunction> function) {
271 Lock lock(pipelines_mutex_);
272
273 fml::erase_if(pipelines_, [&](auto item) {
274 return item->first.GetEntrypointForStage(function->GetStage())
275 ->IsEqual(*function);
276 });
277}
278
279void PipelineLibraryVK::DidAcquireSurfaceFrame() {
280 if (++frames_acquired_ == 50u) {
281 if (cache_dirty_) {
282 cache_dirty_ = false;
283 PersistPipelineCacheToDisk();
284 }
285 frames_acquired_ = 0;
286 }
287}
288
289void PipelineLibraryVK::PersistPipelineCacheToDisk() {
290 worker_task_runner_->PostTask(
291 [weak_cache = decltype(pso_cache_)::weak_type(pso_cache_)]() {
292 auto cache = weak_cache.lock();
293 if (!cache) {
294 return;
295 }
296 cache->PersistCacheToDisk();
297 });
298}
299
300const std::shared_ptr<PipelineCacheVK>& PipelineLibraryVK::GetPSOCache() const {
301 return pso_cache_;
302}
303
304const std::shared_ptr<fml::ConcurrentTaskRunner>&
305PipelineLibraryVK::GetWorkerTaskRunner() const {
306 return worker_task_runner_;
307}
308
309PipelineCompileQueue* PipelineLibraryVK::GetPipelineCompileQueue() const {
310 return compile_queue_.get();
311}
312
313} // namespace impeller
A task queue designed for managing compilation of pipeline state objects.
std::vector< std::pair< uint64_t, std::unique_ptr< GenericRenderPipelineHandle > > > pipelines_
#define FML_DCHECK(condition)
Definition logging.h:122
Dart_NativeFunction function
Definition fuchsia.cc:51
void erase_if(Collection &container, const std::function< bool(typename Collection::iterator)> &predicate)
Definition container.h:16
ScopedObject< Object > Create(CtorArgs &&... args)
Definition object.h:161
constexpr vk::DescriptorSetLayoutBinding ToVKDescriptorSetLayoutBinding(const DescriptorSetLayout &layout)
Definition formats_vk.h:332
int64_t PipelineKey
Definition pipeline.h:22
Definition ref_ptr.h:261
std::shared_ptr< PipelineGLES > pipeline
#define TRACE_EVENT0(category_group, name)
#define VALIDATION_LOG
Definition validation.h:91