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