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 "include/gpu/ganesh/SkSurfaceGanesh.h" 13#include "tools/ToolUtils.h" 14#include "tools/window/GLWindowContext.h" 15#include "tools/window/mac/WindowContextFactory_mac.h" 16#include "include/gpu/ganesh/gl/mac/GrGLMakeMacInterface.h" 17 18#include <OpenGL/gl.h> 19 20#include <Cocoa/Cocoa.h> 21 22using skwindow::DisplayParams; 23using skwindow::MacWindowInfo; 24using skwindow::internal::GLWindowContext; 25 26namespace { 27 28// TODO: This still uses GL to handle the update rather than using a purely raster backend, 29// for historical reasons. Writing a pure raster backend would be better in the long run. 30 31class RasterWindowContext_mac : public GLWindowContext { 32public: 33 RasterWindowContext_mac(const MacWindowInfo&, const DisplayParams&); 34 35 ~RasterWindowContext_mac() override; 36 37 sk_sp<SkSurface> getBackbufferSurface() 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 void onSwapBuffers() override; 46 47 NSView* fMainView; 48 NSOpenGLContext* fGLContext; 49 NSOpenGLPixelFormat* fPixelFormat; 50 sk_sp<SkSurface> fBackbufferSurface; 51}; 52 53RasterWindowContext_mac::RasterWindowContext_mac(const MacWindowInfo& info, 54 const DisplayParams& params) 55 : GLWindowContext(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 = skwindow::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 = SkSurfaces::Raster(info); 150 return GrGLInterfaces::MakeMac(); 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 = GLWindowContext::getBackbufferSurface(); 161 SkCanvas* gpuCanvas = gpuSurface->getCanvas(); 162 gpuCanvas->drawImage(snapshot, 0, 0); 163 skgpu::ganesh::Flush(gpuSurface); 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 GLWindowContext::resize(0, 0); 174} 175 176} // anonymous namespace 177 178namespace skwindow { 179 180std::unique_ptr<WindowContext> MakeRasterForMac(const MacWindowInfo& info, 181 const DisplayParams& params) { 182 std::unique_ptr<WindowContext> ctx(new RasterWindowContext_mac(info, params)); 183 if (!ctx->isValid()) { 184 return nullptr; 185 } 186 return ctx; 187} 188 189} // namespace skwindow 190