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 
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"
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 
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, //
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,
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) {
166  return vk::FrontFace::eClockwise;
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 
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 
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() << "' ";
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 << ": ";
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 
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 
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) {
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(
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 
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