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