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