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/core/SkCanvas.h" 10#include "include/core/SkColorFilter.h" 11#include "include/gpu/gl/GrGLInterface.h" 12#include "tools/ToolUtils.h" 13#include "tools/sk_app/GLWindowContext.h" 14#include "tools/sk_app/mac/WindowContextFactory_mac.h" 15 16#include <OpenGL/gl.h> 17 18#include <Cocoa/Cocoa.h> 19 20using sk_app::DisplayParams; 21using sk_app::window_context_factory::MacWindowInfo; 22using sk_app::GLWindowContext; 23 24namespace { 25 26// TODO: This still uses GL to handle the update rather than using a purely raster backend, 27// for historical reasons. Writing a pure raster backend would be better in the long run. 28 29class RasterWindowContext_mac : public GLWindowContext { 30public: 31 RasterWindowContext_mac(const MacWindowInfo&, const DisplayParams&); 32 33 ~RasterWindowContext_mac() override; 34 35 sk_sp<SkSurface> getBackbufferSurface() override; 36 37 void onSwapBuffers() override; 38 39 sk_sp<const GrGLInterface> onInitializeContext() override; 40 void onDestroyContext() override {} 41 42 void resize(int w, int h) override; 43 44private: 45 NSView* fMainView; 46 NSOpenGLContext* fGLContext; 47 NSOpenGLPixelFormat* fPixelFormat; 48 sk_sp<SkSurface> fBackbufferSurface; 49 50 using INHERITED = GLWindowContext; 51}; 52 53RasterWindowContext_mac::RasterWindowContext_mac(const MacWindowInfo& info, 54 const DisplayParams& params) 55 : INHERITED(params) 56 , fMainView(info.fMainView) 57 , fGLContext(nil) { 58 59 // any config code here (particularly for msaa)? 60 61 this->initializeContext(); 62} 63 64RasterWindowContext_mac::~RasterWindowContext_mac() { 65 [NSOpenGLContext clearCurrentContext]; 66 [fPixelFormat release]; 67 fPixelFormat = nil; 68 [fGLContext release]; 69 fGLContext = nil; 70} 71 72sk_sp<const GrGLInterface> RasterWindowContext_mac::onInitializeContext() { 73 SkASSERT(nil != fMainView); 74 75 if (!fGLContext) { 76 // set up pixel format 77 constexpr int kMaxAttributes = 18; 78 NSOpenGLPixelFormatAttribute attributes[kMaxAttributes]; 79 int numAttributes = 0; 80 attributes[numAttributes++] = NSOpenGLPFAAccelerated; 81 attributes[numAttributes++] = NSOpenGLPFAClosestPolicy; 82 attributes[numAttributes++] = NSOpenGLPFADoubleBuffer; 83 attributes[numAttributes++] = NSOpenGLPFAOpenGLProfile; 84 attributes[numAttributes++] = NSOpenGLProfileVersion3_2Core; 85 attributes[numAttributes++] = NSOpenGLPFAColorSize; 86 attributes[numAttributes++] = 24; 87 attributes[numAttributes++] = NSOpenGLPFAAlphaSize; 88 attributes[numAttributes++] = 8; 89 attributes[numAttributes++] = NSOpenGLPFADepthSize; 90 attributes[numAttributes++] = 0; 91 attributes[numAttributes++] = NSOpenGLPFAStencilSize; 92 attributes[numAttributes++] = 8; 93 if (fDisplayParams.fMSAASampleCount > 1) { 94 attributes[numAttributes++] = NSOpenGLPFASampleBuffers; 95 attributes[numAttributes++] = 1; 96 attributes[numAttributes++] = NSOpenGLPFASamples; 97 attributes[numAttributes++] = fDisplayParams.fMSAASampleCount; 98 } else { 99 attributes[numAttributes++] = NSOpenGLPFASampleBuffers; 100 attributes[numAttributes++] = 0; 101 } 102 attributes[numAttributes++] = 0; 103 SkASSERT(numAttributes <= kMaxAttributes); 104 105 fPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; 106 if (nil == fPixelFormat) { 107 return nullptr; 108 } 109 110 // create context 111 fGLContext = [[NSOpenGLContext alloc] initWithFormat:fPixelFormat shareContext:nil]; 112 if (nil == fGLContext) { 113 [fPixelFormat release]; 114 fPixelFormat = nil; 115 return nullptr; 116 } 117 118 [fMainView setWantsBestResolutionOpenGLSurface:YES]; 119 [fGLContext setView:fMainView]; 120 121 GLint swapInterval = fDisplayParams.fDisableVsync ? 0 : 1; 122 [fGLContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; 123 } 124 125 // make context current 126 [fGLContext makeCurrentContext]; 127 128 glClearStencil(0); 129 glClearColor(0, 0, 0, 255); 130 glStencilMask(0xffffffff); 131 glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 132 133 GLint stencilBits; 134 [fPixelFormat getValues:&stencilBits forAttribute:NSOpenGLPFAStencilSize forVirtualScreen:0]; 135 fStencilBits = stencilBits; 136 GLint sampleCount; 137 [fPixelFormat getValues:&sampleCount forAttribute:NSOpenGLPFASamples forVirtualScreen:0]; 138 fSampleCount = sampleCount; 139 fSampleCount = std::max(fSampleCount, 1); 140 141 CGFloat backingScaleFactor = sk_app::GetBackingScaleFactor(fMainView); 142 fWidth = fMainView.bounds.size.width * backingScaleFactor; 143 fHeight = fMainView.bounds.size.height * backingScaleFactor; 144 glViewport(0, 0, fWidth, fHeight); 145 146 // make the offscreen image 147 SkImageInfo info = SkImageInfo::Make(fWidth, fHeight, fDisplayParams.fColorType, 148 kPremul_SkAlphaType, fDisplayParams.fColorSpace); 149 fBackbufferSurface = SkSurface::MakeRaster(info); 150 return GrGLMakeNativeInterface(); 151} 152 153sk_sp<SkSurface> RasterWindowContext_mac::getBackbufferSurface() { return fBackbufferSurface; } 154 155void RasterWindowContext_mac::onSwapBuffers() { 156 if (fBackbufferSurface) { 157 // We made/have an off-screen surface. Get the contents as an SkImage: 158 sk_sp<SkImage> snapshot = fBackbufferSurface->makeImageSnapshot(); 159 160 sk_sp<SkSurface> gpuSurface = INHERITED::getBackbufferSurface(); 161 SkCanvas* gpuCanvas = gpuSurface->getCanvas(); 162 gpuCanvas->drawImage(snapshot, 0, 0); 163 gpuCanvas->flush(); 164 165 [fGLContext flushBuffer]; 166 } 167} 168 169void RasterWindowContext_mac::resize(int w, int h) { 170 [fGLContext update]; 171 172 // The super class always recreates the context. 173 INHERITED::resize(0, 0); 174} 175 176} // anonymous namespace 177 178namespace sk_app { 179namespace window_context_factory { 180 181std::unique_ptr<WindowContext> MakeRasterForMac(const MacWindowInfo& info, 182 const DisplayParams& params) { 183 std::unique_ptr<WindowContext> ctx(new RasterWindowContext_mac(info, params)); 184 if (!ctx->isValid()) { 185 return nullptr; 186 } 187 return ctx; 188} 189 190} // namespace window_context_factory 191} // namespace sk_app 192