| Flutter Impeller |

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
5 #include "impeller/renderer/backend/vulkan/pipeline_library_vk.h"
6
7 #include <chrono>
8 #include <optional>
9 #include <sstream>
10
11 #include "flutter/fml/container.h"
12 #include "flutter/fml/trace_event.h"
13 #include "impeller/base/promise.h"
14 #include "impeller/base/timing.h"
15 #include "impeller/base/validation.h"
16 #include "impeller/renderer/backend/vulkan/context_vk.h"
17 #include "impeller/renderer/backend/vulkan/formats_vk.h"
18 #include "impeller/renderer/backend/vulkan/pipeline_vk.h"
19 #include "impeller/renderer/backend/vulkan/shader_function_vk.h"
20 #include "impeller/renderer/backend/vulkan/vertex_descriptor_vk.h"
21
22 namespace impeller {
23
24 PipelineLibraryVK::PipelineLibraryVK(
25 const std::shared_ptr<DeviceHolder>& device_holder,
26 std::shared_ptr<const Capabilities> caps,
27 fml::UniqueFD cache_directory,
28 std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner)
29 : device_holder_(device_holder),
30 pso_cache_(std::make_shared<PipelineCacheVK>(std::move(caps),
31 device_holder,
32 std::move(cache_directory))),
33 worker_task_runner_(std::move(worker_task_runner)) {
34 FML_DCHECK(worker_task_runner_);
35 if (!pso_cache_->IsValid() || !worker_task_runner_) {
36 return;
37 }
38
39 is_valid_ = true;
40 }
41
42 PipelineLibraryVK::~PipelineLibraryVK() = default;
43
44 // |PipelineLibrary|
45 bool PipelineLibraryVK::IsValid() const {
46 return is_valid_;
47 }
48
49 //------------------------------------------------------------------------------
50 /// @brief Creates an attachment description that does just enough to
51 /// ensure render pass compatibility with the pass associated later
52 /// with the framebuffer.
53 ///
54 /// See
55 /// https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/chap8.html#renderpass-compatibility
56 ///
57 static vk::AttachmentDescription CreatePlaceholderAttachmentDescription(
58 PixelFormat format,
59 SampleCount sample_count) {
60 // Load store ops are immaterial for pass compatibility. The right ops will be
61 // picked up when the pass associated with framebuffer.
62 return CreateAttachmentDescription(format, //
63 sample_count, //
64 LoadAction::kDontCare, //
65 StoreAction::kDontCare, //
66 vk::ImageLayout::eUndefined //
67 );
68 }
69
70 //----------------------------------------------------------------------------
71 /// Render Pass
72 /// We are NOT going to use the same render pass with the framebuffer (later)
73 /// and the graphics pipeline (here). Instead, we are going to ensure that the
74 /// sub-passes are compatible. To see the compatibility rules, see the Vulkan
75 /// spec:
76 /// https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/chap8.html#renderpass-compatibility
77 ///
78 static vk::UniqueRenderPass CreateCompatRenderPassForPipeline(
79 const vk::Device& device,
80 const PipelineDescriptor& desc) {
81 std::vector<vk::AttachmentDescription> attachments;
82
83 std::vector<vk::AttachmentReference> color_refs;
84 vk::AttachmentReference depth_stencil_ref = kUnusedAttachmentReference;
85
86 color_refs.resize(desc.GetMaxColorAttacmentBindIndex() + 1,
87 kUnusedAttachmentReference);
88
89 const auto sample_count = desc.GetSampleCount();
90
91 for (const auto& [bind_point, color] : desc.GetColorAttachmentDescriptors()) {
92 color_refs[bind_point] =
93 vk::AttachmentReference{static_cast<uint32_t>(attachments.size()),
94 vk::ImageLayout::eColorAttachmentOptimal};
95 attachments.emplace_back(
96 CreatePlaceholderAttachmentDescription(color.format, sample_count));
97 }
98
99 if (auto depth = desc.GetDepthStencilAttachmentDescriptor();
100 depth.has_value()) {
101 depth_stencil_ref = vk::AttachmentReference{
102 static_cast<uint32_t>(attachments.size()),
103 vk::ImageLayout::eDepthStencilAttachmentOptimal};
104 attachments.emplace_back(CreatePlaceholderAttachmentDescription(
105 desc.GetDepthPixelFormat(), sample_count));
106 }
107 if (desc.HasStencilAttachmentDescriptors()) {
108 depth_stencil_ref = vk::AttachmentReference{
109 static_cast<uint32_t>(attachments.size()),
110 vk::ImageLayout::eDepthStencilAttachmentOptimal};
111 attachments.emplace_back(CreatePlaceholderAttachmentDescription(
112 desc.GetStencilPixelFormat(), sample_count));
113 }
114
115 vk::SubpassDescription subpass_desc;
116 subpass_desc.pipelineBindPoint = vk::PipelineBindPoint::eGraphics;
117 subpass_desc.setColorAttachments(color_refs);
118 subpass_desc.setPDepthStencilAttachment(&depth_stencil_ref);
119
120 vk::RenderPassCreateInfo render_pass_desc;
121 render_pass_desc.setAttachments(attachments);
122 render_pass_desc.setPSubpasses(&subpass_desc);
123 render_pass_desc.setSubpassCount(1u);
124
125 auto [result, pass] = device.createRenderPassUnique(render_pass_desc);
126 if (result != vk::Result::eSuccess) {
127 VALIDATION_LOG << "Failed to create render pass for pipeline '"
128 << desc.GetLabel() << "'. Error: " << vk::to_string(result);
129 return {};
130 }
131
132 // This pass is not used with the render pass. It is only necessary to tell
133 // Vulkan the expected render pass layout. The actual pass will be created
134 // later during render pass setup and will need to be compatible with this
135 // one.
136 ContextVK::SetDebugName(device, pass.get(),
137 "Compat Render Pass: " + desc.GetLabel());
138
139 return std::move(pass);
140 }
141
142 constexpr vk::FrontFace ToVKFrontFace(WindingOrder order) {
143 switch (order) {
144 case WindingOrder::kClockwise:
145 return vk::FrontFace::eClockwise;
146 case WindingOrder::kCounterClockwise:
147 return vk::FrontFace::eCounterClockwise;
148 }
149 FML_UNREACHABLE();
150 }
151
152 static vk::PipelineCreationFeedbackEXT EmptyFeedback() {
153 vk::PipelineCreationFeedbackEXT feedback;
154 // If the VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT is not set in flags, an
155 // implementation must not set any other bits in flags, and the values of all
156 // other VkPipelineCreationFeedback data members are undefined.
157 feedback.flags = vk::PipelineCreationFeedbackFlagBits::eValid;
158 return feedback;
159 }
160
161 static void ReportPipelineCreationFeedbackToLog(
162 std::stringstream& stream,
163 const vk::PipelineCreationFeedbackEXT& feedback) {
164 const auto pipeline_cache_hit =
165 feedback.flags &
166 vk::PipelineCreationFeedbackFlagBits::eApplicationPipelineCacheHit;
167 const auto base_pipeline_accl =
168 feedback.flags &
169 vk::PipelineCreationFeedbackFlagBits::eBasePipelineAcceleration;
170 auto duration = std::chrono::duration_cast<MillisecondsF>(
171 std::chrono::nanoseconds{feedback.duration});
172 stream << "Time: " << duration.count() << "ms"
173 << " Cache Hit: " << static_cast<bool>(pipeline_cache_hit)
174 << " Base Accel: " << static_cast<bool>(base_pipeline_accl)
175 << " Thread: " << std::this_thread::get_id();
176 }
177
178 static void ReportPipelineCreationFeedbackToLog(
179 const PipelineDescriptor& desc,
180 const vk::PipelineCreationFeedbackCreateInfoEXT& feedback) {
181 std::stringstream stream;
182 stream << std::fixed << std::showpoint << std::setprecision(2);
183 stream << std::endl << ">>>>>>" << std::endl;
184 stream << "Pipeline '" << desc.GetLabel() << "' ";
185 ReportPipelineCreationFeedbackToLog(stream,
186 *feedback.pPipelineCreationFeedback);
187 if (feedback.pipelineStageCreationFeedbackCount != 0) {
188 stream << std::endl;
189 }
190 for (size_t i = 0, count = feedback.pipelineStageCreationFeedbackCount;
191 i < count; i++) {
192 stream << "\tStage " << i + 1 << ": ";
193 ReportPipelineCreationFeedbackToLog(
194 stream, feedback.pPipelineStageCreationFeedbacks[i]);
195 if (i != count - 1) {
196 stream << std::endl;
197 }
198 }
199 stream << std::endl << "<<<<<<" << std::endl;
200 FML_LOG(ERROR) << stream.str();
201 }
202
203 static void ReportPipelineCreationFeedbackToTrace(
204 const PipelineDescriptor& desc,
205 const vk::PipelineCreationFeedbackCreateInfoEXT& feedback) {
206 static int64_t gPipelineCacheHits = 0;
207 static int64_t gPipelineCacheMisses = 0;
208 static int64_t gPipelines = 0;
209 if (feedback.pPipelineCreationFeedback->flags &
210 vk::PipelineCreationFeedbackFlagBits::eApplicationPipelineCacheHit) {
211 gPipelineCacheHits++;
212 } else {
213 gPipelineCacheMisses++;
214 }
215 gPipelines++;
216 static constexpr int64_t kImpellerPipelineTraceID = 1988;
217 FML_TRACE_COUNTER("impeller", //
218 "PipelineCache", // series name
219 kImpellerPipelineTraceID, // series ID
220 "PipelineCacheHits", gPipelineCacheHits, //
221 "PipelineCacheMisses", gPipelineCacheMisses, //
222 "TotalPipelines", gPipelines //
223 );
224 }
225
226 static void ReportPipelineCreationFeedback(
227 const PipelineDescriptor& desc,
228 const vk::PipelineCreationFeedbackCreateInfoEXT& feedback) {
229 constexpr bool kReportPipelineCreationFeedbackToLogs = false;
230 constexpr bool kReportPipelineCreationFeedbackToTraces = true;
231 if (kReportPipelineCreationFeedbackToLogs) {
232 ReportPipelineCreationFeedbackToLog(desc, feedback);
233 }
234 if (kReportPipelineCreationFeedbackToTraces) {
235 ReportPipelineCreationFeedbackToTrace(desc, feedback);
236 }
237 }
238
239 std::unique_ptr<PipelineVK> PipelineLibraryVK::CreatePipeline(
240 const PipelineDescriptor& desc) {
241 TRACE_EVENT0("flutter", __FUNCTION__);
242 vk::StructureChain<vk::GraphicsPipelineCreateInfo,
243 vk::PipelineCreationFeedbackCreateInfoEXT>
244 chain;
245
246 const auto& supports_pipeline_creation_feedback =
247 pso_cache_->GetCapabilities()->HasOptionalDeviceExtension(
248 OptionalDeviceExtensionVK::kEXTPipelineCreationFeedback);
249 if (!supports_pipeline_creation_feedback) {
250 chain.unlink<vk::PipelineCreationFeedbackCreateInfoEXT>();
251 }
252
253 auto& pipeline_info = chain.get<vk::GraphicsPipelineCreateInfo>();
254
255 //----------------------------------------------------------------------------
256 /// Dynamic States
257 ///
258 vk::PipelineDynamicStateCreateInfo dynamic_create_state_info;
259 std::vector<vk::DynamicState> dynamic_states = {
260 vk::DynamicState::eViewport,
261 vk::DynamicState::eScissor,
262 vk::DynamicState::eStencilReference,
263 };
264 dynamic_create_state_info.setDynamicStates(dynamic_states);
265 pipeline_info.setPDynamicState(&dynamic_create_state_info);
266
267 //----------------------------------------------------------------------------
268 /// Viewport State
269 ///
270 vk::PipelineViewportStateCreateInfo viewport_state;
271 viewport_state.setViewportCount(1u);
272 viewport_state.setScissorCount(1u);
273 // The actual viewport and scissor rects are not set here since they are
274 // dynamic as mentioned above in the dynamic state info.
275 pipeline_info.setPViewportState(&viewport_state);
276
277 //----------------------------------------------------------------------------
278 /// Shader Stages
279 ///
280 std::vector<vk::PipelineShaderStageCreateInfo> shader_stages;
281 for (const auto& entrypoint : desc.GetStageEntrypoints()) {
282 auto stage = ToVKShaderStageFlagBits(entrypoint.first);
283 if (!stage.has_value()) {
284 VALIDATION_LOG << "Unsupported shader type in pipeline: "
285 << desc.GetLabel();
286 return nullptr;
287 }
288 vk::PipelineShaderStageCreateInfo info;
289 info.setStage(stage.value());
290 info.setPName("main");
291 info.setModule(
292 ShaderFunctionVK::Cast(entrypoint.second.get())->GetModule());
293 shader_stages.push_back(info);
294 }
295 pipeline_info.setStages(shader_stages);
296
297 //----------------------------------------------------------------------------
298 /// Rasterization State
299 ///
300 vk::PipelineRasterizationStateCreateInfo rasterization_state;
301 rasterization_state.setFrontFace(ToVKFrontFace(desc.GetWindingOrder()));
302 rasterization_state.setCullMode(ToVKCullModeFlags(desc.GetCullMode()));
303 rasterization_state.setPolygonMode(ToVKPolygonMode(desc.GetPolygonMode()));
304 rasterization_state.setLineWidth(1.0f);
305 rasterization_state.setDepthClampEnable(false);
306 rasterization_state.setRasterizerDiscardEnable(false);
307 pipeline_info.setPRasterizationState(&rasterization_state);
308
309 //----------------------------------------------------------------------------
310 /// Multi-sample State
311 ///
312 vk::PipelineMultisampleStateCreateInfo multisample_state;
313 multisample_state.setRasterizationSamples(
314 ToVKSampleCountFlagBits(desc.GetSampleCount()));
315 pipeline_info.setPMultisampleState(&multisample_state);
316
317 //----------------------------------------------------------------------------
318 /// Primitive Input Assembly State
319 vk::PipelineInputAssemblyStateCreateInfo input_assembly;
320 const auto topology = ToVKPrimitiveTopology(desc.GetPrimitiveType());
321 input_assembly.setTopology(topology);
322 pipeline_info.setPInputAssemblyState(&input_assembly);
323
324 //----------------------------------------------------------------------------
325 /// Color Blend State
326 std::vector<vk::PipelineColorBlendAttachmentState> attachment_blend_state;
327 for (const auto& color_desc : desc.GetColorAttachmentDescriptors()) {
328 // TODO(csg): The blend states are per color attachment. But it isn't clear
329 // how the color attachment indices are specified in the pipeline create
330 // info. But, this should always work for one color attachment.
331 attachment_blend_state.push_back(
332 ToVKPipelineColorBlendAttachmentState(color_desc.second));
333 }
334 vk::PipelineColorBlendStateCreateInfo blend_state;
335 blend_state.setAttachments(attachment_blend_state);
336 pipeline_info.setPColorBlendState(&blend_state);
337
338 std::shared_ptr<DeviceHolder> strong_device = device_holder_.lock();
339 if (!strong_device) {
340 return nullptr;
341 }
342
343 auto render_pass =
344 CreateCompatRenderPassForPipeline(strong_device->GetDevice(), desc);
345 if (render_pass) {
346 pipeline_info.setBasePipelineHandle(VK_NULL_HANDLE);
347 pipeline_info.setSubpass(0);
348 pipeline_info.setRenderPass(render_pass.get());
349 } else {
350 return nullptr;
351 }
352
353 //----------------------------------------------------------------------------
354 /// Vertex Input Setup
355 ///
356 std::vector<vk::VertexInputAttributeDescription> attr_descs;
357 std::vector<vk::VertexInputBindingDescription> buffer_descs;
358
359 const auto& stage_inputs = desc.GetVertexDescriptor()->GetStageInputs();
360 const auto& stage_buffer_layouts =
361 desc.GetVertexDescriptor()->GetStageLayouts();
362 for (const ShaderStageIOSlot& stage_in : stage_inputs) {
363 vk::VertexInputAttributeDescription attr_desc;
364 attr_desc.setBinding(stage_in.binding);
365 attr_desc.setLocation(stage_in.location);
366 attr_desc.setFormat(ToVertexDescriptorFormat(stage_in));
367 attr_desc.setOffset(stage_in.offset);
368 attr_descs.push_back(attr_desc);
369 }
370 for (const ShaderStageBufferLayout& layout : stage_buffer_layouts) {
371 vk::VertexInputBindingDescription binding_description;
372 binding_description.setBinding(layout.binding);
373 binding_description.setInputRate(vk::VertexInputRate::eVertex);
374 binding_description.setStride(layout.stride);
375 buffer_descs.push_back(binding_description);
376 }
377
378 vk::PipelineVertexInputStateCreateInfo vertex_input_state;
379 vertex_input_state.setVertexAttributeDescriptions(attr_descs);
380 vertex_input_state.setVertexBindingDescriptions(buffer_descs);
381
382 pipeline_info.setPVertexInputState(&vertex_input_state);
383
384 //----------------------------------------------------------------------------
385 /// Pipeline Layout a.k.a the descriptor sets and uniforms.
386 ///
387 std::vector<vk::DescriptorSetLayoutBinding> desc_bindings;
388
389 for (auto layout : desc.GetVertexDescriptor()->GetDescriptorSetLayouts()) {
390 auto vk_desc_layout = ToVKDescriptorSetLayoutBinding(layout);
391 desc_bindings.push_back(vk_desc_layout);
392 }
393
394 vk::DescriptorSetLayoutCreateInfo descs_layout_info;
395 descs_layout_info.setBindings(desc_bindings);
396
397 auto [descs_result, descs_layout] =
398 strong_device->GetDevice().createDescriptorSetLayoutUnique(
399 descs_layout_info);
400 if (descs_result != vk::Result::eSuccess) {
401 VALIDATION_LOG << "unable to create uniform descriptors";
402 return nullptr;
403 }
404
405 ContextVK::SetDebugName(strong_device->GetDevice(), descs_layout.get(),
406 "Descriptor Set Layout " + desc.GetLabel());
407
408 //----------------------------------------------------------------------------
409 /// Create the pipeline layout.
410 ///
411 vk::PipelineLayoutCreateInfo pipeline_layout_info;
412 pipeline_layout_info.setSetLayouts(descs_layout.get());
413 auto pipeline_layout = strong_device->GetDevice().createPipelineLayoutUnique(
414 pipeline_layout_info);
415 if (pipeline_layout.result != vk::Result::eSuccess) {
416 VALIDATION_LOG << "Could not create pipeline layout for pipeline "
417 << desc.GetLabel() << ": "
418 << vk::to_string(pipeline_layout.result);
419 return nullptr;
420 }
421 pipeline_info.setLayout(pipeline_layout.value.get());
422
423 //----------------------------------------------------------------------------
424 /// Create the depth stencil state.
425 ///
426 auto depth_stencil_state = ToVKPipelineDepthStencilStateCreateInfo(
427 desc.GetDepthStencilAttachmentDescriptor(),
428 desc.GetFrontStencilAttachmentDescriptor(),
429 desc.GetBackStencilAttachmentDescriptor());
430 pipeline_info.setPDepthStencilState(&depth_stencil_state);
431
432 //----------------------------------------------------------------------------
433 /// Setup the optional pipeline creation feedback struct so we can understand
434 /// how Vulkan created the PSO.
435 ///
436 auto& feedback = chain.get<vk::PipelineCreationFeedbackCreateInfoEXT>();
437 auto pipeline_feedback = EmptyFeedback();
438 std::vector<vk::PipelineCreationFeedbackEXT> stage_feedbacks(
439 pipeline_info.stageCount, EmptyFeedback());
440 feedback.setPPipelineCreationFeedback(&pipeline_feedback);
441 feedback.setPipelineStageCreationFeedbacks(stage_feedbacks);
442
443 //----------------------------------------------------------------------------
444 /// Finally, all done with the setup info. Create the pipeline itself.
445 ///
446 auto pipeline = pso_cache_->CreatePipeline(pipeline_info);
447 if (!pipeline) {
448 VALIDATION_LOG << "Could not create graphics pipeline: " << desc.GetLabel();
449 return nullptr;
450 }
451
452 if (supports_pipeline_creation_feedback) {
453 ReportPipelineCreationFeedback(desc, feedback);
454 }
455
456 ContextVK::SetDebugName(strong_device->GetDevice(), *pipeline_layout.value,
457 "Pipeline Layout " + desc.GetLabel());
458 ContextVK::SetDebugName(strong_device->GetDevice(), *pipeline,
459 "Pipeline " + desc.GetLabel());
460
461 return std::make_unique<PipelineVK>(device_holder_,
462 weak_from_this(), //
463 desc, //
464 std::move(pipeline), //
465 std::move(render_pass), //
466 std::move(pipeline_layout.value), //
467 std::move(descs_layout) //
468 );
469 }
470
471 std::unique_ptr<ComputePipelineVK> PipelineLibraryVK::CreateComputePipeline(
472 const ComputePipelineDescriptor& desc) {
473 TRACE_EVENT0("flutter", __FUNCTION__);
474 vk::ComputePipelineCreateInfo pipeline_info;
475
476 //----------------------------------------------------------------------------
477 /// Shader Stage
478 ///
479 const auto entrypoint = desc.GetStageEntrypoint();
480 if (!entrypoint) {
481 VALIDATION_LOG << "Compute shader is missing an entrypoint.";
482 return nullptr;
483 }
484
485 std::shared_ptr<DeviceHolder> strong_device = device_holder_.lock();
486 if (!strong_device) {
487 return nullptr;
488 }
489 auto device_properties = strong_device->GetPhysicalDevice().getProperties();
490 auto max_wg_size = device_properties.limits.maxComputeWorkGroupSize;
491
492 // Give all compute shaders a specialization constant entry for the
493 // workgroup/threadgroup size.
494 vk::SpecializationMapEntry specialization_map_entry[1];
495
496 uint32_t workgroup_size_x = max_wg_size[0];
497 specialization_map_entry[0].constantID = 0;
498 specialization_map_entry[0].offset = 0;
499 specialization_map_entry[0].size = sizeof(uint32_t);
500
501 vk::SpecializationInfo specialization_info;
502 specialization_info.mapEntryCount = 1;
503 specialization_info.pMapEntries = &specialization_map_entry[0];
504 specialization_info.dataSize = sizeof(uint32_t);
505 specialization_info.pData = &workgroup_size_x;
506
507 vk::PipelineShaderStageCreateInfo info;
508 info.setStage(vk::ShaderStageFlagBits::eCompute);
509 info.setPName("main");
510 info.setModule(ShaderFunctionVK::Cast(entrypoint.get())->GetModule());
511 info.setPSpecializationInfo(&specialization_info);
512 pipeline_info.setStage(info);
513
514 //----------------------------------------------------------------------------
515 /// Pipeline Layout a.k.a the descriptor sets and uniforms.
516 ///
517 std::vector<vk::DescriptorSetLayoutBinding> desc_bindings;
518
519 for (auto layout : desc.GetDescriptorSetLayouts()) {
520 auto vk_desc_layout = ToVKDescriptorSetLayoutBinding(layout);
521 desc_bindings.push_back(vk_desc_layout);
522 }
523
524 vk::DescriptorSetLayoutCreateInfo descs_layout_info;
525 descs_layout_info.setBindings(desc_bindings);
526
527 auto [descs_result, descs_layout] =
528 strong_device->GetDevice().createDescriptorSetLayoutUnique(
529 descs_layout_info);
530 if (descs_result != vk::Result::eSuccess) {
531 VALIDATION_LOG << "unable to create uniform descriptors";
532 return nullptr;
533 }
534
535 ContextVK::SetDebugName(strong_device->GetDevice(), descs_layout.get(),
536 "Descriptor Set Layout " + desc.GetLabel());
537
538 //----------------------------------------------------------------------------
539 /// Create the pipeline layout.
540 ///
541 vk::PipelineLayoutCreateInfo pipeline_layout_info;
542 pipeline_layout_info.setSetLayouts(descs_layout.get());
543 auto pipeline_layout = strong_device->GetDevice().createPipelineLayoutUnique(
544 pipeline_layout_info);
545 if (pipeline_layout.result != vk::Result::eSuccess) {
546 VALIDATION_LOG << "Could not create pipeline layout for pipeline "
547 << desc.GetLabel() << ": "
548 << vk::to_string(pipeline_layout.result);
549 return nullptr;
550 }
551 pipeline_info.setLayout(pipeline_layout.value.get());
552
553 //----------------------------------------------------------------------------
554 /// Finally, all done with the setup info. Create the pipeline itself.
555 ///
556 auto pipeline = pso_cache_->CreatePipeline(pipeline_info);
557 if (!pipeline) {
558 VALIDATION_LOG << "Could not create graphics pipeline: " << desc.GetLabel();
559 return nullptr;
560 }
561
562 ContextVK::SetDebugName(strong_device->GetDevice(), *pipeline_layout.value,
563 "Pipeline Layout " + desc.GetLabel());
564 ContextVK::SetDebugName(strong_device->GetDevice(), *pipeline,
565 "Pipeline " + desc.GetLabel());
566
567 return std::make_unique<ComputePipelineVK>(
568 device_holder_,
569 weak_from_this(), //
570 desc, //
571 std::move(pipeline), //
572 std::move(pipeline_layout.value), //
573 std::move(descs_layout) //
574 );
575 }
576
577 // |PipelineLibrary|
578 PipelineFuture<PipelineDescriptor> PipelineLibraryVK::GetPipeline(
579 PipelineDescriptor descriptor) {
580 Lock lock(pipelines_mutex_);
581 if (auto found = pipelines_.find(descriptor); found != pipelines_.end()) {
582 return found->second;
583 }
584
585 if (!IsValid()) {
586 return {
587 descriptor,
588 RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(nullptr)};
589 }
590
591 auto promise = std::make_shared<
592 std::promise<std::shared_ptr<Pipeline<PipelineDescriptor>>>>();
593 auto pipeline_future =
594 PipelineFuture<PipelineDescriptor>{descriptor, promise->get_future()};
595 pipelines_[descriptor] = pipeline_future;
596
597 auto weak_this = weak_from_this();
598
599 worker_task_runner_->PostTask([descriptor, weak_this, promise]() {
600 auto thiz = weak_this.lock();
601 if (!thiz) {
602 promise->set_value(nullptr);
603 VALIDATION_LOG << "Pipeline library was collected before the pipeline "
604 "could be created.";
605 return;
606 }
607
608 auto pipeline = PipelineLibraryVK::Cast(*thiz).CreatePipeline(descriptor);
609 if (!pipeline) {
610 promise->set_value(nullptr);
611 VALIDATION_LOG << "Could not create pipeline: " << descriptor.GetLabel();
612 return;
613 }
614
615 promise->set_value(std::move(pipeline));
616 });
617
618 return pipeline_future;
619 }
620
621 // |PipelineLibrary|
622 PipelineFuture<ComputePipelineDescriptor> PipelineLibraryVK::GetPipeline(
623 ComputePipelineDescriptor descriptor) {
624 Lock lock(compute_pipelines_mutex_);
625 if (auto found = compute_pipelines_.find(descriptor);
626 found != compute_pipelines_.end()) {
627 return found->second;
628 }
629
630 if (!IsValid()) {
631 return {
632 descriptor,
633 RealizedFuture<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>(
634 nullptr)};
635 }
636
637 auto promise = std::make_shared<
638 std::promise<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>>();
639 auto pipeline_future = PipelineFuture<ComputePipelineDescriptor>{
640 descriptor, promise->get_future()};
641 compute_pipelines_[descriptor] = pipeline_future;
642
643 auto weak_this = weak_from_this();
644
645 worker_task_runner_->PostTask([descriptor, weak_this, promise]() {
646 auto self = weak_this.lock();
647 if (!self) {
648 promise->set_value(nullptr);
649 VALIDATION_LOG << "Pipeline library was collected before the pipeline "
650 "could be created.";
651 return;
652 }
653
654 auto pipeline =
655 PipelineLibraryVK::Cast(*self).CreateComputePipeline(descriptor);
656 if (!pipeline) {
657 promise->set_value(nullptr);
658 VALIDATION_LOG << "Could not create pipeline: " << descriptor.GetLabel();
659 return;
660 }
661
662 promise->set_value(std::move(pipeline));
663 });
664
665 return pipeline_future;
666 }
667
668 // |PipelineLibrary|
669 void PipelineLibraryVK::RemovePipelinesWithEntryPoint(
670 std::shared_ptr<const ShaderFunction> function) {
671 Lock lock(pipelines_mutex_);
672
673 fml::erase_if(pipelines_, [&](auto item) {
674 return item->first.GetEntrypointForStage(function->GetStage())
675 ->IsEqual(*function);
676 });
677 }
678
679 void PipelineLibraryVK::DidAcquireSurfaceFrame() {
680 if (++frames_acquired_ == 50u) {
681 PersistPipelineCacheToDisk();
682 }
683 }
684
685 void PipelineLibraryVK::PersistPipelineCacheToDisk() {
686 worker_task_runner_->PostTask(
687 [weak_cache = decltype(pso_cache_)::weak_type(pso_cache_)]() {
688 auto cache = weak_cache.lock();
689 if (!cache) {
690 return;
691 }
692 cache->PersistCacheToDisk();
693 });
694 }
695
696 } // namespace impeller
impeller::PipelineDescriptor
Definition: pipeline_descriptor.h:30
timing.h
impeller::CreateCompatRenderPassForPipeline
static vk::UniqueRenderPass CreateCompatRenderPassForPipeline(const vk::Device &device, const PipelineDescriptor &desc)
Definition: pipeline_library_vk.cc:78
impeller::ReportPipelineCreationFeedbackToLog
static void ReportPipelineCreationFeedbackToLog(std::stringstream &stream, const vk::PipelineCreationFeedbackEXT &feedback)
Definition: pipeline_library_vk.cc:161
impeller::ToVKPipelineDepthStencilStateCreateInfo
vk::PipelineDepthStencilStateCreateInfo ToVKPipelineDepthStencilStateCreateInfo(std::optional< DepthAttachmentDescriptor > depth, std::optional< StencilAttachmentDescriptor > front, std::optional< StencilAttachmentDescriptor > back)
Definition: formats_vk.cc:9
impeller::SampleCount
SampleCount
Definition: formats.h:269
impeller::ReportPipelineCreationFeedbackToTrace
static void ReportPipelineCreationFeedbackToTrace(const PipelineDescriptor &desc, const vk::PipelineCreationFeedbackCreateInfoEXT &feedback)
Definition: pipeline_library_vk.cc:203
impeller::PipelineDescriptor::GetLabel
const std::string & GetLabel() const
Definition: pipeline_descriptor.cc:230
impeller::ToVKPolygonMode
constexpr vk::PolygonMode ToVKPolygonMode(PolygonMode mode)
Definition: formats_vk.h:348
impeller::ToVKPipelineColorBlendAttachmentState
constexpr vk::PipelineColorBlendAttachmentState ToVKPipelineColorBlendAttachmentState(const ColorAttachmentDescriptor &desc)
Definition: formats_vk.h:99
impeller::PipelineLibraryVK::~PipelineLibraryVK
~PipelineLibraryVK() override
impeller::CreatePlaceholderAttachmentDescription
static vk::AttachmentDescription CreatePlaceholderAttachmentDescription(PixelFormat format, SampleCount sample_count)
Creates an attachment description that does just enough to ensure render pass compatibility with the ...
Definition: pipeline_library_vk.cc:57
impeller::ToVKCullModeFlags
constexpr vk::CullModeFlags ToVKCullModeFlags(CullMode mode)
Definition: formats_vk.h:493
impeller::PipelineDescriptor::GetSampleCount
SampleCount GetSampleCount() const
Definition: pipeline_descriptor.h:42
impeller::StoreAction::kDontCare
@ kDontCare
impeller::EmptyFeedback
static vk::PipelineCreationFeedbackEXT EmptyFeedback()
Definition: pipeline_library_vk.cc:152
impeller::WindingOrder::kClockwise
@ kClockwise
formats_vk.h
impeller::OptionalDeviceExtensionVK::kEXTPipelineCreationFeedback
@ kEXTPipelineCreationFeedback
pipeline_vk.h
validation.h
impeller::PipelineLibraryVK::DidAcquireSurfaceFrame
void DidAcquireSurfaceFrame()
Definition: pipeline_library_vk.cc:679
impeller::WindingOrder
WindingOrder
Definition: tessellator.h:24
impeller::ShaderFunctionVK::GetModule
const vk::ShaderModule & GetModule() const
Definition: shader_function_vk.cc:28
pipeline_library_vk.h
impeller::PipelineDescriptor::HasStencilAttachmentDescriptors
bool HasStencilAttachmentDescriptors() const
Definition: pipeline_descriptor.cc:243
impeller::PipelineDescriptor::GetMaxColorAttacmentBindIndex
size_t GetMaxColorAttacmentBindIndex() const
Definition: pipeline_descriptor.cc:98
impeller::ToVKDescriptorSetLayoutBinding
constexpr vk::DescriptorSetLayoutBinding ToVKDescriptorSetLayoutBinding(const DescriptorSetLayout &layout)
Definition: formats_vk.h:295
impeller::ToVKPrimitiveTopology
constexpr vk::PrimitiveTopology ToVKPrimitiveTopology(PrimitiveType primitive)
Definition: formats_vk.h:358
impeller::ToVertexDescriptorFormat
vk::Format ToVertexDescriptorFormat(const ShaderStageIOSlot &input)
Definition: vertex_descriptor_vk.cc:9
impeller::WindingOrder::kCounterClockwise
@ kCounterClockwise
impeller::ToVKSampleCountFlagBits
constexpr vk::SampleCountFlagBits ToVKSampleCountFlagBits(SampleCount count)
Definition: formats_vk.h:15
impeller::ContextVK::SetDebugName
bool SetDebugName(T handle, std::string_view label) const
Definition: context_vk.h:96
impeller::PipelineDescriptor::GetStencilPixelFormat
PixelFormat GetStencilPixelFormat() const
Definition: pipeline_descriptor.cc:193
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:60
impeller::PipelineDescriptor::GetDepthPixelFormat
PixelFormat GetDepthPixelFormat() const
Definition: pipeline_descriptor.cc:234
promise.h
std
Definition: comparable.h:98
impeller::LoadAction::kDontCare
@ kDontCare
impeller::PipelineDescriptor::GetColorAttachmentDescriptors
const std::map< size_t, ColorAttachmentDescriptor > & GetColorAttachmentDescriptors() const
Definition: pipeline_descriptor.cc:208
impeller::BackendCast< ShaderFunctionVK, ShaderFunction >::Cast
static ShaderFunctionVK & Cast(ShaderFunction &base)
Definition: backend_cast.h:14
impeller::PipelineDescriptor::GetDepthStencilAttachmentDescriptor
std::optional< DepthAttachmentDescriptor > GetDepthStencilAttachmentDescriptor() const
Definition: pipeline_descriptor.cc:203
impeller::kUnusedAttachmentReference
static constexpr vk::AttachmentReference kUnusedAttachmentReference
Definition: formats_vk.h:490
vertex_descriptor_vk.h
impeller::ToVKFrontFace
constexpr vk::FrontFace ToVKFrontFace(WindingOrder order)
Definition: pipeline_library_vk.cc:142
impeller::PixelFormat
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:94
context_vk.h
impeller::ToVKShaderStageFlagBits
constexpr std::optional< vk::ShaderStageFlagBits > ToVKShaderStageFlagBits(ShaderStage stage)
Definition: formats_vk.h:117
impeller::CreateAttachmentDescription
constexpr vk::AttachmentDescription CreateAttachmentDescription(PixelFormat format, SampleCount sample_count, LoadAction load_action, StoreAction store_action, vk::ImageLayout current_layout)
Definition: formats_vk.h:431
shader_function_vk.h
impeller::ReportPipelineCreationFeedback
static void ReportPipelineCreationFeedback(const PipelineDescriptor &desc, const vk::PipelineCreationFeedbackCreateInfoEXT &feedback)
Definition: pipeline_library_vk.cc:226
impeller
Definition: aiks_context.cc:10