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 "include/gpu/gl/GrGLInterface.h" 10#include "tools/sk_app/GLWindowContext.h" 11#include "tools/sk_app/mac/WindowContextFactory_mac.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 33 void resize(int w, int h) override; 34 35private: 36 NSView* fMainView; 37 NSOpenGLContext* fGLContext; 38 NSOpenGLPixelFormat* fPixelFormat; 39 40 typedef GLWindowContext INHERITED; 41}; 42 43GLWindowContext_mac::GLWindowContext_mac(const MacWindowInfo& info, const DisplayParams& params) 44 : INHERITED(params) 45 , fMainView(info.fMainView) 46 , fGLContext(nil) { 47 48 // any config code here (particularly for msaa)? 49 50 this->initializeContext(); 51} 52 53GLWindowContext_mac::~GLWindowContext_mac() { 54 [fPixelFormat release]; 55 fPixelFormat = nil; 56 [fGLContext release]; 57 fGLContext = nil; 58} 59 60sk_sp<const GrGLInterface> GLWindowContext_mac::onInitializeContext() { 61 SkASSERT(nil != fMainView); 62 63 if (!fGLContext) { 64 // set up pixel format 65 constexpr int kMaxAttributes = 18; 66 NSOpenGLPixelFormatAttribute attributes[kMaxAttributes]; 67 int numAttributes = 0; 68 attributes[numAttributes++] = NSOpenGLPFAAccelerated; 69 attributes[numAttributes++] = NSOpenGLPFAClosestPolicy; 70 attributes[numAttributes++] = NSOpenGLPFADoubleBuffer; 71 attributes[numAttributes++] = NSOpenGLPFAOpenGLProfile; 72 attributes[numAttributes++] = NSOpenGLProfileVersion3_2Core; 73 attributes[numAttributes++] = NSOpenGLPFAColorSize; 74 attributes[numAttributes++] = 24; 75 attributes[numAttributes++] = NSOpenGLPFAAlphaSize; 76 attributes[numAttributes++] = 8; 77 attributes[numAttributes++] = NSOpenGLPFADepthSize; 78 attributes[numAttributes++] = 0; 79 attributes[numAttributes++] = NSOpenGLPFAStencilSize; 80 attributes[numAttributes++] = 8; 81 if (fDisplayParams.fMSAASampleCount > 1) { 82 attributes[numAttributes++] = NSOpenGLPFASampleBuffers; 83 attributes[numAttributes++] = 1; 84 attributes[numAttributes++] = NSOpenGLPFASamples; 85 attributes[numAttributes++] = fDisplayParams.fMSAASampleCount; 86 } else { 87 attributes[numAttributes++] = NSOpenGLPFASampleBuffers; 88 attributes[numAttributes++] = 0; 89 } 90 attributes[numAttributes++] = 0; 91 SkASSERT(numAttributes <= kMaxAttributes); 92 93 fPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; 94 if (nil == fPixelFormat) { 95 return nullptr; 96 } 97 98 // create context 99 fGLContext = [[NSOpenGLContext alloc] initWithFormat:fPixelFormat shareContext:nil]; 100 if (nil == fGLContext) { 101 [fPixelFormat release]; 102 fPixelFormat = nil; 103 return nullptr; 104 } 105 106 // TODO: support Retina displays 107 [fMainView setWantsBestResolutionOpenGLSurface:NO]; 108 [fGLContext setView:fMainView]; 109 } 110 111 GLint swapInterval = fDisplayParams.fDisableVsync ? 0 : 1; 112 [fGLContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; 113 114 // make context current 115 [fGLContext makeCurrentContext]; 116 117 glClearStencil(0); 118 glClearColor(0, 0, 0, 255); 119 glStencilMask(0xffffffff); 120 glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 121 122 GLint stencilBits; 123 [fPixelFormat getValues:&stencilBits forAttribute:NSOpenGLPFAStencilSize forVirtualScreen:0]; 124 fStencilBits = stencilBits; 125 GLint sampleCount; 126 [fPixelFormat getValues:&sampleCount forAttribute:NSOpenGLPFASamples forVirtualScreen:0]; 127 fSampleCount = sampleCount; 128 fSampleCount = SkTMax(fSampleCount, 1); 129 130 const NSRect viewportRect = [fMainView frame]; 131 fWidth = viewportRect.size.width; 132 fHeight = viewportRect.size.height; 133 134 glViewport(0, 0, fWidth, fHeight); 135 136 return GrGLMakeNativeInterface(); 137} 138 139void GLWindowContext_mac::onDestroyContext() { 140 // We only need to tear down the GLContext if we've changed the sample count. 141 if (fGLContext && fSampleCount != fDisplayParams.fMSAASampleCount) { 142 [fPixelFormat release]; 143 fPixelFormat = nil; 144 [fGLContext release]; 145 fGLContext = nil; 146 } 147} 148 149void GLWindowContext_mac::onSwapBuffers() { 150 [fGLContext flushBuffer]; 151} 152 153void GLWindowContext_mac::resize(int w, int h) { 154 [fGLContext update]; 155 INHERITED::resize(w, h); 156} 157 158 159} // anonymous namespace 160 161namespace sk_app { 162namespace window_context_factory { 163 164std::unique_ptr<WindowContext> MakeGLForMac(const MacWindowInfo& info, 165 const DisplayParams& params) { 166 std::unique_ptr<WindowContext> ctx(new GLWindowContext_mac(info, params)); 167 if (!ctx->isValid()) { 168 return nullptr; 169 } 170 return ctx; 171} 172 173} // namespace window_context_factory 174} // namespace sk_app 175