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)