1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2019 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 9cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 10cb93a386Sopenharmony_ci#include "include/gpu/GrBackendSurface.h" 11cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 12cb93a386Sopenharmony_ci#include "include/gpu/mtl/GrMtlBackendContext.h" 13cb93a386Sopenharmony_ci#include "include/gpu/mtl/GrMtlTypes.h" 14cb93a386Sopenharmony_ci#include "src/core/SkMathPriv.h" 15cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h" 16cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 17cb93a386Sopenharmony_ci#include "src/image/SkImage_Base.h" 18cb93a386Sopenharmony_ci#include "tools/sk_app/MetalWindowContext.h" 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_ciusing sk_app::DisplayParams; 21cb93a386Sopenharmony_ciusing sk_app::MetalWindowContext; 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_cinamespace sk_app { 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ciMetalWindowContext::MetalWindowContext(const DisplayParams& params) 26cb93a386Sopenharmony_ci : WindowContext(params) 27cb93a386Sopenharmony_ci , fValid(false) 28cb93a386Sopenharmony_ci , fDrawableHandle(nil) { 29cb93a386Sopenharmony_ci fDisplayParams.fMSAASampleCount = GrNextPow2(fDisplayParams.fMSAASampleCount); 30cb93a386Sopenharmony_ci} 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_ciNSURL* MetalWindowContext::CacheURL() { 33cb93a386Sopenharmony_ci NSArray *paths = [[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory 34cb93a386Sopenharmony_ci inDomains:NSUserDomainMask]; 35cb93a386Sopenharmony_ci NSURL* cachePath = [paths objectAtIndex:0]; 36cb93a386Sopenharmony_ci return [cachePath URLByAppendingPathComponent:@"binaryArchive.metallib"]; 37cb93a386Sopenharmony_ci} 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_civoid MetalWindowContext::initializeContext() { 40cb93a386Sopenharmony_ci SkASSERT(!fContext); 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ci fDevice.reset(MTLCreateSystemDefaultDevice()); 43cb93a386Sopenharmony_ci fQueue.reset([*fDevice newCommandQueue]); 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci if (fDisplayParams.fMSAASampleCount > 1) { 46cb93a386Sopenharmony_ci if (@available(macOS 10.11, iOS 9.0, *)) { 47cb93a386Sopenharmony_ci if (![*fDevice supportsTextureSampleCount:fDisplayParams.fMSAASampleCount]) { 48cb93a386Sopenharmony_ci return; 49cb93a386Sopenharmony_ci } 50cb93a386Sopenharmony_ci } else { 51cb93a386Sopenharmony_ci return; 52cb93a386Sopenharmony_ci } 53cb93a386Sopenharmony_ci } 54cb93a386Sopenharmony_ci fSampleCount = fDisplayParams.fMSAASampleCount; 55cb93a386Sopenharmony_ci fStencilBits = 8; 56cb93a386Sopenharmony_ci 57cb93a386Sopenharmony_ci fValid = this->onInitializeContext(); 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ci#if GR_METAL_SDK_VERSION >= 230 60cb93a386Sopenharmony_ci if (fDisplayParams.fEnableBinaryArchive) { 61cb93a386Sopenharmony_ci if (@available(macOS 11.0, iOS 14.0, *)) { 62cb93a386Sopenharmony_ci sk_cfp<MTLBinaryArchiveDescriptor*> desc([MTLBinaryArchiveDescriptor new]); 63cb93a386Sopenharmony_ci (*desc).url = CacheURL(); // try to load 64cb93a386Sopenharmony_ci NSError* error; 65cb93a386Sopenharmony_ci fPipelineArchive = [*fDevice newBinaryArchiveWithDescriptor:*desc error:&error]; 66cb93a386Sopenharmony_ci if (!fPipelineArchive) { 67cb93a386Sopenharmony_ci (*desc).url = nil; // create new 68cb93a386Sopenharmony_ci fPipelineArchive = [*fDevice newBinaryArchiveWithDescriptor:*desc error:&error]; 69cb93a386Sopenharmony_ci if (!fPipelineArchive) { 70cb93a386Sopenharmony_ci SkDebugf("Error creating MTLBinaryArchive:\n%s\n", 71cb93a386Sopenharmony_ci error.debugDescription.UTF8String); 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci } 74cb93a386Sopenharmony_ci } 75cb93a386Sopenharmony_ci } else { 76cb93a386Sopenharmony_ci if (@available(macOS 11.0, iOS 14.0, *)) { 77cb93a386Sopenharmony_ci fPipelineArchive = nil; 78cb93a386Sopenharmony_ci } 79cb93a386Sopenharmony_ci } 80cb93a386Sopenharmony_ci#endif 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_ci GrMtlBackendContext backendContext = {}; 83cb93a386Sopenharmony_ci backendContext.fDevice.retain((GrMTLHandle)fDevice.get()); 84cb93a386Sopenharmony_ci backendContext.fQueue.retain((GrMTLHandle)fQueue.get()); 85cb93a386Sopenharmony_ci#if GR_METAL_SDK_VERSION >= 230 86cb93a386Sopenharmony_ci if (@available(macOS 11.0, iOS 14.0, *)) { 87cb93a386Sopenharmony_ci backendContext.fBinaryArchive.retain((__bridge GrMTLHandle)fPipelineArchive); 88cb93a386Sopenharmony_ci } 89cb93a386Sopenharmony_ci#endif 90cb93a386Sopenharmony_ci fContext = GrDirectContext::MakeMetal(backendContext, fDisplayParams.fGrContextOptions); 91cb93a386Sopenharmony_ci if (!fContext && fDisplayParams.fMSAASampleCount > 1) { 92cb93a386Sopenharmony_ci fDisplayParams.fMSAASampleCount /= 2; 93cb93a386Sopenharmony_ci this->initializeContext(); 94cb93a386Sopenharmony_ci return; 95cb93a386Sopenharmony_ci } 96cb93a386Sopenharmony_ci} 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_civoid MetalWindowContext::destroyContext() { 99cb93a386Sopenharmony_ci if (fContext) { 100cb93a386Sopenharmony_ci // in case we have outstanding refs to this (lua?) 101cb93a386Sopenharmony_ci fContext->abandonContext(); 102cb93a386Sopenharmony_ci fContext.reset(); 103cb93a386Sopenharmony_ci } 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ci this->onDestroyContext(); 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci fMetalLayer = nil; 108cb93a386Sopenharmony_ci fValid = false; 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci#if GR_METAL_SDK_VERSION >= 230 111cb93a386Sopenharmony_ci if (@available(macOS 11.0, iOS 14.0, *)) { 112cb93a386Sopenharmony_ci [fPipelineArchive release]; 113cb93a386Sopenharmony_ci } 114cb93a386Sopenharmony_ci#endif 115cb93a386Sopenharmony_ci fQueue.reset(); 116cb93a386Sopenharmony_ci fDevice.reset(); 117cb93a386Sopenharmony_ci} 118cb93a386Sopenharmony_ci 119cb93a386Sopenharmony_cisk_sp<SkSurface> MetalWindowContext::getBackbufferSurface() { 120cb93a386Sopenharmony_ci sk_sp<SkSurface> surface; 121cb93a386Sopenharmony_ci if (fContext) { 122cb93a386Sopenharmony_ci if (fDisplayParams.fDelayDrawableAcquisition) { 123cb93a386Sopenharmony_ci surface = SkSurface::MakeFromCAMetalLayer(fContext.get(), 124cb93a386Sopenharmony_ci (__bridge GrMTLHandle)fMetalLayer, 125cb93a386Sopenharmony_ci kTopLeft_GrSurfaceOrigin, fSampleCount, 126cb93a386Sopenharmony_ci kBGRA_8888_SkColorType, 127cb93a386Sopenharmony_ci fDisplayParams.fColorSpace, 128cb93a386Sopenharmony_ci &fDisplayParams.fSurfaceProps, 129cb93a386Sopenharmony_ci &fDrawableHandle); 130cb93a386Sopenharmony_ci } else { 131cb93a386Sopenharmony_ci id<CAMetalDrawable> currentDrawable = [fMetalLayer nextDrawable]; 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci GrMtlTextureInfo fbInfo; 134cb93a386Sopenharmony_ci fbInfo.fTexture.retain(currentDrawable.texture); 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_ci GrBackendRenderTarget backendRT(fWidth, 137cb93a386Sopenharmony_ci fHeight, 138cb93a386Sopenharmony_ci fSampleCount, 139cb93a386Sopenharmony_ci fbInfo); 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_ci surface = SkSurface::MakeFromBackendRenderTarget(fContext.get(), backendRT, 142cb93a386Sopenharmony_ci kTopLeft_GrSurfaceOrigin, 143cb93a386Sopenharmony_ci kBGRA_8888_SkColorType, 144cb93a386Sopenharmony_ci fDisplayParams.fColorSpace, 145cb93a386Sopenharmony_ci &fDisplayParams.fSurfaceProps); 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci fDrawableHandle = CFRetain((GrMTLHandle) currentDrawable); 148cb93a386Sopenharmony_ci } 149cb93a386Sopenharmony_ci } 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_ci return surface; 152cb93a386Sopenharmony_ci} 153cb93a386Sopenharmony_ci 154cb93a386Sopenharmony_civoid MetalWindowContext::swapBuffers() { 155cb93a386Sopenharmony_ci id<CAMetalDrawable> currentDrawable = (id<CAMetalDrawable>)fDrawableHandle; 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci id<MTLCommandBuffer> commandBuffer([*fQueue commandBuffer]); 158cb93a386Sopenharmony_ci commandBuffer.label = @"Present"; 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ci [commandBuffer presentDrawable:currentDrawable]; 161cb93a386Sopenharmony_ci [commandBuffer commit]; 162cb93a386Sopenharmony_ci // ARC is off in sk_app, so we need to release the CF ref manually 163cb93a386Sopenharmony_ci CFRelease(fDrawableHandle); 164cb93a386Sopenharmony_ci fDrawableHandle = nil; 165cb93a386Sopenharmony_ci} 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_civoid MetalWindowContext::setDisplayParams(const DisplayParams& params) { 168cb93a386Sopenharmony_ci this->destroyContext(); 169cb93a386Sopenharmony_ci fDisplayParams = params; 170cb93a386Sopenharmony_ci this->initializeContext(); 171cb93a386Sopenharmony_ci} 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_civoid MetalWindowContext::activate(bool isActive) { 174cb93a386Sopenharmony_ci // serialize pipeline archive 175cb93a386Sopenharmony_ci if (!isActive) { 176cb93a386Sopenharmony_ci#if GR_METAL_SDK_VERSION >= 230 177cb93a386Sopenharmony_ci if (@available(macOS 11.0, iOS 14.0, *)) { 178cb93a386Sopenharmony_ci if (fPipelineArchive) { 179cb93a386Sopenharmony_ci NSError* error; 180cb93a386Sopenharmony_ci [fPipelineArchive serializeToURL:CacheURL() error:&error]; 181cb93a386Sopenharmony_ci if (error) { 182cb93a386Sopenharmony_ci SkDebugf("Error storing MTLBinaryArchive:\n%s\n", 183cb93a386Sopenharmony_ci error.debugDescription.UTF8String); 184cb93a386Sopenharmony_ci } 185cb93a386Sopenharmony_ci } 186cb93a386Sopenharmony_ci } 187cb93a386Sopenharmony_ci#endif 188cb93a386Sopenharmony_ci } 189cb93a386Sopenharmony_ci} 190cb93a386Sopenharmony_ci 191cb93a386Sopenharmony_ci} //namespace sk_app 192