Flutter Engine
The Flutter Engine
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"
18
19namespace impeller {
20
22 : device_(device) {}
23
24PipelineLibraryMTL::~PipelineLibraryMTL() = default;
25
26using 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 =
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
84static MTLComputePipelineDescriptor* GetMTLComputePipelineDescriptor(
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.
94static id<MTLDepthStencilState> CreateDepthStencilDescriptor(
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|
106bool PipelineLibraryMTL::IsValid() const {
107 return device_ != nullptr;
108}
109
110// |PipelineLibrary|
111PipelineFuture<PipelineDescriptor> PipelineLibraryMTL::GetPipeline(
112 PipelineDescriptor descriptor,
113 bool async) {
114 if (auto found = pipelines_.find(descriptor); found != pipelines_.end()) {
115 return found->second;
116 }
117
118 if (!IsValid()) {
119 return {
120 descriptor,
121 RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(nullptr)};
122 }
123
124 auto promise = std::make_shared<
125 std::promise<std::shared_ptr<Pipeline<PipelineDescriptor>>>>();
126 auto pipeline_future =
127 PipelineFuture<PipelineDescriptor>{descriptor, promise->get_future()};
128 pipelines_[descriptor] = pipeline_future;
129 auto weak_this = weak_from_this();
130
131 auto completion_handler =
132 ^(id<MTLRenderPipelineState> _Nullable render_pipeline_state,
133 NSError* _Nullable error) {
134 if (error != nil) {
135 VALIDATION_LOG << "Could not create render pipeline for "
136 << descriptor.GetLabel() << " :"
137 << error.localizedDescription.UTF8String;
138 promise->set_value(nullptr);
139 return;
140 }
141
142 auto strong_this = weak_this.lock();
143 if (!strong_this) {
144 promise->set_value(nullptr);
145 return;
146 }
147
148 auto new_pipeline = std::shared_ptr<PipelineMTL>(new PipelineMTL(
149 weak_this,
150 descriptor, //
151 render_pipeline_state, //
152 CreateDepthStencilDescriptor(descriptor, device_) //
153 ));
154 promise->set_value(new_pipeline);
155 };
157 descriptor, [device = device_, completion_handler](
158 MTLRenderPipelineDescriptor* descriptor) {
159 [device newRenderPipelineStateWithDescriptor:descriptor
160 completionHandler:completion_handler];
161 });
162 return pipeline_future;
163}
164
165PipelineFuture<ComputePipelineDescriptor> PipelineLibraryMTL::GetPipeline(
166 ComputePipelineDescriptor descriptor,
167 bool async) {
168 if (auto found = compute_pipelines_.find(descriptor);
169 found != compute_pipelines_.end()) {
170 return found->second;
171 }
172
173 if (!IsValid()) {
174 return {
175 descriptor,
176 RealizedFuture<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>(
177 nullptr)};
178 }
179
180 auto promise = std::make_shared<
181 std::promise<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>>();
182 auto pipeline_future = PipelineFuture<ComputePipelineDescriptor>{
183 descriptor, promise->get_future()};
184 compute_pipelines_[descriptor] = pipeline_future;
185 auto weak_this = weak_from_this();
186
187 auto completion_handler =
188 ^(id<MTLComputePipelineState> _Nullable compute_pipeline_state,
189 MTLComputePipelineReflection* _Nullable reflection,
190 NSError* _Nullable error) {
191 if (error != nil) {
192 VALIDATION_LOG << "Could not create compute pipeline: "
193 << error.localizedDescription.UTF8String;
194 promise->set_value(nullptr);
195 return;
196 }
197
198 auto strong_this = weak_this.lock();
199 if (!strong_this) {
200 VALIDATION_LOG << "Library was collected before a pending pipeline "
201 "creation could finish.";
202 promise->set_value(nullptr);
203 return;
204 }
205
206 auto new_pipeline = std::shared_ptr<ComputePipelineMTL>(
207 new ComputePipelineMTL(weak_this,
208 descriptor, //
209 compute_pipeline_state //
210 ));
211 promise->set_value(new_pipeline);
212 };
213 [device_
214 newComputePipelineStateWithDescriptor:GetMTLComputePipelineDescriptor(
215 descriptor)
216 options:MTLPipelineOptionNone
217 completionHandler:completion_handler];
218 return pipeline_future;
219}
220
221// |PipelineLibrary|
222void PipelineLibraryMTL::RemovePipelinesWithEntryPoint(
223 std::shared_ptr<const ShaderFunction> function) {
224 fml::erase_if(pipelines_, [&](auto item) {
225 return item->first.GetEntrypointForStage(function->GetStage())
226 ->IsEqual(*function);
227 });
228}
229
230} // namespace impeller
const char * options
bool SetStageInputsAndLayout(const std::vector< ShaderStageIOSlot > &inputs, const std::vector< ShaderStageBufferLayout > &layouts)
MTLVertexDescriptor * GetMTLVertexDescriptor() const
VkDevice device
Definition: main.cc:53
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
const uint8_t uint32_t uint32_t GError ** error
#define FML_CHECK(condition)
Definition: logging.h:85
Dart_NativeFunction function
Definition: fuchsia.cc:51
static bool init()
void erase_if(Collection &container, std::function< bool(typename Collection::iterator)> predicate)
Definition: container.h:16
static void GetMTLRenderPipelineDescriptor(const PipelineDescriptor &desc, const Callback &callback)
std::function< void(MTLRenderPipelineDescriptor *)> Callback
static id< MTLDepthStencilState > CreateDepthStencilDescriptor(const PipelineDescriptor &desc, id< MTLDevice > device)
MTLDepthStencilDescriptor * ToMTLDepthStencilDescriptor(std::optional< DepthAttachmentDescriptor > depth, std::optional< StencilAttachmentDescriptor > front, std::optional< StencilAttachmentDescriptor > back)
Definition: formats_mtl.mm:54
constexpr MTLPixelFormat ToMTLPixelFormat(PixelFormat format)
Definition: formats_mtl.h:76
static MTLComputePipelineDescriptor * GetMTLComputePipelineDescriptor(const ComputePipelineDescriptor &desc)
MTLRenderPipelineColorAttachmentDescriptor * ToMTLRenderPipelineColorAttachmentDescriptor(ColorAttachmentDescriptor descriptor)
Definition: formats_mtl.mm:15
#define VALIDATION_LOG
Definition: validation.h:73