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