7 #include <Foundation/Foundation.h>
8 #include <Metal/Metal.h>
10 #include "flutter/fml/build_config.h"
11 #include "flutter/fml/container.h"
19 #if !__has_feature(objc_arc)
20 #error ARC must be enabled !
28 PipelineLibraryMTL::~PipelineLibraryMTL() =
default;
30 using Callback = std::function<void(MTLRenderPipelineDescriptor*)>;
34 auto descriptor = [[MTLRenderPipelineDescriptor alloc] init];
35 descriptor.label = @(desc.
GetLabel().data());
36 descriptor.rasterSampleCount =
static_cast<NSUInteger
>(desc.
GetSampleCount());
37 bool created_specialized_function =
false;
42 vertex_descriptor->GetStageInputs(),
43 vertex_descriptor->GetStageLayouts())) {
44 descriptor.vertexDescriptor =
50 descriptor.colorAttachments[item.first] =
54 descriptor.depthAttachmentPixelFormat =
56 descriptor.stencilAttachmentPixelFormat =
61 if (entry.first == ShaderStage::kVertex) {
62 descriptor.vertexFunction =
63 ShaderFunctionMTL::Cast(*entry.second).GetMTLFunction();
65 if (entry.first == ShaderStage::kFragment) {
66 if (constants.empty()) {
67 descriptor.fragmentFunction =
68 ShaderFunctionMTL::Cast(*entry.second).GetMTLFunction();
71 FML_CHECK(!created_specialized_function);
72 created_specialized_function =
true;
73 ShaderFunctionMTL::Cast(*entry.second)
74 .GetMTLFunctionSpecialized(
75 constants, [callback, descriptor](id<MTLFunction>
function) {
76 descriptor.fragmentFunction =
function;
83 if (!created_specialized_function) {
90 auto descriptor = [[MTLComputePipelineDescriptor alloc] init];
91 descriptor.label = @(desc.
GetLabel().c_str());
92 descriptor.computeFunction =
99 id<MTLDevice> device) {
105 return [device newDepthStencilStateWithDescriptor:descriptor];
109 bool PipelineLibraryMTL::IsValid()
const {
110 return device_ !=
nullptr;
114 PipelineFuture<PipelineDescriptor> PipelineLibraryMTL::GetPipeline(
115 PipelineDescriptor descriptor,
118 return found->second;
124 RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(
nullptr)};
127 auto promise = std::make_shared<
128 std::promise<std::shared_ptr<Pipeline<PipelineDescriptor>>>>();
129 auto pipeline_future =
130 PipelineFuture<PipelineDescriptor>{descriptor, promise->get_future()};
132 auto weak_this = weak_from_this();
134 auto get_pipeline_descriptor =
136 device = device_](MTLNewRenderPipelineStateCompletionHandler handler) {
139 [device, handler](MTLRenderPipelineDescriptor* descriptor) {
140 [device newRenderPipelineStateWithDescriptor:descriptor
141 completionHandler:handler];
146 std::optional<std::string> thread_name =
150 [NSThread isMainThread] ?
"main"
151 : [[[NSThread currentThread] name] UTF8String];
153 auto completion_handler = ^(
154 id<MTLRenderPipelineState> _Nullable render_pipeline_state,
155 NSError* _Nullable error) {
158 << descriptor.GetLabel() <<
" :"
159 << error.localizedDescription.UTF8String <<
" (thread: "
160 << (thread_name.has_value() ? *thread_name :
"unknown")
162 promise->set_value(
nullptr);
166 auto strong_this = weak_this.lock();
168 promise->set_value(
nullptr);
172 auto new_pipeline = std::shared_ptr<PipelineMTL>(
new PipelineMTL(
175 render_pipeline_state,
178 promise->set_value(new_pipeline);
181 ^(id<MTLRenderPipelineState> _Nullable render_pipeline_state,
182 NSError* _Nullable error) {
184 FML_LOG(INFO) <<
"pipeline creation retry";
188 dispatch_async(dispatch_get_main_queue(), ^{
189 get_pipeline_descriptor(completion_handler);
192 completion_handler(render_pipeline_state, error);
195 #if defined(FML_ARCH_CPU_X86_64)
196 get_pipeline_descriptor(retry_handler);
198 get_pipeline_descriptor(completion_handler);
201 return pipeline_future;
204 PipelineFuture<ComputePipelineDescriptor> PipelineLibraryMTL::GetPipeline(
205 ComputePipelineDescriptor descriptor,
207 if (
auto found = compute_pipelines_.find(descriptor);
208 found != compute_pipelines_.end()) {
209 return found->second;
215 RealizedFuture<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>(
219 auto promise = std::make_shared<
220 std::promise<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>>();
221 auto pipeline_future = PipelineFuture<ComputePipelineDescriptor>{
222 descriptor, promise->get_future()};
223 compute_pipelines_[descriptor] = pipeline_future;
224 auto weak_this = weak_from_this();
226 auto completion_handler =
227 ^(id<MTLComputePipelineState> _Nullable compute_pipeline_state,
228 MTLComputePipelineReflection* _Nullable reflection,
229 NSError* _Nullable error) {
232 << error.localizedDescription.UTF8String;
233 promise->set_value(
nullptr);
237 auto strong_this = weak_this.lock();
239 VALIDATION_LOG <<
"Library was collected before a pending pipeline "
240 "creation could finish.";
241 promise->set_value(
nullptr);
245 auto new_pipeline = std::shared_ptr<ComputePipelineMTL>(
246 new ComputePipelineMTL(weak_this,
248 compute_pipeline_state
250 promise->set_value(new_pipeline);
255 options:MTLPipelineOptionNone
256 completionHandler:completion_handler];
257 return pipeline_future;
261 bool PipelineLibraryMTL::HasPipeline(
const PipelineDescriptor& descriptor) {
266 void PipelineLibraryMTL::RemovePipelinesWithEntryPoint(
267 std::shared_ptr<const ShaderFunction>
function) {
269 return item->first.GetEntrypointForStage(function->GetStage())
270 ->IsEqual(*
function);
std::shared_ptr< const ShaderFunction > GetStageEntrypoint() const
const std::string & GetLabel() const
std::string_view GetLabel() const
PixelFormat GetDepthPixelFormat() const
std::optional< DepthAttachmentDescriptor > GetDepthStencilAttachmentDescriptor() const
const std::map< ShaderStage, std::shared_ptr< const ShaderFunction > > & GetStageEntrypoints() const
PixelFormat GetStencilPixelFormat() const
const std::vector< Scalar > & GetSpecializationConstants() const
const std::map< size_t, ColorAttachmentDescriptor > & GetColorAttachmentDescriptors() const
std::optional< StencilAttachmentDescriptor > GetBackStencilAttachmentDescriptor() const
const std::shared_ptr< VertexDescriptor > & GetVertexDescriptor() const
std::optional< StencilAttachmentDescriptor > GetFrontStencilAttachmentDescriptor() const
SampleCount GetSampleCount() const
bool SetStageInputsAndLayout(const std::vector< ShaderStageIOSlot > &inputs, const std::vector< ShaderStageBufferLayout > &layouts)
MTLVertexDescriptor * GetMTLVertexDescriptor() const
std::vector< std::pair< uint64_t, std::unique_ptr< GenericRenderPipelineHandle > > > pipelines_
static MTLComputePipelineDescriptor * GetMTLComputePipelineDescriptor(const ComputePipelineDescriptor &desc)
static void GetMTLRenderPipelineDescriptor(const PipelineDescriptor &desc, const Callback &callback)
std::function< void(MTLRenderPipelineDescriptor *)> Callback
MTLDepthStencilDescriptor * ToMTLDepthStencilDescriptor(std::optional< DepthAttachmentDescriptor > depth, std::optional< StencilAttachmentDescriptor > front, std::optional< StencilAttachmentDescriptor > back)
constexpr MTLPixelFormat ToMTLPixelFormat(PixelFormat format)
MTLRenderPipelineColorAttachmentDescriptor * ToMTLRenderPipelineColorAttachmentDescriptor(ColorAttachmentDescriptor descriptor)
static id< MTLDepthStencilState > CreateDepthStencilDescriptor(const PipelineDescriptor &desc, id< MTLDevice > device)