| 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
5 #include "impeller/renderer/backend/metal/pipeline_library_mtl.h"
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"
13 #include "impeller/renderer/backend/metal/compute_pipeline_mtl.h"
14 #include "impeller/renderer/backend/metal/formats_mtl.h"
15 #include "impeller/renderer/backend/metal/pipeline_mtl.h"
16 #include "impeller/renderer/backend/metal/shader_function_mtl.h"
17 #include "impeller/renderer/backend/metal/vertex_descriptor_mtl.h"
18
19 namespace impeller {
20
21 PipelineLibraryMTL::PipelineLibraryMTL(id<MTLDevice> device)
22 : device_(device) {}
23
24 PipelineLibraryMTL::~PipelineLibraryMTL() = default;
25
26 using Callback = std::function<void(MTLRenderPipelineDescriptor*)>;
27
28 static void GetMTLRenderPipelineDescriptor(const PipelineDescriptor& desc,
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] =
47 ToMTLRenderPipelineColorAttachmentDescriptor(item.second);
48 }
49
50 descriptor.depthAttachmentPixelFormat =
51 ToMTLPixelFormat(desc.GetDepthPixelFormat());
52 descriptor.stencilAttachmentPixelFormat =
53 ToMTLPixelFormat(desc.GetStencilPixelFormat());
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)
70 .GetMTLFunctionSpecialized(
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 =
89 ShaderFunctionMTL::Cast(*desc.GetStageEntrypoint()).GetMTLFunction();
90 return descriptor;
91 }
92
93 // TODO(csg): Make PipelineDescriptor a struct and move this to formats_mtl.
94 static id<MTLDepthStencilState> CreateDepthStencilDescriptor(
95 const PipelineDescriptor& desc,
96 id<MTLDevice> device) {
97 auto descriptor = ToMTLDepthStencilDescriptor(
98 desc.GetDepthStencilAttachmentDescriptor(), //
99 desc.GetFrontStencilAttachmentDescriptor(), //
100 desc.GetBackStencilAttachmentDescriptor() //
101 );
102 return [device newDepthStencilStateWithDescriptor:descriptor];
103 }
104
105 // |PipelineLibrary|
106 bool PipelineLibraryMTL::IsValid() const {
107 return device_ != nullptr;
108 }
109
110 // |PipelineLibrary|
111 PipelineFuture<PipelineDescriptor> PipelineLibraryMTL::GetPipeline(
112 PipelineDescriptor descriptor) {
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 };
155 GetMTLRenderPipelineDescriptor(
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 if (auto found = compute_pipelines_.find(descriptor);
167 found != compute_pipelines_.end()) {
168 return found->second;
169 }
170
171 if (!IsValid()) {
172 return {
173 descriptor,
174 RealizedFuture<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>(
175 nullptr)};
176 }
177
178 auto promise = std::make_shared<
179 std::promise<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>>();
180 auto pipeline_future = PipelineFuture<ComputePipelineDescriptor>{
181 descriptor, promise->get_future()};
182 compute_pipelines_[descriptor] = pipeline_future;
183 auto weak_this = weak_from_this();
184
185 auto completion_handler =
186 ^(id<MTLComputePipelineState> _Nullable compute_pipeline_state,
187 MTLComputePipelineReflection* _Nullable reflection,
188 NSError* _Nullable error) {
189 if (error != nil) {
190 VALIDATION_LOG << "Could not create compute pipeline: "
191 << error.localizedDescription.UTF8String;
192 promise->set_value(nullptr);
193 return;
194 }
195
196 auto strong_this = weak_this.lock();
197 if (!strong_this) {
198 VALIDATION_LOG << "Library was collected before a pending pipeline "
199 "creation could finish.";
200 promise->set_value(nullptr);
201 return;
202 }
203
204 auto new_pipeline = std::shared_ptr<ComputePipelineMTL>(
205 new ComputePipelineMTL(weak_this,
206 descriptor, //
207 compute_pipeline_state //
208 ));
209 promise->set_value(new_pipeline);
210 };
211 [device_
212 newComputePipelineStateWithDescriptor:GetMTLComputePipelineDescriptor(
213 descriptor)
214 options:MTLPipelineOptionNone
215 completionHandler:completion_handler];
216 return pipeline_future;
217 }
218
219 // |PipelineLibrary|
220 void PipelineLibraryMTL::RemovePipelinesWithEntryPoint(
221 std::shared_ptr<const ShaderFunction> function) {
222 fml::erase_if(pipelines_, [&](auto item) {
223 return item->first.GetEntrypointForStage(function->GetStage())
224 ->IsEqual(*function);
225 });
226 }
227
228 } // namespace impeller
impeller::PipelineDescriptor
Definition: pipeline_descriptor.h:29
impeller::ComputePipelineDescriptor
Definition: compute_pipeline_descriptor.h:30
impeller::PipelineDescriptor::GetSpecializationConstants
const std::vector< Scalar > & GetSpecializationConstants() const
Definition: pipeline_descriptor.cc:291
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:245
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:236
compute_pipeline_mtl.h
formats_mtl.h
impeller::PipelineDescriptor::GetSampleCount
SampleCount GetSampleCount() const
Definition: pipeline_descriptor.h:41
impeller::PipelineDescriptor::GetVertexDescriptor
const std::shared_ptr< VertexDescriptor > & GetVertexDescriptor() const
Definition: pipeline_descriptor.cc:219
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:199
impeller::Callback
std::function< void(MTLRenderPipelineDescriptor *)> Callback
Definition: pipeline_library_mtl.mm:26
impeller::ToMTLPixelFormat
constexpr MTLPixelFormat ToMTLPixelFormat(PixelFormat format)
Definition: formats_mtl.h:77
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:67
impeller::PipelineDescriptor::GetFrontStencilAttachmentDescriptor
std::optional< StencilAttachmentDescriptor > GetFrontStencilAttachmentDescriptor() const
Definition: pipeline_descriptor.cc:204
impeller::PipelineLibraryMTL::PipelineLibraryMTL
PipelineLibraryMTL()
impeller::PipelineDescriptor::GetDepthPixelFormat
PixelFormat GetDepthPixelFormat() const
Definition: pipeline_descriptor.cc:240
impeller::CreateDepthStencilDescriptor
static id< MTLDepthStencilState > CreateDepthStencilDescriptor(const PipelineDescriptor &desc, id< MTLDevice > device)
Definition: pipeline_library_mtl.mm:94
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:214
impeller::BackendCast< ShaderFunctionMTL, ShaderFunction >::Cast
static ShaderFunctionMTL & Cast(ShaderFunction &base)
Definition: backend_cast.h:15
impeller::PipelineDescriptor::GetDepthStencilAttachmentDescriptor
std::optional< DepthAttachmentDescriptor > GetDepthStencilAttachmentDescriptor() const
Definition: pipeline_descriptor.cc:209
impeller::VertexDescriptorMTL
Definition: vertex_descriptor_mtl.h:18
impeller::PipelineDescriptor::GetStageEntrypoints
const std::map< ShaderStage, std::shared_ptr< const ShaderFunction > > & GetStageEntrypoints() const
Definition: pipeline_descriptor.cc:224
impeller::PipelineLibraryMTL::~PipelineLibraryMTL
~PipelineLibraryMTL() override
impeller
Definition: aiks_context.cc:10