• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1
2/*
3 * Copyright 2019 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "include/core/SkCanvas.h"
10#include "include/core/SkColorFilter.h"
11#include "include/gpu/gl/GrGLInterface.h"
12#include "tools/ToolUtils.h"
13#include "tools/sk_app/GLWindowContext.h"
14#include "tools/sk_app/ios/WindowContextFactory_ios.h"
15
16#import <OpenGLES/ES3/gl.h>
17#import <UIKit/UIKit.h>
18
19using sk_app::DisplayParams;
20using sk_app::window_context_factory::IOSWindowInfo;
21using sk_app::GLWindowContext;
22
23@interface RasterView : MainView
24@end
25
26@implementation RasterView
27+ (Class) layerClass {
28    return [CAEAGLLayer class];
29}
30@end
31
32namespace {
33
34// TODO: This still uses GL to handle the update rather than using a purely raster backend,
35// for historical reasons. Writing a pure raster backend would be better in the long run.
36
37class RasterWindowContext_ios : public GLWindowContext {
38public:
39    RasterWindowContext_ios(const IOSWindowInfo&, const DisplayParams&);
40
41    ~RasterWindowContext_ios() override;
42
43    sk_sp<SkSurface> getBackbufferSurface() override;
44
45    void onSwapBuffers() override;
46
47    sk_sp<const GrGLInterface> onInitializeContext() override;
48    void onDestroyContext() override;
49
50    void resize(int w, int h) override;
51
52private:
53    sk_app::Window_ios*  fWindow;
54    UIViewController*    fViewController;
55    RasterView*          fRasterView;
56    EAGLContext*         fGLContext;
57    GLuint               fFramebuffer;
58    GLuint               fRenderbuffer;
59    sk_sp<SkSurface>     fBackbufferSurface;
60
61    using INHERITED = GLWindowContext;
62};
63
64RasterWindowContext_ios::RasterWindowContext_ios(const IOSWindowInfo& info,
65                                                 const DisplayParams& params)
66    : INHERITED(params)
67    , fWindow(info.fWindow)
68    , fViewController(info.fViewController)
69    , fGLContext(nil) {
70
71    // any config code here (particularly for msaa)?
72
73    this->initializeContext();
74}
75
76RasterWindowContext_ios::~RasterWindowContext_ios() {
77    this->destroyContext();
78    [fRasterView removeFromSuperview];
79    [fRasterView release];
80}
81
82sk_sp<const GrGLInterface> RasterWindowContext_ios::onInitializeContext() {
83    SkASSERT(nil != fViewController);
84    SkASSERT(!fGLContext);
85
86    CGRect frameRect = [fViewController.view frame];
87    fRasterView = [[[RasterView alloc] initWithFrame:frameRect] initWithWindow:fWindow];
88    [fViewController.view addSubview:fRasterView];
89
90    fGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
91
92    if (!fGLContext)
93    {
94        SkDebugf("Could Not Create OpenGL ES Context\n");
95        return nullptr;
96    }
97
98    if (![EAGLContext setCurrentContext:fGLContext]) {
99        SkDebugf("Could Not Set OpenGL ES Context As Current\n");
100        this->onDestroyContext();
101        return nullptr;
102    }
103
104    // Set up EAGLLayer
105    CAEAGLLayer* eaglLayer = (CAEAGLLayer*)fRasterView.layer;
106    eaglLayer.drawableProperties = @{kEAGLDrawablePropertyRetainedBacking : @NO,
107                                     kEAGLDrawablePropertyColorFormat     : kEAGLColorFormatRGBA8 };
108    eaglLayer.opaque = YES;
109    eaglLayer.frame = frameRect;
110    eaglLayer.contentsGravity = kCAGravityTopLeft;
111
112    // Set up framebuffer
113    glGenFramebuffers(1, &fFramebuffer);
114    glBindFramebuffer(GL_FRAMEBUFFER, fFramebuffer);
115
116    glGenRenderbuffers(1, &fRenderbuffer);
117    glBindRenderbuffer(GL_RENDERBUFFER, fRenderbuffer);
118    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fRenderbuffer);
119
120    [fGLContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:eaglLayer];
121
122    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
123    if (status != GL_FRAMEBUFFER_COMPLETE) {
124        SkDebugf("Invalid Framebuffer\n");
125        this->onDestroyContext();
126        return nullptr;
127    }
128
129    glClearStencil(0);
130    glClearColor(0, 0, 0, 255);
131    glStencilMask(0xffffffff);
132    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
133
134    fStencilBits = 8;
135    fSampleCount = 1; // TODO: handle multisampling
136
137    fWidth = fViewController.view.frame.size.width;
138    fHeight = fViewController.view.frame.size.height;
139
140    glViewport(0, 0, fWidth, fHeight);
141
142    // make the offscreen image
143    SkImageInfo info = SkImageInfo::Make(fWidth, fHeight, fDisplayParams.fColorType,
144                                         kPremul_SkAlphaType, fDisplayParams.fColorSpace);
145    fBackbufferSurface = SkSurface::MakeRaster(info);
146    return GrGLMakeNativeInterface();
147}
148
149void RasterWindowContext_ios::onDestroyContext() {
150    glDeleteFramebuffers(1, &fFramebuffer);
151    glDeleteRenderbuffers(1, &fRenderbuffer);
152    [EAGLContext setCurrentContext:nil];
153    [fGLContext release];
154    fGLContext = nil;
155}
156
157sk_sp<SkSurface> RasterWindowContext_ios::getBackbufferSurface() {
158    return fBackbufferSurface;
159}
160
161void RasterWindowContext_ios::onSwapBuffers() {
162    if (fBackbufferSurface) {
163        // We made/have an off-screen surface. Get the contents as an SkImage:
164        sk_sp<SkImage> snapshot = fBackbufferSurface->makeImageSnapshot();
165
166        sk_sp<SkSurface> gpuSurface = INHERITED::getBackbufferSurface();
167        SkCanvas* gpuCanvas = gpuSurface->getCanvas();
168        gpuCanvas->drawImage(snapshot, 0, 0);
169        gpuCanvas->flush();
170        glBindRenderbuffer(GL_RENDERBUFFER, fRenderbuffer);
171        [fGLContext presentRenderbuffer:GL_RENDERBUFFER];
172    }
173}
174
175void RasterWindowContext_ios::resize(int w, int h) {
176    // TODO: handle rotation
177    // [fGLContext update];
178     INHERITED::resize(w, h);
179}
180
181}  // anonymous namespace
182
183namespace sk_app {
184namespace window_context_factory {
185
186std::unique_ptr<WindowContext> MakeRasterForIOS(const IOSWindowInfo& info,
187                                                const DisplayParams& params) {
188    std::unique_ptr<WindowContext> ctx(new RasterWindowContext_ios(info, params));
189    if (!ctx->isValid()) {
190        return nullptr;
191    }
192    return ctx;
193}
194
195}  // namespace window_context_factory
196}  // namespace sk_app
197