xref: /aosp_15_r20/external/skia/tools/window/mac/RasterWindowContext_mac.mm (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1/*
2 * Copyright 2019 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "tools/window/mac/RasterWindowContext_mac.h"
9
10#include "include/core/SkCanvas.h"
11#include "include/core/SkColorFilter.h"
12#include "include/gpu/ganesh/SkSurfaceGanesh.h"
13#include "include/gpu/ganesh/gl/mac/GrGLMakeMacInterface.h"
14#include "include/gpu/ganesh/gl/GrGLInterface.h"
15#include "tools/ToolUtils.h"
16#include "tools/window/GLWindowContext.h"
17#include "tools/window/mac/MacWindowInfo.h"
18
19#include <OpenGL/gl.h>
20
21#include <Cocoa/Cocoa.h>
22
23using skwindow::DisplayParams;
24using skwindow::MacWindowInfo;
25using skwindow::internal::GLWindowContext;
26
27namespace {
28
29// TODO: This still uses GL to handle the update rather than using a purely raster backend,
30// for historical reasons. Writing a pure raster backend would be better in the long run.
31
32class RasterWindowContext_mac : public GLWindowContext {
33public:
34    RasterWindowContext_mac(const MacWindowInfo&, std::unique_ptr<const DisplayParams>);
35
36    ~RasterWindowContext_mac() override;
37
38    sk_sp<SkSurface> getBackbufferSurface() override;
39
40    sk_sp<const GrGLInterface> onInitializeContext() override;
41    void onDestroyContext() override {}
42
43    void resize(int w, int h) override;
44
45private:
46    void onSwapBuffers() override;
47
48    NSView*              fMainView;
49    NSOpenGLContext*     fGLContext;
50    NSOpenGLPixelFormat* fPixelFormat;
51    sk_sp<SkSurface>     fBackbufferSurface;
52};
53
54RasterWindowContext_mac::RasterWindowContext_mac(const MacWindowInfo& info,
55                                                 std::unique_ptr<const DisplayParams> params)
56        : GLWindowContext(std::move(params)), fMainView(info.fMainView), fGLContext(nil) {
57    // any config code here (particularly for msaa)?
58
59    this->initializeContext();
60}
61
62RasterWindowContext_mac::~RasterWindowContext_mac() {
63    [NSOpenGLContext clearCurrentContext];
64    [fPixelFormat release];
65    fPixelFormat = nil;
66    [fGLContext release];
67    fGLContext = nil;
68}
69
70sk_sp<const GrGLInterface> RasterWindowContext_mac::onInitializeContext() {
71    SkASSERT(nil != fMainView);
72
73    if (!fGLContext) {
74        // set up pixel format
75        constexpr int kMaxAttributes = 18;
76        NSOpenGLPixelFormatAttribute attributes[kMaxAttributes];
77        int numAttributes = 0;
78        attributes[numAttributes++] = NSOpenGLPFAAccelerated;
79        attributes[numAttributes++] = NSOpenGLPFAClosestPolicy;
80        attributes[numAttributes++] = NSOpenGLPFADoubleBuffer;
81        attributes[numAttributes++] = NSOpenGLPFAOpenGLProfile;
82        attributes[numAttributes++] = NSOpenGLProfileVersion3_2Core;
83        attributes[numAttributes++] = NSOpenGLPFAColorSize;
84        attributes[numAttributes++] = 24;
85        attributes[numAttributes++] = NSOpenGLPFAAlphaSize;
86        attributes[numAttributes++] = 8;
87        attributes[numAttributes++] = NSOpenGLPFADepthSize;
88        attributes[numAttributes++] = 0;
89        attributes[numAttributes++] = NSOpenGLPFAStencilSize;
90        attributes[numAttributes++] = 8;
91        if (fDisplayParams->msaaSampleCount() > 1) {
92            attributes[numAttributes++] = NSOpenGLPFASampleBuffers;
93            attributes[numAttributes++] = 1;
94            attributes[numAttributes++] = NSOpenGLPFASamples;
95            attributes[numAttributes++] = fDisplayParams->msaaSampleCount();
96        } else {
97            attributes[numAttributes++] = NSOpenGLPFASampleBuffers;
98            attributes[numAttributes++] = 0;
99        }
100        attributes[numAttributes++] = 0;
101        SkASSERT(numAttributes <= kMaxAttributes);
102
103        fPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
104        if (nil == fPixelFormat) {
105            return nullptr;
106        }
107
108        // create context
109        fGLContext = [[NSOpenGLContext alloc] initWithFormat:fPixelFormat shareContext:nil];
110        if (nil == fGLContext) {
111            [fPixelFormat release];
112            fPixelFormat = nil;
113            return nullptr;
114        }
115
116        [fMainView setWantsBestResolutionOpenGLSurface:YES];
117        [fGLContext setView:fMainView];
118
119        GLint swapInterval = fDisplayParams->disableVsync() ? 0 : 1;
120        [fGLContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
121    }
122
123    // make context current
124    [fGLContext makeCurrentContext];
125
126    glClearStencil(0);
127    glClearColor(0, 0, 0, 255);
128    glStencilMask(0xffffffff);
129    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
130
131    GLint stencilBits;
132    [fPixelFormat getValues:&stencilBits forAttribute:NSOpenGLPFAStencilSize forVirtualScreen:0];
133    fStencilBits = stencilBits;
134    GLint sampleCount;
135    [fPixelFormat getValues:&sampleCount forAttribute:NSOpenGLPFASamples forVirtualScreen:0];
136    fSampleCount = sampleCount;
137    fSampleCount = std::max(fSampleCount, 1);
138
139    CGFloat backingScaleFactor = skwindow::GetBackingScaleFactor(fMainView);
140    fWidth = fMainView.bounds.size.width * backingScaleFactor;
141    fHeight = fMainView.bounds.size.height * backingScaleFactor;
142    glViewport(0, 0, fWidth, fHeight);
143
144    // make the offscreen image
145    SkImageInfo info = SkImageInfo::Make(fWidth,
146                                         fHeight,
147                                         fDisplayParams->colorType(),
148                                         kPremul_SkAlphaType,
149                                         fDisplayParams->colorSpace());
150    fBackbufferSurface = SkSurfaces::Raster(info);
151    return GrGLInterfaces::MakeMac();
152}
153
154sk_sp<SkSurface> RasterWindowContext_mac::getBackbufferSurface() { return fBackbufferSurface; }
155
156void RasterWindowContext_mac::onSwapBuffers() {
157    if (fBackbufferSurface) {
158        // We made/have an off-screen surface. Get the contents as an SkImage:
159        sk_sp<SkImage> snapshot = fBackbufferSurface->makeImageSnapshot();
160
161        sk_sp<SkSurface> gpuSurface = GLWindowContext::getBackbufferSurface();
162        SkCanvas* gpuCanvas = gpuSurface->getCanvas();
163        gpuCanvas->drawImage(snapshot, 0, 0);
164        skgpu::ganesh::Flush(gpuSurface);
165
166        [fGLContext flushBuffer];
167    }
168}
169
170void RasterWindowContext_mac::resize(int w, int h) {
171    [fGLContext update];
172
173    // The super class always recreates the context.
174    GLWindowContext::resize(0, 0);
175}
176
177}  // anonymous namespace
178
179namespace skwindow {
180
181std::unique_ptr<WindowContext> MakeRasterForMac(const MacWindowInfo& info,
182                                                std::unique_ptr<const DisplayParams> params) {
183    std::unique_ptr<WindowContext> ctx(new RasterWindowContext_mac(info, std::move(params)));
184    if (!ctx->isValid()) {
185        return nullptr;
186    }
187    return ctx;
188}
189
190}  // namespace skwindow
191