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