7 #include <Foundation/Foundation.h>
8 #include <Metal/Metal.h>
10 #include "flutter/fml/build_config.h"
11 #include "flutter/fml/container.h"
26 using Callback = std::function<void(MTLRenderPipelineDescriptor*)>;
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;
38 vertex_descriptor->GetStageInputs(),
39 vertex_descriptor->GetStageLayouts())) {
40 descriptor.vertexDescriptor =
46 descriptor.colorAttachments[item.first] =
50 descriptor.depthAttachmentPixelFormat =
52 descriptor.stencilAttachmentPixelFormat =
58 descriptor.vertexFunction =
62 if (constants.empty()) {
63 descriptor.fragmentFunction =
67 FML_CHECK(!created_specialized_function);
68 created_specialized_function =
true;
71 constants, [callback, descriptor](id<MTLFunction>
function) {
72 descriptor.fragmentFunction =
function;
79 if (!created_specialized_function) {
86 auto descriptor = [[MTLComputePipelineDescriptor alloc] init];
87 descriptor.label = @(desc.
GetLabel().c_str());
88 descriptor.computeFunction =
95 id<MTLDevice> device) {
101 return [device newDepthStencilStateWithDescriptor:descriptor];
105 bool PipelineLibraryMTL::IsValid()
const {
106 return device_ !=
nullptr;
110 PipelineFuture<PipelineDescriptor> PipelineLibraryMTL::GetPipeline(
111 PipelineDescriptor descriptor,
113 if (
auto found = pipelines_.find(descriptor); found != pipelines_.end()) {
114 return found->second;
120 RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(
nullptr)};
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();
130 auto completion_handler =
131 ^(id<MTLRenderPipelineState> _Nullable render_pipeline_state,
132 NSError* _Nullable error) {
135 << descriptor.GetLabel() <<
" :"
136 << error.localizedDescription.UTF8String;
137 promise->set_value(
nullptr);
141 auto strong_this = weak_this.lock();
143 promise->set_value(
nullptr);
147 auto new_pipeline = std::shared_ptr<PipelineMTL>(
new PipelineMTL(
150 render_pipeline_state,
153 promise->set_value(new_pipeline);
156 descriptor, [device = device_, completion_handler](
157 MTLRenderPipelineDescriptor* descriptor) {
158 [device newRenderPipelineStateWithDescriptor:descriptor
159 completionHandler:completion_handler];
161 return pipeline_future;
164 PipelineFuture<ComputePipelineDescriptor> PipelineLibraryMTL::GetPipeline(
165 ComputePipelineDescriptor descriptor,
167 if (
auto found = compute_pipelines_.find(descriptor);
168 found != compute_pipelines_.end()) {
169 return found->second;
175 RealizedFuture<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>(
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();
186 auto completion_handler =
187 ^(id<MTLComputePipelineState> _Nullable compute_pipeline_state,
188 MTLComputePipelineReflection* _Nullable reflection,
189 NSError* _Nullable error) {
192 << error.localizedDescription.UTF8String;
193 promise->set_value(
nullptr);
197 auto strong_this = weak_this.lock();
199 VALIDATION_LOG <<
"Library was collected before a pending pipeline "
200 "creation could finish.";
201 promise->set_value(
nullptr);
205 auto new_pipeline = std::shared_ptr<ComputePipelineMTL>(
206 new ComputePipelineMTL(weak_this,
208 compute_pipeline_state
210 promise->set_value(new_pipeline);
215 options:MTLPipelineOptionNone
216 completionHandler:completion_handler];
217 return pipeline_future;
221 bool PipelineLibraryMTL::HasPipeline(
const PipelineDescriptor& descriptor) {
222 return pipelines_.find(descriptor) != pipelines_.end();
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);