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