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