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