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