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 20 namespace sk_app { 21 22 static int kMaxBuffersInFlight = 3; 23 24 MetalWindowContext::MetalWindowContext(const DisplayParams& params) 25 : WindowContext(params) 26 , fValid(false) 27 , fSurface(nullptr) { 28 fDisplayParams.fMSAASampleCount = GrNextPow2(fDisplayParams.fMSAASampleCount); 29 } 30 31 void 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 49 void 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 65 sk_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 86 void 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 104 void MetalWindowContext::resize(int w, int h) { 105 this->destroyContext(); 106 this->initializeContext(); 107 } 108 109 void MetalWindowContext::setDisplayParams(const DisplayParams& params) { 110 this->destroyContext(); 111 fDisplayParams = params; 112 this->initializeContext(); 113 } 114 115 } //namespace sk_app 116