xref: /aosp_15_r20/external/skia/tools/window/ios/RasterWindowContext_ios.mm (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/ganesh/GrDirectContext.h"
12#include "include/gpu/ganesh/GrRecordingContext.h"
13#include "include/gpu/ganesh/gl/GrGLInterface.h"
14#include "tools/ToolUtils.h"
15#include "tools/window/GLWindowContext.h"
16#include "tools/window/ios/WindowContextFactory_ios.h"
17#include "include/gpu/ganesh/gl/ios/GrGLMakeIOSInterface.h"
18
19#import <OpenGLES/ES3/gl.h>
20#import <UIKit/UIKit.h>
21
22using skwindow::DisplayParams;
23using skwindow::IOSWindowInfo;
24using skwindow::internal::GLWindowContext;
25
26@interface RasterView : MainView
27@end
28
29@implementation RasterView
30+ (Class) layerClass {
31    return [CAEAGLLayer class];
32}
33@end
34
35namespace {
36
37// TODO: This still uses GL to handle the update rather than using a purely raster backend,
38// for historical reasons. Writing a pure raster backend would be better in the long run.
39
40class RasterWindowContext_ios : public GLWindowContext {
41public:
42    RasterWindowContext_ios(const IOSWindowInfo&, std::unique_ptr<const DisplayParams>);
43
44    ~RasterWindowContext_ios() override;
45
46    sk_sp<SkSurface> getBackbufferSurface() override;
47
48    sk_sp<const GrGLInterface> onInitializeContext() override;
49    void onDestroyContext() override;
50
51    void resize(int w, int h) override;
52
53private:
54    void onSwapBuffers() override;
55
56    sk_app::Window_ios*  fWindow;
57    UIViewController*    fViewController;
58    RasterView*          fRasterView;
59    EAGLContext*         fGLContext;
60    GLuint               fFramebuffer;
61    GLuint               fRenderbuffer;
62    sk_sp<SkSurface>     fBackbufferSurface;
63};
64
65RasterWindowContext_ios::RasterWindowContext_ios(const IOSWindowInfo& info,
66                                                 std::unique_ptr<const DisplayParams> params)
67        : GLWindowContext(std::move(params))
68        , fWindow(info.fWindow)
69        , fViewController(info.fViewController)
70        , fGLContext(nil) {
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,
144                                         fHeight,
145                                         fDisplayParams->colorType(),
146                                         kPremul_SkAlphaType,
147                                         fDisplayParams->colorSpace());
148    fBackbufferSurface = SkSurfaces::Raster(info);
149    return GrGLInterfaces::MakeIOS();
150}
151
152void RasterWindowContext_ios::onDestroyContext() {
153    glDeleteFramebuffers(1, &fFramebuffer);
154    glDeleteRenderbuffers(1, &fRenderbuffer);
155    [EAGLContext setCurrentContext:nil];
156    [fGLContext release];
157    fGLContext = nil;
158}
159
160sk_sp<SkSurface> RasterWindowContext_ios::getBackbufferSurface() {
161    return fBackbufferSurface;
162}
163
164void RasterWindowContext_ios::onSwapBuffers() {
165    if (fBackbufferSurface) {
166        // We made/have an off-screen surface. Get the contents as an SkImage:
167        sk_sp<SkImage> snapshot = fBackbufferSurface->makeImageSnapshot();
168
169        sk_sp<SkSurface> gpuSurface = GLWindowContext::getBackbufferSurface();
170        SkCanvas* gpuCanvas = gpuSurface->getCanvas();
171        gpuCanvas->drawImage(snapshot, 0, 0);
172        auto dContext = GrAsDirectContext(gpuCanvas->recordingContext());
173        dContext->flushAndSubmit();
174
175        glBindRenderbuffer(GL_RENDERBUFFER, fRenderbuffer);
176        [fGLContext presentRenderbuffer:GL_RENDERBUFFER];
177    }
178}
179
180void RasterWindowContext_ios::resize(int w, int h) {
181    // TODO: handle rotation
182    // [fGLContext update];
183    GLWindowContext::resize(w, h);
184}
185
186}  // anonymous namespace
187
188namespace skwindow {
189
190std::unique_ptr<WindowContext> MakeRasterForIOS(const IOSWindowInfo& info,
191                                                std::unique_ptr<const DisplayParams> params) {
192    std::unique_ptr<WindowContext> ctx(new RasterWindowContext_ios(info, std::move(params)));
193    if (!ctx->isValid()) {
194        return nullptr;
195    }
196    return ctx;
197}
198
199}  // namespace skwindow
200