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