| // Copyright 2013 The Flutter Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #import "flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalSkia.h" | 
 |  | 
 | #include "flutter/common/graphics/persistent_cache.h" | 
 | #include "flutter/fml/logging.h" | 
 | #include "flutter/shell/common/context_options.h" | 
 | #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" | 
 | #include "third_party/skia/include/gpu/GrDirectContext.h" | 
 | #include "third_party/skia/include/gpu/ganesh/mtl/GrMtlBackendContext.h" | 
 | #include "third_party/skia/include/gpu/ganesh/mtl/GrMtlDirectContext.h" | 
 |  | 
 | FLUTTER_ASSERT_ARC | 
 |  | 
 | @implementation FlutterDarwinContextMetalSkia | 
 |  | 
 | - (instancetype)initWithDefaultMTLDevice { | 
 |   id<MTLDevice> device = MTLCreateSystemDefaultDevice(); | 
 |   return [self initWithMTLDevice:device commandQueue:[device newCommandQueue]]; | 
 | } | 
 |  | 
 | - (instancetype)initWithMTLDevice:(id<MTLDevice>)device | 
 |                      commandQueue:(id<MTLCommandQueue>)commandQueue { | 
 |   self = [super init]; | 
 |   if (self != nil) { | 
 |     _device = device; | 
 |  | 
 |     if (!_device) { | 
 |       FML_DLOG(ERROR) << "Could not acquire Metal device."; | 
 |       return nil; | 
 |     } | 
 |  | 
 |     _commandQueue = commandQueue; | 
 |  | 
 |     if (!_commandQueue) { | 
 |       FML_DLOG(ERROR) << "Could not create Metal command queue."; | 
 |       return nil; | 
 |     } | 
 |  | 
 |     [_commandQueue setLabel:@"Flutter Main Queue"]; | 
 |  | 
 |     CVReturn cvReturn = CVMetalTextureCacheCreate(kCFAllocatorDefault,  // allocator | 
 |                                                   nil,      // cache attributes (nil default) | 
 |                                                   _device,  // metal device | 
 |                                                   nil,      // texture attributes (nil default) | 
 |                                                   &_textureCache  // [out] cache | 
 |     ); | 
 |     if (cvReturn != kCVReturnSuccess) { | 
 |       FML_DLOG(ERROR) << "Could not create Metal texture cache."; | 
 |       return nil; | 
 |     } | 
 |  | 
 |     // The devices are in the same "sharegroup" because they share the same device and command | 
 |     // queues for now. When the resource context gets its own transfer queue, this will have to be | 
 |     // refactored. | 
 |     _mainContext = [self createGrContext]; | 
 |     _resourceContext = [self createGrContext]; | 
 |  | 
 |     if (!_mainContext || !_resourceContext) { | 
 |       FML_DLOG(ERROR) << "Could not create Skia Metal contexts."; | 
 |       return nil; | 
 |     } | 
 |  | 
 |     FML_LOG(IMPORTANT) << "Using the Skia rendering backend (Metal)."; | 
 |  | 
 |     _resourceContext->setResourceCacheLimit(0u); | 
 |   } | 
 |   return self; | 
 | } | 
 |  | 
 | - (sk_sp<GrDirectContext>)createGrContext { | 
 |   const auto contextOptions = | 
 |       flutter::MakeDefaultContextOptions(flutter::ContextType::kRender, GrBackendApi::kMetal); | 
 |   id<MTLDevice> device = _device; | 
 |   id<MTLCommandQueue> commandQueue = _commandQueue; | 
 |   return [FlutterDarwinContextMetalSkia createGrContext:device commandQueue:commandQueue]; | 
 | } | 
 |  | 
 | + (sk_sp<GrDirectContext>)createGrContext:(id<MTLDevice>)device | 
 |                              commandQueue:(id<MTLCommandQueue>)commandQueue { | 
 |   const auto contextOptions = | 
 |       flutter::MakeDefaultContextOptions(flutter::ContextType::kRender, GrBackendApi::kMetal); | 
 |   GrMtlBackendContext backendContext = {}; | 
 |   // Skia expect arguments to `MakeMetal` transfer ownership of the reference in for release later | 
 |   // when the GrDirectContext is collected. | 
 |   backendContext.fDevice.reset((__bridge_retained void*)device); | 
 |   backendContext.fQueue.reset((__bridge_retained void*)commandQueue); | 
 |   return GrDirectContexts::MakeMetal(backendContext, contextOptions); | 
 | } | 
 |  | 
 | - (void)dealloc { | 
 |   if (_textureCache) { | 
 |     CFRelease(_textureCache); | 
 |   } | 
 | } | 
 |  | 
 | - (FlutterDarwinExternalTextureMetal*) | 
 |     createExternalTextureWithIdentifier:(int64_t)textureID | 
 |                                 texture:(NSObject<FlutterTexture>*)texture { | 
 |   return [[FlutterDarwinExternalTextureMetal alloc] initWithTextureCache:_textureCache | 
 |                                                                textureID:textureID | 
 |                                                                  texture:texture | 
 |                                                           enableImpeller:NO]; | 
 | } | 
 |  | 
 | @end |