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 "../GLWindowContext.h" 10#include "SkCanvas.h" 11#include "SkColorFilter.h" 12#include "WindowContextFactory_mac.h" 13#include "gl/GrGLInterface.h" 14#include "sk_tool_utils.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 42private: 43 NSView* fMainView; 44 NSOpenGLView* fRasterView; 45 NSOpenGLContext* fGLContext; 46 NSOpenGLPixelFormat* fPixelFormat; 47 sk_sp<SkSurface> fBackbufferSurface; 48 49 typedef GLWindowContext INHERITED; 50}; 51 52RasterWindowContext_mac::RasterWindowContext_mac(const MacWindowInfo& info, 53 const DisplayParams& params) 54 : INHERITED(params) 55 , fMainView(info.fMainView) { 56 57 // any config code here (particularly for msaa)? 58 59 this->initializeContext(); 60} 61 62RasterWindowContext_mac::~RasterWindowContext_mac() { 63 this->destroyContext(); 64} 65 66sk_sp<const GrGLInterface> RasterWindowContext_mac::onInitializeContext() { 67 SkASSERT(nil != fMainView); 68 69 // set up pixel format 70 constexpr int kMaxAttributes = 18; 71 NSOpenGLPixelFormatAttribute attributes[kMaxAttributes]; 72 int numAttributes = 0; 73 attributes[numAttributes++] = NSOpenGLPFAAccelerated; 74 attributes[numAttributes++] = NSOpenGLPFAClosestPolicy; 75 attributes[numAttributes++] = NSOpenGLPFAOpenGLProfile; 76 attributes[numAttributes++] = NSOpenGLProfileVersion3_2Core; 77 attributes[numAttributes++] = NSOpenGLPFAColorSize; 78 attributes[numAttributes++] = 24; 79 attributes[numAttributes++] = NSOpenGLPFAAlphaSize; 80 attributes[numAttributes++] = 8; 81 attributes[numAttributes++] = NSOpenGLPFADepthSize; 82 attributes[numAttributes++] = 0; 83 attributes[numAttributes++] = NSOpenGLPFAStencilSize; 84 attributes[numAttributes++] = 8; 85 attributes[numAttributes++] = NSOpenGLPFADoubleBuffer; 86 if (fDisplayParams.fMSAASampleCount > 1) { 87 attributes[numAttributes++] = NSOpenGLPFASampleBuffers; 88 attributes[numAttributes++] = 1; 89 attributes[numAttributes++] = NSOpenGLPFASamples; 90 attributes[numAttributes++] = fDisplayParams.fMSAASampleCount; 91 } else { 92 attributes[numAttributes++] = NSOpenGLPFASampleBuffers; 93 attributes[numAttributes++] = 0; 94 } 95 attributes[numAttributes++] = 0; 96 SkASSERT(numAttributes <= kMaxAttributes); 97 98 fPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; 99 if (nil == fPixelFormat) { 100 return nullptr; 101 } 102 103 // create context 104 fGLContext = [[NSOpenGLContext alloc] initWithFormat:fPixelFormat shareContext:nil]; 105 if (nil == fGLContext) { 106 [fPixelFormat release]; 107 fPixelFormat = nil; 108 return nullptr; 109 } 110 111 // create view 112 NSRect rect = fMainView.bounds; 113 fRasterView = [[NSOpenGLView alloc] initWithFrame:rect]; 114 if (nil == fRasterView) { 115 [fGLContext release]; 116 fGLContext = nil; 117 [fPixelFormat release]; 118 fPixelFormat = nil; 119 return nullptr; 120 } 121 [fRasterView setTranslatesAutoresizingMaskIntoConstraints:NO]; 122 123 // attach OpenGL view to main view 124 [fMainView addSubview:fRasterView]; 125 NSDictionary *views = NSDictionaryOfVariableBindings(fRasterView); 126 127 [fMainView addConstraints: 128 [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[fRasterView]|" 129 options:0 130 metrics:nil 131 views:views]]; 132 133 [fMainView addConstraints: 134 [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[fRasterView]|" 135 options:0 136 metrics:nil 137 views:views]]; 138 139 // make context current 140 GLint swapInterval = 1; 141 [fGLContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; 142 [fRasterView setOpenGLContext:fGLContext]; 143 [fRasterView setPixelFormat:fPixelFormat]; 144 // TODO: support Retina displays 145 [fRasterView setWantsBestResolutionOpenGLSurface:NO]; 146 [fGLContext setView:fRasterView]; 147 148 [fGLContext makeCurrentContext]; 149 150 glClearStencil(0); 151 glClearColor(0, 0, 0, 0); 152 glStencilMask(0xffffffff); 153 glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 154 155 GLint stencilBits; 156 [fPixelFormat getValues:&stencilBits forAttribute:NSOpenGLPFAStencilSize forVirtualScreen:0]; 157 fStencilBits = stencilBits; 158 GLint sampleCount; 159 [fPixelFormat getValues:&sampleCount forAttribute:NSOpenGLPFASamples forVirtualScreen:0]; 160 fSampleCount = sampleCount; 161 fSampleCount = SkTMax(fSampleCount, 1); 162 163 const NSRect viewportRect = [fRasterView bounds]; 164 fWidth = viewportRect.size.width; 165 fHeight = viewportRect.size.height; 166 glViewport(0, 0, fWidth, fHeight); 167 168 // make the offscreen image 169 SkImageInfo info = SkImageInfo::Make(fWidth, fHeight, fDisplayParams.fColorType, 170 kPremul_SkAlphaType, fDisplayParams.fColorSpace); 171 fBackbufferSurface = SkSurface::MakeRaster(info); 172 return GrGLMakeNativeInterface(); 173} 174 175void RasterWindowContext_mac::onDestroyContext() { 176 fBackbufferSurface.reset(nullptr); 177 178 [fRasterView removeFromSuperview]; 179 [fRasterView release]; 180 fRasterView = nil; 181 [fGLContext release]; 182 fGLContext = nil; 183 [fPixelFormat release]; 184 fPixelFormat = nil; 185} 186 187sk_sp<SkSurface> RasterWindowContext_mac::getBackbufferSurface() { return fBackbufferSurface; } 188 189void RasterWindowContext_mac::onSwapBuffers() { 190 if (fBackbufferSurface) { 191 // We made/have an off-screen surface. Get the contents as an SkImage: 192 sk_sp<SkImage> snapshot = fBackbufferSurface->makeImageSnapshot(); 193 194 sk_sp<SkSurface> gpuSurface = INHERITED::getBackbufferSurface(); 195 SkCanvas* gpuCanvas = gpuSurface->getCanvas(); 196 gpuCanvas->drawImage(snapshot, 0, 0); 197 gpuCanvas->flush(); 198 199 [fGLContext flushBuffer]; 200 } 201} 202 203} // anonymous namespace 204 205namespace sk_app { 206namespace window_context_factory { 207 208WindowContext* NewRasterForMac(const MacWindowInfo& info, const DisplayParams& params) { 209 WindowContext* ctx = new RasterWindowContext_mac(info, params); 210 if (!ctx->isValid()) { 211 delete ctx; 212 return nullptr; 213 } 214 return ctx; 215} 216 217} // namespace window_context_factory 218} // namespace sk_app 219