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