1*c8dee2aaSAndroid Build Coastguard Worker// Copyright 2020 Google LLC. 2*c8dee2aaSAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. 3*c8dee2aaSAndroid Build Coastguard Worker 4*c8dee2aaSAndroid Build Coastguard Worker#include "tools/skottie_ios_app/SkiaContext.h" 5*c8dee2aaSAndroid Build Coastguard Worker 6*c8dee2aaSAndroid Build Coastguard Worker#include "include/core/SkColorSpace.h" 7*c8dee2aaSAndroid Build Coastguard Worker#include "include/core/SkSurface.h" 8*c8dee2aaSAndroid Build Coastguard Worker#include "include/gpu/ganesh/GrBackendSurface.h" 9*c8dee2aaSAndroid Build Coastguard Worker#include "include/gpu/ganesh/GrDirectContext.h" 10*c8dee2aaSAndroid Build Coastguard Worker#include "include/gpu/ganesh/SkSurfaceGanesh.h" 11*c8dee2aaSAndroid Build Coastguard Worker#include "include/gpu/ganesh/gl/GrGLBackendSurface.h" 12*c8dee2aaSAndroid Build Coastguard Worker#include "include/gpu/ganesh/gl/GrGLDirectContext.h" 13*c8dee2aaSAndroid Build Coastguard Worker#include "include/gpu/ganesh/gl/GrGLInterface.h" 14*c8dee2aaSAndroid Build Coastguard Worker#include "include/gpu/ganesh/gl/GrGLTypes.h" 15*c8dee2aaSAndroid Build Coastguard Worker#include "src/base/SkTime.h" 16*c8dee2aaSAndroid Build Coastguard Worker 17*c8dee2aaSAndroid Build Coastguard Worker#import <GLKit/GLKit.h> 18*c8dee2aaSAndroid Build Coastguard Worker#import <UIKit/UIKit.h> 19*c8dee2aaSAndroid Build Coastguard Worker#import <OpenGLES/ES3/gl.h> 20*c8dee2aaSAndroid Build Coastguard Worker 21*c8dee2aaSAndroid Build Coastguard Worker#include <CoreFoundation/CoreFoundation.h> 22*c8dee2aaSAndroid Build Coastguard Worker 23*c8dee2aaSAndroid Build Coastguard Workerstatic void configure_glkview_for_skia(GLKView* view) { 24*c8dee2aaSAndroid Build Coastguard Worker [view setDrawableColorFormat:GLKViewDrawableColorFormatRGBA8888]; 25*c8dee2aaSAndroid Build Coastguard Worker [view setDrawableDepthFormat:GLKViewDrawableDepthFormat24]; 26*c8dee2aaSAndroid Build Coastguard Worker [view setDrawableStencilFormat:GLKViewDrawableStencilFormat8]; 27*c8dee2aaSAndroid Build Coastguard Worker} 28*c8dee2aaSAndroid Build Coastguard Worker 29*c8dee2aaSAndroid Build Coastguard Workerstatic sk_sp<SkSurface> make_gl_surface(GrDirectContext* dContext, int width, int height) { 30*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kStencilBits = 8; 31*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kSampleCount = 1; 32*c8dee2aaSAndroid Build Coastguard Worker static const SkSurfaceProps surfaceProps; 33*c8dee2aaSAndroid Build Coastguard Worker if (!dContext || width <= 0 || height <= 0) { 34*c8dee2aaSAndroid Build Coastguard Worker return nullptr; 35*c8dee2aaSAndroid Build Coastguard Worker } 36*c8dee2aaSAndroid Build Coastguard Worker GLint fboid = 0; 37*c8dee2aaSAndroid Build Coastguard Worker glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fboid); 38*c8dee2aaSAndroid Build Coastguard Worker return SkSurfaces::WrapBackendRenderTarget( 39*c8dee2aaSAndroid Build Coastguard Worker dContext, 40*c8dee2aaSAndroid Build Coastguard Worker GrBackendRenderTargets::MakeGL(width, 41*c8dee2aaSAndroid Build Coastguard Worker height, 42*c8dee2aaSAndroid Build Coastguard Worker kSampleCount, 43*c8dee2aaSAndroid Build Coastguard Worker kStencilBits, 44*c8dee2aaSAndroid Build Coastguard Worker GrGLFramebufferInfo{(GrGLuint)fboid, GL_RGBA8}), 45*c8dee2aaSAndroid Build Coastguard Worker kBottomLeft_GrSurfaceOrigin, 46*c8dee2aaSAndroid Build Coastguard Worker kRGBA_8888_SkColorType, 47*c8dee2aaSAndroid Build Coastguard Worker nullptr, 48*c8dee2aaSAndroid Build Coastguard Worker &surfaceProps); 49*c8dee2aaSAndroid Build Coastguard Worker} 50*c8dee2aaSAndroid Build Coastguard Worker 51*c8dee2aaSAndroid Build Coastguard Worker// A UIView that uses a GL-backed SkSurface to draw. 52*c8dee2aaSAndroid Build Coastguard Worker@interface SkiaGLView : GLKView 53*c8dee2aaSAndroid Build Coastguard Worker @property (strong) SkiaViewController* controller; 54*c8dee2aaSAndroid Build Coastguard Worker 55*c8dee2aaSAndroid Build Coastguard Worker // Override of the UIView interface. 56*c8dee2aaSAndroid Build Coastguard Worker - (void)drawRect:(CGRect)rect; 57*c8dee2aaSAndroid Build Coastguard Worker 58*c8dee2aaSAndroid Build Coastguard Worker // Required initializer. 59*c8dee2aaSAndroid Build Coastguard Worker - (instancetype)initWithFrame:(CGRect)frame 60*c8dee2aaSAndroid Build Coastguard Worker withEAGLContext:(EAGLContext*)eaglContext 61*c8dee2aaSAndroid Build Coastguard Worker withDirectContext:(GrDirectContext*)dContext; 62*c8dee2aaSAndroid Build Coastguard Worker@end 63*c8dee2aaSAndroid Build Coastguard Worker 64*c8dee2aaSAndroid Build Coastguard Worker@implementation SkiaGLView { 65*c8dee2aaSAndroid Build Coastguard Worker GrDirectContext* fDContext; 66*c8dee2aaSAndroid Build Coastguard Worker} 67*c8dee2aaSAndroid Build Coastguard Worker 68*c8dee2aaSAndroid Build Coastguard Worker- (instancetype)initWithFrame:(CGRect)frame 69*c8dee2aaSAndroid Build Coastguard Worker withEAGLContext:(EAGLContext*)eaglContext 70*c8dee2aaSAndroid Build Coastguard Worker withDirectContext:(GrDirectContext*)dContext { 71*c8dee2aaSAndroid Build Coastguard Worker self = [super initWithFrame:frame context:eaglContext]; 72*c8dee2aaSAndroid Build Coastguard Worker fDContext = dContext; 73*c8dee2aaSAndroid Build Coastguard Worker configure_glkview_for_skia(self); 74*c8dee2aaSAndroid Build Coastguard Worker return self; 75*c8dee2aaSAndroid Build Coastguard Worker} 76*c8dee2aaSAndroid Build Coastguard Worker 77*c8dee2aaSAndroid Build Coastguard Worker- (void)drawRect:(CGRect)rect { 78*c8dee2aaSAndroid Build Coastguard Worker SkiaViewController* viewController = [self controller]; 79*c8dee2aaSAndroid Build Coastguard Worker static constexpr double kFrameRate = 1.0 / 30.0; 80*c8dee2aaSAndroid Build Coastguard Worker double next = [viewController isPaused] ? 0 : kFrameRate + SkTime::GetNSecs() * 1e-9; 81*c8dee2aaSAndroid Build Coastguard Worker 82*c8dee2aaSAndroid Build Coastguard Worker [super drawRect:rect]; 83*c8dee2aaSAndroid Build Coastguard Worker 84*c8dee2aaSAndroid Build Coastguard Worker int width = (int)[self drawableWidth], 85*c8dee2aaSAndroid Build Coastguard Worker height = (int)[self drawableHeight]; 86*c8dee2aaSAndroid Build Coastguard Worker if (!(fDContext)) { 87*c8dee2aaSAndroid Build Coastguard Worker NSLog(@"Error: GrDirectContext missing.\n"); 88*c8dee2aaSAndroid Build Coastguard Worker return; 89*c8dee2aaSAndroid Build Coastguard Worker } 90*c8dee2aaSAndroid Build Coastguard Worker if (sk_sp<SkSurface> surface = make_gl_surface(fDContext, width, height)) { 91*c8dee2aaSAndroid Build Coastguard Worker [viewController draw:rect 92*c8dee2aaSAndroid Build Coastguard Worker toCanvas:(surface->getCanvas()) 93*c8dee2aaSAndroid Build Coastguard Worker atSize:CGSize{(CGFloat)width, (CGFloat)height}]; 94*c8dee2aaSAndroid Build Coastguard Worker fDContext->flushAndSubmit(surface.get()); 95*c8dee2aaSAndroid Build Coastguard Worker } 96*c8dee2aaSAndroid Build Coastguard Worker if (next) { 97*c8dee2aaSAndroid Build Coastguard Worker [NSTimer scheduledTimerWithTimeInterval:std::max(0.0, next - SkTime::GetNSecs() * 1e-9) 98*c8dee2aaSAndroid Build Coastguard Worker target:self 99*c8dee2aaSAndroid Build Coastguard Worker selector:@selector(setNeedsDisplay) 100*c8dee2aaSAndroid Build Coastguard Worker userInfo:nil 101*c8dee2aaSAndroid Build Coastguard Worker repeats:NO]; 102*c8dee2aaSAndroid Build Coastguard Worker } 103*c8dee2aaSAndroid Build Coastguard Worker} 104*c8dee2aaSAndroid Build Coastguard Worker@end 105*c8dee2aaSAndroid Build Coastguard Worker 106*c8dee2aaSAndroid Build Coastguard Worker@interface SkiaGLContext : SkiaContext 107*c8dee2aaSAndroid Build Coastguard Worker @property (strong) EAGLContext* eaglContext; 108*c8dee2aaSAndroid Build Coastguard Worker - (instancetype) init; 109*c8dee2aaSAndroid Build Coastguard Worker - (UIView*) makeViewWithController:(SkiaViewController*)vc withFrame:(CGRect)frame; 110*c8dee2aaSAndroid Build Coastguard Worker - (SkiaViewController*) getViewController:(UIView*)view; 111*c8dee2aaSAndroid Build Coastguard Worker@end 112*c8dee2aaSAndroid Build Coastguard Worker 113*c8dee2aaSAndroid Build Coastguard Worker@implementation SkiaGLContext { 114*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GrDirectContext> fDContext; 115*c8dee2aaSAndroid Build Coastguard Worker} 116*c8dee2aaSAndroid Build Coastguard Worker- (instancetype) init { 117*c8dee2aaSAndroid Build Coastguard Worker self = [super init]; 118*c8dee2aaSAndroid Build Coastguard Worker [self setEaglContext:[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]]; 119*c8dee2aaSAndroid Build Coastguard Worker if (![self eaglContext]) { 120*c8dee2aaSAndroid Build Coastguard Worker NSLog(@"Falling back to GLES2.\n"); 121*c8dee2aaSAndroid Build Coastguard Worker [self setEaglContext:[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]]; 122*c8dee2aaSAndroid Build Coastguard Worker } 123*c8dee2aaSAndroid Build Coastguard Worker if (![self eaglContext]) { 124*c8dee2aaSAndroid Build Coastguard Worker NSLog(@"[[EAGLContext alloc] initWithAPI:...] failed"); 125*c8dee2aaSAndroid Build Coastguard Worker return nil; 126*c8dee2aaSAndroid Build Coastguard Worker } 127*c8dee2aaSAndroid Build Coastguard Worker EAGLContext* oldContext = [EAGLContext currentContext]; 128*c8dee2aaSAndroid Build Coastguard Worker [EAGLContext setCurrentContext:[self eaglContext]]; 129*c8dee2aaSAndroid Build Coastguard Worker fDContext = GrDirectContexts::MakeGL(nullptr, GrContextOptions()); 130*c8dee2aaSAndroid Build Coastguard Worker [EAGLContext setCurrentContext:oldContext]; 131*c8dee2aaSAndroid Build Coastguard Worker if (!fDContext) { 132*c8dee2aaSAndroid Build Coastguard Worker NSLog(@"GrDirectContexts::MakeGL failed"); 133*c8dee2aaSAndroid Build Coastguard Worker return nil; 134*c8dee2aaSAndroid Build Coastguard Worker } 135*c8dee2aaSAndroid Build Coastguard Worker return self; 136*c8dee2aaSAndroid Build Coastguard Worker} 137*c8dee2aaSAndroid Build Coastguard Worker 138*c8dee2aaSAndroid Build Coastguard Worker- (UIView*) makeViewWithController:(SkiaViewController*)vc withFrame:(CGRect)frame { 139*c8dee2aaSAndroid Build Coastguard Worker SkiaGLView* skiaView = [[SkiaGLView alloc] initWithFrame:frame 140*c8dee2aaSAndroid Build Coastguard Worker withEAGLContext:[self eaglContext] 141*c8dee2aaSAndroid Build Coastguard Worker withDirectContext:fDContext.get()]; 142*c8dee2aaSAndroid Build Coastguard Worker [skiaView setController:vc]; 143*c8dee2aaSAndroid Build Coastguard Worker return skiaView; 144*c8dee2aaSAndroid Build Coastguard Worker} 145*c8dee2aaSAndroid Build Coastguard Worker- (SkiaViewController*) getViewController:(UIView*)view { 146*c8dee2aaSAndroid Build Coastguard Worker return [view isKindOfClass:[SkiaGLView class]] ? [(SkiaGLView*)view controller] : nil; 147*c8dee2aaSAndroid Build Coastguard Worker} 148*c8dee2aaSAndroid Build Coastguard Worker@end 149*c8dee2aaSAndroid Build Coastguard Worker 150*c8dee2aaSAndroid Build Coastguard WorkerSkiaContext* MakeSkiaGLContext() { return [[SkiaGLContext alloc] init]; } 151