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 "MetalWindowContext.h" 10#include "GrBackendSurface.h" 11#include "GrCaps.h" 12#include "GrContext.h" 13#include "GrContextPriv.h" 14#include "SkCanvas.h" 15#include "SkImage_Base.h" 16#include "SkMathPriv.h" 17#include "SkSurface.h" 18#include "mtl/GrMtlTypes.h" 19 20namespace sk_app { 21 22static int kMaxBuffersInFlight = 3; 23 24MetalWindowContext::MetalWindowContext(const DisplayParams& params) 25 : WindowContext(params) 26 , fValid(false) 27 , fSurface(nullptr) { 28 fDisplayParams.fMSAASampleCount = GrNextPow2(fDisplayParams.fMSAASampleCount); 29} 30 31void MetalWindowContext::initializeContext() { 32 SkASSERT(!fContext); 33 34 // The subclass uses these to initialize their view 35 fDevice = MTLCreateSystemDefaultDevice(); 36 fQueue = [fDevice newCommandQueue]; 37 38 fInFlightSemaphore = dispatch_semaphore_create(kMaxBuffersInFlight); 39 40 fValid = this->onInitializeContext(); 41 fContext = GrContext::MakeMetal(fDevice, fQueue, fDisplayParams.fGrContextOptions); 42 if (!fContext && fDisplayParams.fMSAASampleCount > 1) { 43 fDisplayParams.fMSAASampleCount /= 2; 44 this->initializeContext(); 45 return; 46 } 47} 48 49void MetalWindowContext::destroyContext() { 50 fSurface.reset(nullptr); 51 52 if (fContext) { 53 // in case we have outstanding refs to this guy (lua?) 54 fContext->abandonContext(); 55 fContext.reset(); 56 } 57 58 // TODO: Figure out who's releasing this 59 // [fQueue release]; 60 [fDevice release]; 61 62 this->onDestroyContext(); 63} 64 65sk_sp<SkSurface> MetalWindowContext::getBackbufferSurface() { 66 sk_sp<SkSurface> surface; 67 if (fContext) { 68 GrMtlTextureInfo fbInfo; 69 fbInfo.fTexture = [[fMTKView currentDrawable] texture]; 70 71 GrBackendRenderTarget backendRT(fWidth, 72 fHeight, 73 fSampleCount, 74 fbInfo); 75 76 surface = SkSurface::MakeFromBackendRenderTarget(fContext.get(), backendRT, 77 kTopLeft_GrSurfaceOrigin, 78 kBGRA_8888_SkColorType, 79 fDisplayParams.fColorSpace, 80 &fDisplayParams.fSurfaceProps); 81 } 82 83 return surface; 84} 85 86void MetalWindowContext::swapBuffers() { 87 // Block to ensure we don't try to render to a frame that hasn't finished presenting 88 dispatch_semaphore_wait(fInFlightSemaphore, DISPATCH_TIME_FOREVER); 89 90 id<MTLCommandBuffer> commandBuffer = [fQueue commandBuffer]; 91 commandBuffer.label = @"Present"; 92 93 __block dispatch_semaphore_t block_sema = fInFlightSemaphore; 94 [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) 95 { 96 dispatch_semaphore_signal(block_sema); 97 }]; 98 99 id<MTLDrawable> drawable = [fMTKView currentDrawable]; 100 [commandBuffer presentDrawable:drawable]; 101 [commandBuffer commit]; 102} 103 104void MetalWindowContext::resize(int w, int h) { 105 this->destroyContext(); 106 this->initializeContext(); 107} 108 109void MetalWindowContext::setDisplayParams(const DisplayParams& params) { 110 this->destroyContext(); 111 fDisplayParams = params; 112 this->initializeContext(); 113} 114 115} //namespace sk_app 116