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 typedef GLWindowContext INHERITED; 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 [fPixelFormat release]; 66 fPixelFormat = nil; 67 [fGLContext release]; 68 fGLContext = nil; 69} 70 71sk_sp<const GrGLInterface> RasterWindowContext_mac::onInitializeContext() { 72 SkASSERT(nil != fMainView); 73 74 if (!fGLContext) { 75 // set up pixel format 76 constexpr int kMaxAttributes = 18; 77 NSOpenGLPixelFormatAttribute attributes[kMaxAttributes]; 78 int numAttributes = 0; 79 attributes[numAttributes++] = NSOpenGLPFAAccelerated; 80 attributes[numAttributes++] = NSOpenGLPFAClosestPolicy; 81 attributes[numAttributes++] = NSOpenGLPFADoubleBuffer; 82 attributes[numAttributes++] = NSOpenGLPFAOpenGLProfile; 83 attributes[numAttributes++] = NSOpenGLProfileVersion3_2Core; 84 attributes[numAttributes++] = NSOpenGLPFAColorSize; 85 attributes[numAttributes++] = 24; 86 attributes[numAttributes++] = NSOpenGLPFAAlphaSize; 87 attributes[numAttributes++] = 8; 88 attributes[numAttributes++] = NSOpenGLPFADepthSize; 89 attributes[numAttributes++] = 0; 90 attributes[numAttributes++] = NSOpenGLPFAStencilSize; 91 attributes[numAttributes++] = 8; 92 if (fDisplayParams.fMSAASampleCount > 1) { 93 attributes[numAttributes++] = NSOpenGLPFASampleBuffers; 94 attributes[numAttributes++] = 1; 95 attributes[numAttributes++] = NSOpenGLPFASamples; 96 attributes[numAttributes++] = fDisplayParams.fMSAASampleCount; 97 } else { 98 attributes[numAttributes++] = NSOpenGLPFASampleBuffers; 99 attributes[numAttributes++] = 0; 100 } 101 attributes[numAttributes++] = 0; 102 SkASSERT(numAttributes <= kMaxAttributes); 103 104 fPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; 105 if (nil == fPixelFormat) { 106 return nullptr; 107 } 108 109 // create context 110 fGLContext = [[NSOpenGLContext alloc] initWithFormat:fPixelFormat shareContext:nil]; 111 if (nil == fGLContext) { 112 [fPixelFormat release]; 113 fPixelFormat = nil; 114 return nullptr; 115 } 116 117 [fGLContext setView:fMainView]; 118 119 GLint swapInterval = fDisplayParams.fDisableVsync ? 0 : 1; 120 [fGLContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; 121 } 122 123 // make context current 124 [fGLContext makeCurrentContext]; 125 126 glClearStencil(0); 127 glClearColor(0, 0, 0, 255); 128 glStencilMask(0xffffffff); 129 glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 130 131 GLint stencilBits; 132 [fPixelFormat getValues:&stencilBits forAttribute:NSOpenGLPFAStencilSize forVirtualScreen:0]; 133 fStencilBits = stencilBits; 134 GLint sampleCount; 135 [fPixelFormat getValues:&sampleCount forAttribute:NSOpenGLPFASamples forVirtualScreen:0]; 136 fSampleCount = sampleCount; 137 fSampleCount = SkTMax(fSampleCount, 1); 138 139 const NSRect viewportRect = [fMainView frame]; 140 fWidth = viewportRect.size.width; 141 fHeight = viewportRect.size.height; 142 glViewport(0, 0, fWidth, fHeight); 143 144 // make the offscreen image 145 SkImageInfo info = SkImageInfo::Make(fWidth, fHeight, fDisplayParams.fColorType, 146 kPremul_SkAlphaType, fDisplayParams.fColorSpace); 147 fBackbufferSurface = SkSurface::MakeRaster(info); 148 return GrGLMakeNativeInterface(); 149} 150 151sk_sp<SkSurface> RasterWindowContext_mac::getBackbufferSurface() { return fBackbufferSurface; } 152 153void RasterWindowContext_mac::onSwapBuffers() { 154 if (fBackbufferSurface) { 155 // We made/have an off-screen surface. Get the contents as an SkImage: 156 sk_sp<SkImage> snapshot = fBackbufferSurface->makeImageSnapshot(); 157 158 sk_sp<SkSurface> gpuSurface = INHERITED::getBackbufferSurface(); 159 SkCanvas* gpuCanvas = gpuSurface->getCanvas(); 160 gpuCanvas->drawImage(snapshot, 0, 0); 161 gpuCanvas->flush(); 162 163 [fGLContext flushBuffer]; 164 } 165} 166 167void RasterWindowContext_mac::resize(int w, int h) { 168 [fGLContext update]; 169 INHERITED::resize(w, h); 170} 171 172} // anonymous namespace 173 174namespace sk_app { 175namespace window_context_factory { 176 177std::unique_ptr<WindowContext> MakeRasterForMac(const MacWindowInfo& info, 178 const DisplayParams& params) { 179 std::unique_ptr<WindowContext> ctx(new RasterWindowContext_mac(info, params)); 180 if (!ctx->isValid()) { 181 return nullptr; 182 } 183 return ctx; 184} 185 186} // namespace window_context_factory 187} // namespace sk_app 188