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 "tools/window/MetalWindowContext.h" 9 10#include "include/core/SkCanvas.h" 11#include "include/core/SkSurface.h" 12#include "include/gpu/GrBackendSurface.h" 13#include "include/gpu/GrDirectContext.h" 14#include "include/gpu/ganesh/SkSurfaceGanesh.h" 15#include "include/gpu/ganesh/mtl/GrMtlBackendContext.h" 16#include "include/gpu/ganesh/mtl/GrMtlBackendSurface.h" 17#include "include/gpu/ganesh/mtl/GrMtlDirectContext.h" 18#include "include/gpu/ganesh/mtl/GrMtlTypes.h" 19#include "include/gpu/ganesh/mtl/SkSurfaceMetal.h" 20#include "src/base/SkMathPriv.h" 21#include "src/gpu/ganesh/GrCaps.h" 22#include "src/gpu/ganesh/GrDirectContextPriv.h" 23#include "src/image/SkImage_Base.h" 24 25using skwindow::DisplayParams; 26using skwindow::internal::MetalWindowContext; 27 28namespace skwindow::internal { 29 30MetalWindowContext::MetalWindowContext(const DisplayParams& params) 31 : WindowContext(params) 32 , fValid(false) 33 , fDrawableHandle(nil) { 34 fDisplayParams.fMSAASampleCount = GrNextPow2(fDisplayParams.fMSAASampleCount); 35} 36 37void MetalWindowContext::initializeContext() { 38 SkASSERT(!fContext); 39 40 fDevice.reset(MTLCreateSystemDefaultDevice()); 41 fQueue.reset([*fDevice newCommandQueue]); 42 43 if (fDisplayParams.fMSAASampleCount > 1) { 44 if (@available(macOS 10.11, iOS 9.0, tvOS 9.0, *)) { 45 if (![*fDevice supportsTextureSampleCount:fDisplayParams.fMSAASampleCount]) { 46 return; 47 } 48 } else { 49 return; 50 } 51 } 52 fSampleCount = fDisplayParams.fMSAASampleCount; 53 fStencilBits = 8; 54 55 fValid = this->onInitializeContext(); 56 57 GrMtlBackendContext backendContext = {}; 58 backendContext.fDevice.retain((GrMTLHandle)fDevice.get()); 59 backendContext.fQueue.retain((GrMTLHandle)fQueue.get()); 60 fContext = GrDirectContexts::MakeMetal(backendContext, fDisplayParams.fGrContextOptions); 61 if (!fContext && fDisplayParams.fMSAASampleCount > 1) { 62 fDisplayParams.fMSAASampleCount /= 2; 63 this->initializeContext(); 64 return; 65 } 66} 67 68void MetalWindowContext::destroyContext() { 69 if (fContext) { 70 // in case we have outstanding refs to this (lua?) 71 fContext->abandonContext(); 72 fContext.reset(); 73 } 74 75 this->onDestroyContext(); 76 77 fMetalLayer = nil; 78 fValid = false; 79 80 fQueue.reset(); 81 fDevice.reset(); 82} 83 84sk_sp<SkSurface> MetalWindowContext::getBackbufferSurface() { 85 sk_sp<SkSurface> surface; 86 if (fContext) { 87 if (fDisplayParams.fDelayDrawableAcquisition) { 88 surface = SkSurfaces::WrapCAMetalLayer(fContext.get(), 89 (__bridge GrMTLHandle)fMetalLayer, 90 kTopLeft_GrSurfaceOrigin, 91 fSampleCount, 92 kBGRA_8888_SkColorType, 93 fDisplayParams.fColorSpace, 94 &fDisplayParams.fSurfaceProps, 95 &fDrawableHandle); 96 } else { 97 id<CAMetalDrawable> currentDrawable = [fMetalLayer nextDrawable]; 98 if (currentDrawable == nil) { 99 return nullptr; 100 } 101 102 GrMtlTextureInfo fbInfo; 103 fbInfo.fTexture.retain(currentDrawable.texture); 104 105 GrBackendRenderTarget backendRT = 106 GrBackendRenderTargets::MakeMtl(fWidth, fHeight, fbInfo); 107 108 surface = SkSurfaces::WrapBackendRenderTarget(fContext.get(), 109 backendRT, 110 kTopLeft_GrSurfaceOrigin, 111 kBGRA_8888_SkColorType, 112 fDisplayParams.fColorSpace, 113 &fDisplayParams.fSurfaceProps); 114 115 fDrawableHandle = CFRetain((GrMTLHandle) currentDrawable); 116 } 117 } 118 119 return surface; 120} 121 122void MetalWindowContext::onSwapBuffers() { 123 id<CAMetalDrawable> currentDrawable = (id<CAMetalDrawable>)fDrawableHandle; 124 125 id<MTLCommandBuffer> commandBuffer([*fQueue commandBuffer]); 126 commandBuffer.label = @"Present"; 127 128 [commandBuffer presentDrawable:currentDrawable]; 129 [commandBuffer commit]; 130 // ARC is off in sk_app, so we need to release the CF ref manually 131 CFRelease(fDrawableHandle); 132 fDrawableHandle = nil; 133} 134 135void MetalWindowContext::setDisplayParams(const DisplayParams& params) { 136 this->destroyContext(); 137 fDisplayParams = params; 138 this->initializeContext(); 139} 140 141} //namespace skwindow::internal 142