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