1/* 2 * Copyright 2019 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "include/core/SkCanvas.h" 9#include "include/core/SkSurface.h" 10#include "include/gpu/GrBackendSurface.h" 11#include "include/gpu/GrContext.h" 12#include "include/gpu/mtl/GrMtlTypes.h" 13#include "src/core/SkMathPriv.h" 14#include "src/gpu/GrCaps.h" 15#include "src/gpu/GrContextPriv.h" 16#include "src/image/SkImage_Base.h" 17#include "tools/sk_app/MetalWindowContext.h" 18 19using sk_app::DisplayParams; 20using sk_app::MetalWindowContext; 21 22namespace sk_app { 23 24MetalWindowContext::MetalWindowContext(const DisplayParams& params) 25 : WindowContext(params) 26 , fValid(false) { 27 28 fDisplayParams.fMSAASampleCount = GrNextPow2(fDisplayParams.fMSAASampleCount); 29} 30 31void MetalWindowContext::initializeContext() { 32 SkASSERT(!fContext); 33 34 fDevice = MTLCreateSystemDefaultDevice(); 35 fQueue = [fDevice newCommandQueue]; 36 37 if (fDisplayParams.fMSAASampleCount > 1) { 38 if (![fDevice supportsTextureSampleCount:fDisplayParams.fMSAASampleCount]) { 39 return; 40 } 41 } 42 fSampleCount = fDisplayParams.fMSAASampleCount; 43 fStencilBits = 8; 44 45 fMetalLayer = [CAMetalLayer layer]; 46 fMetalLayer.device = fDevice; 47 fMetalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm; 48 49 fValid = this->onInitializeContext(); 50 51 fContext = GrContext::MakeMetal((__bridge void*)fDevice, (__bridge void*)fQueue, 52 fDisplayParams.fGrContextOptions); 53 if (!fContext && fDisplayParams.fMSAASampleCount > 1) { 54 fDisplayParams.fMSAASampleCount /= 2; 55 this->initializeContext(); 56 return; 57 } 58} 59 60void MetalWindowContext::destroyContext() { 61 if (fContext) { 62 // in case we have outstanding refs to this guy (lua?) 63 fContext->abandonContext(); 64 fContext.reset(); 65 } 66 67 this->onDestroyContext(); 68 69 fMetalLayer = nil; 70 fValid = false; 71 72 [fQueue release]; 73 [fDevice release]; 74} 75 76sk_sp<SkSurface> MetalWindowContext::getBackbufferSurface() { 77 sk_sp<SkSurface> surface; 78 if (fContext) { 79 // TODO: Apple recommends grabbing the drawable (which we're implicitly doing here) 80 // for as little time as possible. I'm not sure it matters for our test apps, but 81 // you can get better throughput by doing any offscreen renders, texture uploads, or 82 // other non-dependant tasks first before grabbing the drawable. 83 fCurrentDrawable = [fMetalLayer nextDrawable]; 84 85 GrMtlTextureInfo fbInfo; 86 fbInfo.fTexture.retain((__bridge const void*)(fCurrentDrawable.texture)); 87 88 if (fSampleCount == 1) { 89 GrBackendRenderTarget backendRT(fWidth, 90 fHeight, 91 fSampleCount, 92 fbInfo); 93 94 surface = SkSurface::MakeFromBackendRenderTarget(fContext.get(), backendRT, 95 kTopLeft_GrSurfaceOrigin, 96 kBGRA_8888_SkColorType, 97 fDisplayParams.fColorSpace, 98 &fDisplayParams.fSurfaceProps); 99 } else { 100 GrBackendTexture backendTexture(fWidth, 101 fHeight, 102 GrMipMapped::kNo, 103 fbInfo); 104 105 surface = SkSurface::MakeFromBackendTexture( 106 fContext.get(), backendTexture, kTopLeft_GrSurfaceOrigin, fSampleCount, 107 kBGRA_8888_SkColorType, fDisplayParams.fColorSpace, 108 &fDisplayParams.fSurfaceProps); 109 } 110 } 111 112 return surface; 113} 114 115void MetalWindowContext::swapBuffers() { 116 id<MTLCommandBuffer> commandBuffer = [fQueue commandBuffer]; 117 commandBuffer.label = @"Present"; 118 119 [commandBuffer presentDrawable:fCurrentDrawable]; 120 [commandBuffer commit]; 121 fCurrentDrawable = nil; 122} 123 124void MetalWindowContext::setDisplayParams(const DisplayParams& params) { 125 this->destroyContext(); 126 fDisplayParams = params; 127 this->initializeContext(); 128} 129 130} //namespace sk_app 131