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