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 "WindowContextFactory_mac.h"
11#include "gl/GrGLInterface.h"
12
13#include <OpenGL/gl.h>
14#include <Cocoa/Cocoa.h>
15
16using sk_app::DisplayParams;
17using sk_app::window_context_factory::MacWindowInfo;
18using sk_app::GLWindowContext;
19
20@interface GLView : NSOpenGLView
21@end
22
23@implementation GLView
24
25- (void)drawRect:(NSRect)dirtyRect {
26    // not sure why the parent isn't getting this, but we'll pass it up
27    [[self superview] drawRect:dirtyRect];
28}
29
30@end
31
32namespace {
33
34class GLWindowContext_mac : public GLWindowContext {
35public:
36    GLWindowContext_mac(const MacWindowInfo&, const DisplayParams&);
37
38    ~GLWindowContext_mac() override;
39
40    void onSwapBuffers() override;
41
42    sk_sp<const GrGLInterface> onInitializeContext() override;
43    void onDestroyContext() override;
44
45private:
46    NSView*              fMainView;
47    GLView*              fGLView;
48    NSOpenGLContext*     fGLContext;
49    NSOpenGLPixelFormat* fPixelFormat;
50
51    typedef GLWindowContext INHERITED;
52};
53
54GLWindowContext_mac::GLWindowContext_mac(const MacWindowInfo& info, const DisplayParams& params)
55    : INHERITED(params)
56    , fMainView(info.fMainView) {
57
58    // any config code here (particularly for msaa)?
59
60    this->initializeContext();
61}
62
63GLWindowContext_mac::~GLWindowContext_mac() {
64    this->destroyContext();
65}
66
67sk_sp<const GrGLInterface> GLWindowContext_mac::onInitializeContext() {
68    SkASSERT(nil != fMainView);
69
70    // set up pixel format
71    constexpr int kMaxAttributes = 18;
72    NSOpenGLPixelFormatAttribute attributes[kMaxAttributes];
73    int numAttributes = 0;
74    attributes[numAttributes++] = NSOpenGLPFAAccelerated;
75    attributes[numAttributes++] = NSOpenGLPFAClosestPolicy;
76    attributes[numAttributes++] = NSOpenGLPFADoubleBuffer;
77    attributes[numAttributes++] = NSOpenGLPFAOpenGLProfile;
78    attributes[numAttributes++] = NSOpenGLProfileVersion3_2Core;
79    attributes[numAttributes++] = NSOpenGLPFAColorSize;
80    attributes[numAttributes++] = 24;
81    attributes[numAttributes++] = NSOpenGLPFAAlphaSize;
82    attributes[numAttributes++] = 8;
83    attributes[numAttributes++] = NSOpenGLPFADepthSize;
84    attributes[numAttributes++] = 0;
85    attributes[numAttributes++] = NSOpenGLPFAStencilSize;
86    attributes[numAttributes++] = 8;
87    if (fDisplayParams.fMSAASampleCount > 1) {
88        attributes[numAttributes++] = NSOpenGLPFASampleBuffers;
89        attributes[numAttributes++] = 1;
90        attributes[numAttributes++] = NSOpenGLPFASamples;
91        attributes[numAttributes++] = fDisplayParams.fMSAASampleCount;
92    } else {
93        attributes[numAttributes++] = NSOpenGLPFASampleBuffers;
94        attributes[numAttributes++] = 0;
95    }
96    attributes[numAttributes++] = 0;
97    SkASSERT(numAttributes <= kMaxAttributes);
98
99    fPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
100    if (nil == fPixelFormat) {
101        return nullptr;
102    }
103
104    // create context
105    fGLContext = [[NSOpenGLContext alloc] initWithFormat:fPixelFormat shareContext:nil];
106    if (nil == fGLContext) {
107        [fPixelFormat release];
108        fPixelFormat = nil;
109        return nullptr;
110    }
111
112    // create view
113    NSRect rect = fMainView.bounds;
114    fGLView = [[GLView alloc] initWithFrame:rect];
115    if (nil == fGLView) {
116        [fGLContext release];
117        fGLContext = nil;
118        [fPixelFormat release];
119        fPixelFormat = nil;
120        return nullptr;
121    }
122    [fGLView setTranslatesAutoresizingMaskIntoConstraints:NO];
123
124    // attach OpenGL view to main view
125    [fMainView addSubview:fGLView];
126    NSDictionary *views = NSDictionaryOfVariableBindings(fGLView);
127
128    [fMainView addConstraints:
129     [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[fGLView]|"
130                                             options:0
131                                             metrics:nil
132                                               views:views]];
133
134    [fMainView addConstraints:
135     [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[fGLView]|"
136                                             options:0
137                                             metrics:nil
138                                               views:views]];
139
140    // make context current
141    GLint swapInterval = 1;
142    [fGLContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
143    [fGLView setOpenGLContext:fGLContext];
144    [fGLView setPixelFormat:fPixelFormat];
145    [fGLView setWantsBestResolutionOpenGLSurface:YES];
146    [fGLContext setView:fGLView];
147
148    [fGLContext makeCurrentContext];
149
150    glClearStencil(0);
151    glClearColor(0, 0, 0, 255);
152    glStencilMask(0xffffffff);
153    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
154
155    GLint stencilBits;
156    [fPixelFormat getValues:&stencilBits forAttribute:NSOpenGLPFAStencilSize forVirtualScreen:0];
157    fStencilBits = stencilBits;
158    GLint sampleCount;
159    [fPixelFormat getValues:&sampleCount forAttribute:NSOpenGLPFASamples forVirtualScreen:0];
160    fSampleCount = sampleCount;
161    fSampleCount = SkTMax(fSampleCount, 1);
162
163    const NSRect viewportRect = [fMainView bounds];
164    fWidth = viewportRect.size.width;
165    fHeight = viewportRect.size.height;
166    glViewport(0, 0, fWidth, fHeight);
167
168    return GrGLMakeNativeInterface();
169}
170
171void GLWindowContext_mac::onDestroyContext() {
172    [fGLView removeFromSuperview];
173    [fGLView release];
174    fGLView = nil;
175    [fGLContext release];
176    fGLContext = nil;
177    [fPixelFormat release];
178    fPixelFormat = nil;
179}
180
181void GLWindowContext_mac::onSwapBuffers() {
182    [fGLContext flushBuffer];
183}
184
185}  // anonymous namespace
186
187namespace sk_app {
188namespace window_context_factory {
189
190WindowContext* NewGLForMac(const MacWindowInfo& info, const DisplayParams& params) {
191    WindowContext* ctx = new GLWindowContext_mac(info, params);
192    if (!ctx->isValid()) {
193        delete ctx;
194        return nullptr;
195    }
196    return ctx;
197}
198
199}  // namespace window_context_factory
200}  // namespace sk_app
201