• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "../GLWindowContext.h"
10#include "SkCanvas.h"
11#include "SkColorFilter.h"
12#include "WindowContextFactory_mac.h"
13#include "gl/GrGLInterface.h"
14#include "sk_tool_utils.h"
15
16#include <OpenGL/gl.h>
17
18#include <Cocoa/Cocoa.h>
19
20using sk_app::DisplayParams;
21using sk_app::window_context_factory::MacWindowInfo;
22using sk_app::GLWindowContext;
23
24@interface RasterView : NSOpenGLView
25@end
26
27@implementation RasterView
28
29- (void)drawRect:(NSRect)dirtyRect {
30    // not sure why the parent isn't getting this, but we'll pass it up
31    [[self superview] drawRect:dirtyRect];
32}
33
34@end
35
36namespace {
37
38// TODO: This still uses GL to handle the update rather than using a purely raster backend,
39// for historical reasons. Writing a pure raster backend would be better in the long run.
40
41class RasterWindowContext_mac : public GLWindowContext {
42public:
43    RasterWindowContext_mac(const MacWindowInfo&, const DisplayParams&);
44
45    ~RasterWindowContext_mac() override;
46
47    sk_sp<SkSurface> getBackbufferSurface() override;
48
49    void onSwapBuffers() override;
50
51    sk_sp<const GrGLInterface> onInitializeContext() override;
52    void onDestroyContext() override;
53
54private:
55    NSView*              fMainView;
56    RasterView*          fRasterView;
57    NSOpenGLContext*     fGLContext;
58    NSOpenGLPixelFormat* fPixelFormat;
59    sk_sp<SkSurface>     fBackbufferSurface;
60
61    typedef GLWindowContext INHERITED;
62};
63
64RasterWindowContext_mac::RasterWindowContext_mac(const MacWindowInfo& info,
65                                                 const DisplayParams& params)
66    : INHERITED(params)
67    , fMainView(info.fMainView) {
68
69    // any config code here (particularly for msaa)?
70
71    this->initializeContext();
72}
73
74RasterWindowContext_mac::~RasterWindowContext_mac() {
75    this->destroyContext();
76}
77
78sk_sp<const GrGLInterface> RasterWindowContext_mac::onInitializeContext() {
79    SkASSERT(nil != fMainView);
80
81    // set up pixel format
82    constexpr int kMaxAttributes = 18;
83    NSOpenGLPixelFormatAttribute attributes[kMaxAttributes];
84    int numAttributes = 0;
85    attributes[numAttributes++] = NSOpenGLPFAAccelerated;
86    attributes[numAttributes++] = NSOpenGLPFAClosestPolicy;
87    attributes[numAttributes++] = NSOpenGLPFAOpenGLProfile;
88    attributes[numAttributes++] = NSOpenGLProfileVersion3_2Core;
89    attributes[numAttributes++] = NSOpenGLPFAColorSize;
90    attributes[numAttributes++] = 24;
91    attributes[numAttributes++] = NSOpenGLPFAAlphaSize;
92    attributes[numAttributes++] = 8;
93    attributes[numAttributes++] = NSOpenGLPFADepthSize;
94    attributes[numAttributes++] = 0;
95    attributes[numAttributes++] = NSOpenGLPFAStencilSize;
96    attributes[numAttributes++] = 8;
97    attributes[numAttributes++] = NSOpenGLPFADoubleBuffer;
98    if (fDisplayParams.fMSAASampleCount > 1) {
99        attributes[numAttributes++] = NSOpenGLPFASampleBuffers;
100        attributes[numAttributes++] = 1;
101        attributes[numAttributes++] = NSOpenGLPFASamples;
102        attributes[numAttributes++] = fDisplayParams.fMSAASampleCount;
103    } else {
104        attributes[numAttributes++] = NSOpenGLPFASampleBuffers;
105        attributes[numAttributes++] = 0;
106    }
107    attributes[numAttributes++] = 0;
108    SkASSERT(numAttributes <= kMaxAttributes);
109
110    fPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
111    if (nil == fPixelFormat) {
112        return nullptr;
113    }
114
115    // create context
116    fGLContext = [[NSOpenGLContext alloc] initWithFormat:fPixelFormat shareContext:nil];
117    if (nil == fGLContext) {
118        [fPixelFormat release];
119        fPixelFormat = nil;
120        return nullptr;
121    }
122
123    // create view
124    NSRect rect = fMainView.bounds;
125    fRasterView = [[RasterView alloc] initWithFrame:rect];
126    if (nil == fRasterView) {
127        [fGLContext release];
128        fGLContext = nil;
129        [fPixelFormat release];
130        fPixelFormat = nil;
131        return nullptr;
132    }
133    [fRasterView setTranslatesAutoresizingMaskIntoConstraints:NO];
134
135    // attach OpenGL view to main view
136    [fMainView addSubview:fRasterView];
137    NSDictionary *views = NSDictionaryOfVariableBindings(fRasterView);
138
139    [fMainView addConstraints:
140     [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[fRasterView]|"
141                                             options:0
142                                             metrics:nil
143                                               views:views]];
144
145    [fMainView addConstraints:
146     [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[fRasterView]|"
147                                             options:0
148                                             metrics:nil
149                                               views:views]];
150
151    // make context current
152    GLint swapInterval = 1;
153    [fGLContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
154    [fRasterView setOpenGLContext:fGLContext];
155    [fRasterView setPixelFormat:fPixelFormat];
156    [fRasterView setWantsBestResolutionOpenGLSurface:YES];
157    [fGLContext setView:fRasterView];
158
159    [fGLContext makeCurrentContext];
160
161    glClearStencil(0);
162    glClearColor(0, 0, 0, 0);
163    glStencilMask(0xffffffff);
164    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
165
166    GLint stencilBits;
167    [fPixelFormat getValues:&stencilBits forAttribute:NSOpenGLPFAStencilSize forVirtualScreen:0];
168    fStencilBits = stencilBits;
169    GLint sampleCount;
170    [fPixelFormat getValues:&sampleCount forAttribute:NSOpenGLPFASamples forVirtualScreen:0];
171    fSampleCount = sampleCount;
172    fSampleCount = SkTMax(fSampleCount, 1);
173
174    const NSRect viewportRect = [fMainView bounds];
175    fWidth = viewportRect.size.width;
176    fHeight = viewportRect.size.height;
177    glViewport(0, 0, fWidth, fHeight);
178
179    // make the offscreen image
180    SkImageInfo info = SkImageInfo::Make(fWidth, fHeight, fDisplayParams.fColorType,
181                                         kPremul_SkAlphaType, fDisplayParams.fColorSpace);
182    fBackbufferSurface = SkSurface::MakeRaster(info);
183    return GrGLMakeNativeInterface();
184}
185
186void RasterWindowContext_mac::onDestroyContext() {
187    fBackbufferSurface.reset(nullptr);
188
189    [fRasterView removeFromSuperview];
190    [fRasterView release];
191    fRasterView = nil;
192    [fGLContext release];
193    fGLContext = nil;
194    [fPixelFormat release];
195    fPixelFormat = nil;
196}
197
198sk_sp<SkSurface> RasterWindowContext_mac::getBackbufferSurface() { return fBackbufferSurface; }
199
200void RasterWindowContext_mac::onSwapBuffers() {
201    if (fBackbufferSurface) {
202        // We made/have an off-screen surface. Get the contents as an SkImage:
203        sk_sp<SkImage> snapshot = fBackbufferSurface->makeImageSnapshot();
204
205        sk_sp<SkSurface> gpuSurface = INHERITED::getBackbufferSurface();
206        SkCanvas* gpuCanvas = gpuSurface->getCanvas();
207        gpuCanvas->drawImage(snapshot, 0, 0);
208        gpuCanvas->flush();
209
210        [fGLContext flushBuffer];
211    }
212}
213
214}  // anonymous namespace
215
216namespace sk_app {
217namespace window_context_factory {
218
219WindowContext* NewRasterForMac(const MacWindowInfo& info, const DisplayParams& params) {
220    WindowContext* ctx = new RasterWindowContext_mac(info, params);
221    if (!ctx->isValid()) {
222        delete ctx;
223        return nullptr;
224    }
225    return ctx;
226}
227
228}  // namespace window_context_factory
229}  // namespace sk_app
230