Flutter Impeller
pipeline_library_mtl.mm
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 <Foundation/Foundation.h>
8 #include <Metal/Metal.h>
9 
10 #include "flutter/fml/build_config.h"
11 #include "flutter/fml/container.h"
12 #include "impeller/base/promise.h"
18 
19 namespace impeller {
20 
21 PipelineLibraryMTL::PipelineLibraryMTL(id<MTLDevice> device)
22  : device_(device) {}
23 
25 
26 using Callback = std::function<void(MTLRenderPipelineDescriptor*)>;
27 
29  const Callback& callback) {
30  auto descriptor = [[MTLRenderPipelineDescriptor alloc] init];
31  descriptor.label = @(desc.GetLabel().c_str());
32  descriptor.rasterSampleCount = static_cast<NSUInteger>(desc.GetSampleCount());
33  bool created_specialized_function = false;
34 
35  if (const auto& vertex_descriptor = desc.GetVertexDescriptor()) {
36  VertexDescriptorMTL vertex_descriptor_mtl;
37  if (vertex_descriptor_mtl.SetStageInputsAndLayout(
38  vertex_descriptor->GetStageInputs(),
39  vertex_descriptor->GetStageLayouts())) {
40  descriptor.vertexDescriptor =
41  vertex_descriptor_mtl.GetMTLVertexDescriptor();
42  }
43  }
44 
45  for (const auto& item : desc.GetColorAttachmentDescriptors()) {
46  descriptor.colorAttachments[item.first] =
48  }
49 
50  descriptor.depthAttachmentPixelFormat =
52  descriptor.stencilAttachmentPixelFormat =
54 
55  const auto& constants = desc.GetSpecializationConstants();
56  for (const auto& entry : desc.GetStageEntrypoints()) {
57  if (entry.first == ShaderStage::kVertex) {
58  descriptor.vertexFunction =
59  ShaderFunctionMTL::Cast(*entry.second).GetMTLFunction();
60  }
61  if (entry.first == ShaderStage::kFragment) {
62  if (constants.empty()) {
63  descriptor.fragmentFunction =
64  ShaderFunctionMTL::Cast(*entry.second).GetMTLFunction();
65  } else {
66  // This code only expects a single specialized function per pipeline.
67  FML_CHECK(!created_specialized_function);
68  created_specialized_function = true;
69  ShaderFunctionMTL::Cast(*entry.second)
71  constants, [callback, descriptor](id<MTLFunction> function) {
72  descriptor.fragmentFunction = function;
73  callback(descriptor);
74  });
75  }
76  }
77  }
78 
79  if (!created_specialized_function) {
80  callback(descriptor);
81  }
82 }
83 
84 static MTLComputePipelineDescriptor* GetMTLComputePipelineDescriptor(
85  const ComputePipelineDescriptor& desc) {
86  auto descriptor = [[MTLComputePipelineDescriptor alloc] init];
87  descriptor.label = @(desc.GetLabel().c_str());
88  descriptor.computeFunction =
90  return descriptor;
91 }
92 
93 static id<MTLDepthStencilState> CreateDepthStencilDescriptor(
94  const PipelineDescriptor& desc,
95  id<MTLDevice> device) {
96  auto descriptor = ToMTLDepthStencilDescriptor(
100  );
101  return [device newDepthStencilStateWithDescriptor:descriptor];
102 }
103 
104 // |PipelineLibrary|
105 bool PipelineLibraryMTL::IsValid() const {
106  return device_ != nullptr;
107 }
108 
109 // |PipelineLibrary|
110 PipelineFuture<PipelineDescriptor> PipelineLibraryMTL::GetPipeline(
111  PipelineDescriptor descriptor,
112  bool async) {
113  if (auto found = pipelines_.find(descriptor); found != pipelines_.end()) {
114  return found->second;
115  }
116 
117  if (!IsValid()) {
118  return {
119  descriptor,
120  RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(nullptr)};
121  }
122 
123  auto promise = std::make_shared<
124  std::promise<std::shared_ptr<Pipeline<PipelineDescriptor>>>>();
125  auto pipeline_future =
126  PipelineFuture<PipelineDescriptor>{descriptor, promise->get_future()};
127  pipelines_[descriptor] = pipeline_future;
128  auto weak_this = weak_from_this();
129 
130  auto completion_handler =
131  ^(id<MTLRenderPipelineState> _Nullable render_pipeline_state,
132  NSError* _Nullable error) {
133  if (error != nil) {
134  VALIDATION_LOG << "Could not create render pipeline for "
135  << descriptor.GetLabel() << " :"
136  << error.localizedDescription.UTF8String;
137  promise->set_value(nullptr);
138  return;
139  }
140 
141  auto strong_this = weak_this.lock();
142  if (!strong_this) {
143  promise->set_value(nullptr);
144  return;
145  }
146 
147  auto new_pipeline = std::shared_ptr<PipelineMTL>(new PipelineMTL(
148  weak_this,
149  descriptor, //
150  render_pipeline_state, //
151  CreateDepthStencilDescriptor(descriptor, device_) //
152  ));
153  promise->set_value(new_pipeline);
154  };
156  descriptor, [device = device_, completion_handler](
157  MTLRenderPipelineDescriptor* descriptor) {
158  [device newRenderPipelineStateWithDescriptor:descriptor
159  completionHandler:completion_handler];
160  });
161  return pipeline_future;
162 }
163 
164 PipelineFuture<ComputePipelineDescriptor> PipelineLibraryMTL::GetPipeline(
165  ComputePipelineDescriptor descriptor,
166  bool async) {
167  if (auto found = compute_pipelines_.find(descriptor);
168  found != compute_pipelines_.end()) {
169  return found->second;
170  }
171 
172  if (!IsValid()) {
173  return {
174  descriptor,
175  RealizedFuture<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>(
176  nullptr)};
177  }
178 
179  auto promise = std::make_shared<
180  std::promise<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>>();
181  auto pipeline_future = PipelineFuture<ComputePipelineDescriptor>{
182  descriptor, promise->get_future()};
183  compute_pipelines_[descriptor] = pipeline_future;
184  auto weak_this = weak_from_this();
185 
186  auto completion_handler =
187  ^(id<MTLComputePipelineState> _Nullable compute_pipeline_state,
188  MTLComputePipelineReflection* _Nullable reflection,
189  NSError* _Nullable error) {
190  if (error != nil) {
191  VALIDATION_LOG << "Could not create compute pipeline: "
192  << error.localizedDescription.UTF8String;
193  promise->set_value(nullptr);
194  return;
195  }
196 
197  auto strong_this = weak_this.lock();
198  if (!strong_this) {
199  VALIDATION_LOG << "Library was collected before a pending pipeline "
200  "creation could finish.";
201  promise->set_value(nullptr);
202  return;
203  }
204 
205  auto new_pipeline = std::shared_ptr<ComputePipelineMTL>(
206  new ComputePipelineMTL(weak_this,
207  descriptor, //
208  compute_pipeline_state //
209  ));
210  promise->set_value(new_pipeline);
211  };
212  [device_
213  newComputePipelineStateWithDescriptor:GetMTLComputePipelineDescriptor(
214  descriptor)
215  options:MTLPipelineOptionNone
216  completionHandler:completion_handler];
217  return pipeline_future;
218 }
219 
220 // |PipelineLibrary|
221 bool PipelineLibraryMTL::HasPipeline(const PipelineDescriptor& descriptor) {
222  return pipelines_.find(descriptor) != pipelines_.end();
223 }
224 
225 // |PipelineLibrary|
226 void PipelineLibraryMTL::RemovePipelinesWithEntryPoint(
227  std::shared_ptr<const ShaderFunction> function) {
228  fml::erase_if(pipelines_, [&](auto item) {
229  return item->first.GetEntrypointForStage(function->GetStage())
230  ->IsEqual(*function);
231  });
232 }
233 
234 } // namespace impeller
impeller::PipelineDescriptor
Definition: pipeline_descriptor.h:24
impeller::ComputePipelineDescriptor
Definition: compute_pipeline_descriptor.h:20
impeller::PipelineDescriptor::GetSpecializationConstants
const std::vector< Scalar > & GetSpecializationConstants() const
Definition: pipeline_descriptor.cc:289
impeller::ComputePipelineDescriptor::GetStageEntrypoint
std::shared_ptr< const ShaderFunction > GetStageEntrypoint() const
Definition: compute_pipeline_descriptor.cc:58
impeller::PipelineDescriptor::GetBackStencilAttachmentDescriptor
std::optional< StencilAttachmentDescriptor > GetBackStencilAttachmentDescriptor() const
Definition: pipeline_descriptor.cc:243
impeller::GetMTLComputePipelineDescriptor
static MTLComputePipelineDescriptor * GetMTLComputePipelineDescriptor(const ComputePipelineDescriptor &desc)
Definition: pipeline_library_mtl.mm:84
impeller::PipelineDescriptor::GetLabel
const std::string & GetLabel() const
Definition: pipeline_descriptor.cc:234
compute_pipeline_mtl.h
formats_mtl.h
impeller::PipelineDescriptor::GetSampleCount
SampleCount GetSampleCount() const
Definition: pipeline_descriptor.h:36
impeller::PipelineDescriptor::GetVertexDescriptor
const std::shared_ptr< VertexDescriptor > & GetVertexDescriptor() const
Definition: pipeline_descriptor.cc:217
impeller::GetMTLRenderPipelineDescriptor
static void GetMTLRenderPipelineDescriptor(const PipelineDescriptor &desc, const Callback &callback)
Definition: pipeline_library_mtl.mm:28
pipeline_mtl.h
impeller::VertexDescriptorMTL::SetStageInputsAndLayout
bool SetStageInputsAndLayout(const std::vector< ShaderStageIOSlot > &inputs, const std::vector< ShaderStageBufferLayout > &layouts)
Definition: vertex_descriptor_mtl.mm:172
impeller::ToMTLDepthStencilDescriptor
MTLDepthStencilDescriptor * ToMTLDepthStencilDescriptor(std::optional< DepthAttachmentDescriptor > depth, std::optional< StencilAttachmentDescriptor > front, std::optional< StencilAttachmentDescriptor > back)
Definition: formats_mtl.mm:54
impeller::ShaderFunctionMTL::GetMTLFunctionSpecialized
void GetMTLFunctionSpecialized(const std::vector< Scalar > &constants, const CompileCallback &callback) const
Definition: shader_function_mtl.mm:20
shader_function_mtl.h
impeller::ToMTLRenderPipelineColorAttachmentDescriptor
MTLRenderPipelineColorAttachmentDescriptor * ToMTLRenderPipelineColorAttachmentDescriptor(ColorAttachmentDescriptor descriptor)
Definition: formats_mtl.mm:15
impeller::ShaderFunctionMTL::GetMTLFunction
id< MTLFunction > GetMTLFunction() const
Definition: shader_function_mtl.mm:42
impeller::ShaderStage::kFragment
@ kFragment
impeller::PipelineDescriptor::GetStencilPixelFormat
PixelFormat GetStencilPixelFormat() const
Definition: pipeline_descriptor.cc:197
impeller::Callback
std::function< void(MTLRenderPipelineDescriptor *)> Callback
Definition: pipeline_library_mtl.mm:26
impeller::ToMTLPixelFormat
constexpr MTLPixelFormat ToMTLPixelFormat(PixelFormat format)
Definition: formats_mtl.h:76
impeller::ComputePipelineDescriptor::GetLabel
const std::string & GetLabel() const
Definition: compute_pipeline_descriptor.cc:62
impeller::VertexDescriptorMTL::GetMTLVertexDescriptor
MTLVertexDescriptor * GetMTLVertexDescriptor() const
Definition: vertex_descriptor_mtl.mm:206
pipeline_library_mtl.h
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:91
impeller::PipelineDescriptor::GetFrontStencilAttachmentDescriptor
std::optional< StencilAttachmentDescriptor > GetFrontStencilAttachmentDescriptor() const
Definition: pipeline_descriptor.cc:202
impeller::PipelineLibraryMTL::PipelineLibraryMTL
PipelineLibraryMTL()
impeller::PipelineDescriptor::GetDepthPixelFormat
PixelFormat GetDepthPixelFormat() const
Definition: pipeline_descriptor.cc:238
impeller::CreateDepthStencilDescriptor
static id< MTLDepthStencilState > CreateDepthStencilDescriptor(const PipelineDescriptor &desc, id< MTLDevice > device)
Definition: pipeline_library_mtl.mm:93
promise.h
impeller::ShaderStage::kVertex
@ kVertex
vertex_descriptor_mtl.h
impeller::PipelineDescriptor::GetColorAttachmentDescriptors
const std::map< size_t, ColorAttachmentDescriptor > & GetColorAttachmentDescriptors() const
Definition: pipeline_descriptor.cc:212
impeller::BackendCast< ShaderFunctionMTL, ShaderFunction >::Cast
static ShaderFunctionMTL & Cast(ShaderFunction &base)
Definition: backend_cast.h:13
impeller::PipelineDescriptor::GetDepthStencilAttachmentDescriptor
std::optional< DepthAttachmentDescriptor > GetDepthStencilAttachmentDescriptor() const
Definition: pipeline_descriptor.cc:207
impeller::VertexDescriptorMTL
Definition: vertex_descriptor_mtl.h:17
impeller::PipelineDescriptor::GetStageEntrypoints
const std::map< ShaderStage, std::shared_ptr< const ShaderFunction > > & GetStageEntrypoints() const
Definition: pipeline_descriptor.cc:222
impeller::PipelineLibraryMTL::~PipelineLibraryMTL
~PipelineLibraryMTL() override
impeller
Definition: allocation.cc:12