1cb93a386Sopenharmony_ci// Copyright 2020 Google LLC. 2cb93a386Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. 3cb93a386Sopenharmony_ci 4cb93a386Sopenharmony_ci#include "tools/skottie_ios_app/SkiaContext.h" 5cb93a386Sopenharmony_ci 6cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 7cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 8cb93a386Sopenharmony_ci#include "tools/skottie_ios_app/SkMetalViewBridge.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#import <Metal/Metal.h> 11cb93a386Sopenharmony_ci#import <MetalKit/MetalKit.h> 12cb93a386Sopenharmony_ci#import <UIKit/UIKit.h> 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_ci// A UIView that uses a Metal-backed SkSurface to draw. 15cb93a386Sopenharmony_ci@interface SkiaMtkView : MTKView 16cb93a386Sopenharmony_ci @property (strong) SkiaViewController* controller; 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_ci // Override of the MTKView interface. Uses Skia+Metal to draw. 19cb93a386Sopenharmony_ci - (void)drawRect:(CGRect)rect; 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ci // Required initializer. 22cb93a386Sopenharmony_ci - (instancetype)initWithFrame:(CGRect)frameRect 23cb93a386Sopenharmony_ci device:(id<MTLDevice>)device 24cb93a386Sopenharmony_ci queue:(id<MTLCommandQueue>)queue 25cb93a386Sopenharmony_ci grDevice:(GrDirectContext*)dContext; 26cb93a386Sopenharmony_ci@end 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ci@implementation SkiaMtkView { 29cb93a386Sopenharmony_ci id<MTLCommandQueue> fQueue; 30cb93a386Sopenharmony_ci GrDirectContext* fDContext; 31cb93a386Sopenharmony_ci} 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_ci- (instancetype)initWithFrame:(CGRect)frameRect 34cb93a386Sopenharmony_ci device:(id<MTLDevice>)mtlDevice 35cb93a386Sopenharmony_ci queue:(id<MTLCommandQueue>)queue 36cb93a386Sopenharmony_ci grDevice:(GrDirectContext*)dContext { 37cb93a386Sopenharmony_ci self = [super initWithFrame:frameRect device:mtlDevice]; 38cb93a386Sopenharmony_ci fQueue = queue; 39cb93a386Sopenharmony_ci fDContext = dContext; 40cb93a386Sopenharmony_ci SkMtkViewConfigForSkia(self); 41cb93a386Sopenharmony_ci return self; 42cb93a386Sopenharmony_ci} 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ci- (void)drawRect:(CGRect)rect { 45cb93a386Sopenharmony_ci [super drawRect:rect]; 46cb93a386Sopenharmony_ci // TODO(halcanary): Use the rect and the InvalidationController to speed up rendering. 47cb93a386Sopenharmony_ci SkiaViewController* viewController = [self controller]; 48cb93a386Sopenharmony_ci if (!viewController || ![[self currentDrawable] texture] || !fDContext) { 49cb93a386Sopenharmony_ci return; 50cb93a386Sopenharmony_ci } 51cb93a386Sopenharmony_ci CGSize size = [self drawableSize]; 52cb93a386Sopenharmony_ci sk_sp<SkSurface> surface = SkMtkViewToSurface(self, fDContext); 53cb93a386Sopenharmony_ci if (!surface) { 54cb93a386Sopenharmony_ci NSLog(@"error: no sksurface"); 55cb93a386Sopenharmony_ci return; 56cb93a386Sopenharmony_ci } 57cb93a386Sopenharmony_ci [viewController draw:rect toCanvas:surface->getCanvas() atSize:size]; 58cb93a386Sopenharmony_ci surface->flushAndSubmit(); 59cb93a386Sopenharmony_ci surface = nullptr; 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci id<MTLCommandBuffer> commandBuffer = [fQueue commandBuffer]; 62cb93a386Sopenharmony_ci [commandBuffer presentDrawable:[self currentDrawable]]; 63cb93a386Sopenharmony_ci [commandBuffer commit]; 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci bool paused = [viewController isPaused]; 66cb93a386Sopenharmony_ci [self setEnableSetNeedsDisplay:paused]; 67cb93a386Sopenharmony_ci [self setPaused:paused]; 68cb93a386Sopenharmony_ci} 69cb93a386Sopenharmony_ci@end 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ci@interface SkiaMetalContext : SkiaContext 72cb93a386Sopenharmony_ci @property (strong) id<MTLDevice> metalDevice; 73cb93a386Sopenharmony_ci @property (strong) id<MTLCommandQueue> metalQueue; 74cb93a386Sopenharmony_ci - (instancetype) init; 75cb93a386Sopenharmony_ci - (UIView*) makeViewWithController:(SkiaViewController*)vc withFrame:(CGRect)frame; 76cb93a386Sopenharmony_ci - (SkiaViewController*) getViewController:(UIView*)view; 77cb93a386Sopenharmony_ci@end 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_ci@implementation SkiaMetalContext { 80cb93a386Sopenharmony_ci sk_sp<GrDirectContext> fDContext; 81cb93a386Sopenharmony_ci} 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ci- (instancetype) init { 84cb93a386Sopenharmony_ci self = [super init]; 85cb93a386Sopenharmony_ci [self setMetalDevice:MTLCreateSystemDefaultDevice()]; 86cb93a386Sopenharmony_ci if(![self metalDevice]) { 87cb93a386Sopenharmony_ci NSLog(@"Metal is not supported on this device"); 88cb93a386Sopenharmony_ci return nil; 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci [self setMetalQueue:[[self metalDevice] newCommandQueue]]; 91cb93a386Sopenharmony_ci fDContext = GrDirectContext::MakeMetal((__bridge void*)[self metalDevice], 92cb93a386Sopenharmony_ci (__bridge void*)[self metalQueue], 93cb93a386Sopenharmony_ci GrContextOptions()); 94cb93a386Sopenharmony_ci 95cb93a386Sopenharmony_ci if (!fDContext) { 96cb93a386Sopenharmony_ci NSLog(@"GrDirectContext::MakeMetal failed"); 97cb93a386Sopenharmony_ci return nil; 98cb93a386Sopenharmony_ci } 99cb93a386Sopenharmony_ci return self; 100cb93a386Sopenharmony_ci} 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ci- (UIView*) makeViewWithController:(SkiaViewController*)vc withFrame:(CGRect)frame { 103cb93a386Sopenharmony_ci SkiaMtkView* skiaView = [[SkiaMtkView alloc] initWithFrame:frame 104cb93a386Sopenharmony_ci device:[self metalDevice] 105cb93a386Sopenharmony_ci queue:[self metalQueue] 106cb93a386Sopenharmony_ci grDevice:fDContext.get()]; 107cb93a386Sopenharmony_ci [skiaView setPreferredFramesPerSecond:30]; 108cb93a386Sopenharmony_ci [skiaView setController:vc]; 109cb93a386Sopenharmony_ci return skiaView; 110cb93a386Sopenharmony_ci} 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci- (SkiaViewController*) getViewController:(UIView*)view { 113cb93a386Sopenharmony_ci return [view isKindOfClass:[SkiaMtkView class]] ? [(SkiaMtkView*)view controller] : nil; 114cb93a386Sopenharmony_ci} 115cb93a386Sopenharmony_ci@end 116cb93a386Sopenharmony_ci 117cb93a386Sopenharmony_ciSkiaContext* MakeSkiaMetalContext() { return [[SkiaMetalContext alloc] init]; } 118