1/* 2 * Copyright 2021 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/GraphiteNativeMetalWindowContext.h" 9 10#include "include/core/SkSurface.h" 11#include "include/gpu/graphite/BackendTexture.h" 12#include "include/gpu/graphite/Context.h" 13#include "include/gpu/graphite/ContextOptions.h" 14#include "include/gpu/graphite/Recorder.h" 15#include "include/gpu/graphite/Recording.h" 16#include "include/gpu/graphite/Surface.h" 17#include "include/gpu/graphite/mtl/MtlBackendContext.h" 18#include "include/gpu/graphite/mtl/MtlGraphiteTypes.h" 19#include "src/base/SkMathPriv.h" 20#include "src/gpu/graphite/ContextOptionsPriv.h" 21#include "tools/graphite/GraphiteToolUtils.h" 22#include "tools/graphite/TestOptions.h" 23#include "tools/window/GraphiteDisplayParams.h" 24 25using skwindow::DisplayParams; 26using skwindow::internal::GraphiteMetalWindowContext; 27 28namespace skwindow::internal { 29 30GraphiteMetalWindowContext::GraphiteMetalWindowContext(std::unique_ptr<const DisplayParams> params) 31 : WindowContext(DisplayParamsBuilder(params.get()).roundUpMSAA().build()) 32 , fValid(false) 33 , fDrawableHandle(nil) {} 34 35void GraphiteMetalWindowContext::initializeContext() { 36 SkASSERT(!fContext); 37 SkASSERT(!fGraphiteContext); 38 39 fDevice.reset(MTLCreateSystemDefaultDevice()); 40 fQueue.reset([*fDevice newCommandQueue]); 41 42 if (fDisplayParams->msaaSampleCount() > 1) { 43 if (@available(macOS 10.11, iOS 9.0, tvOS 9.0, *)) { 44 if (![*fDevice supportsTextureSampleCount:fDisplayParams->msaaSampleCount()]) { 45 return; 46 } 47 } else { 48 return; 49 } 50 } 51 fSampleCount = fDisplayParams->msaaSampleCount(); 52 fStencilBits = 8; 53 54 fValid = this->onInitializeContext(); 55 56 skgpu::graphite::MtlBackendContext backendContext = {}; 57 backendContext.fDevice.retain((CFTypeRef)fDevice.get()); 58 backendContext.fQueue.retain((CFTypeRef)fQueue.get()); 59 60 SkASSERT(fDisplayParams->graphiteTestOptions()); 61 skwindow::GraphiteTestOptions opts = *fDisplayParams->graphiteTestOptions(); 62 63 opts.fTestOptions.fContextOptions.fRequireOrderedRecordings = true; 64 // Needed to make synchronous readPixels work: 65 opts.fPriv.fStoreContextRefInRecorder = true; 66 fDisplayParams = 67 GraphiteDisplayParamsBuilder(fDisplayParams.get()).graphiteTestOptions(opts).build(); 68 fGraphiteContext = skgpu::graphite::ContextFactory::MakeMetal( 69 backendContext, fDisplayParams->graphiteTestOptions()->fTestOptions.fContextOptions); 70 fGraphiteRecorder = fGraphiteContext->makeRecorder(ToolUtils::CreateTestingRecorderOptions()); 71 // TODO 72 // if (!fGraphiteContext && fDisplayParams->msaaSampleCount() > 1) { 73 // fDisplayParams->msaaSampleCount() /= 2; 74 // this->initializeContext(); 75 // return; 76 // } 77} 78 79void GraphiteMetalWindowContext::destroyContext() { 80 if (fGraphiteContext) { 81 fGraphiteRecorder.reset(); 82 fGraphiteContext.reset(); 83 } 84 85 this->onDestroyContext(); 86 87 fMetalLayer = nil; 88 fValid = false; 89 90 fQueue.reset(); 91 fDevice.reset(); 92} 93 94sk_sp<SkSurface> GraphiteMetalWindowContext::getBackbufferSurface() { 95 sk_sp<SkSurface> surface; 96 id<CAMetalDrawable> currentDrawable = [fMetalLayer nextDrawable]; 97 if (currentDrawable == nil) { 98 return nullptr; 99 } 100 101 auto backendTex = skgpu::graphite::BackendTextures::MakeMetal( 102 this->dimensions(), (CFTypeRef)currentDrawable.texture); 103 104 surface = SkSurfaces::WrapBackendTexture(this->graphiteRecorder(), 105 backendTex, 106 kBGRA_8888_SkColorType, 107 fDisplayParams->colorSpace(), 108 &fDisplayParams->surfaceProps()); 109 fDrawableHandle = CFRetain((CFTypeRef)currentDrawable); 110 111 return surface; 112} 113 114void GraphiteMetalWindowContext::onSwapBuffers() { 115 this->submitToGpu(); 116 117 id<CAMetalDrawable> currentDrawable = (id<CAMetalDrawable>)fDrawableHandle; 118 119 id<MTLCommandBuffer> commandBuffer([*fQueue commandBuffer]); 120 commandBuffer.label = @"Present"; 121 122 [commandBuffer presentDrawable:currentDrawable]; 123 [commandBuffer commit]; 124 // ARC is off in sk_app, so we need to release the CF ref manually 125 CFRelease(fDrawableHandle); 126 fDrawableHandle = nil; 127} 128 129void GraphiteMetalWindowContext::setDisplayParams(std::unique_ptr<const DisplayParams> params) { 130 this->destroyContext(); 131 fDisplayParams = std::move(params); 132 this->initializeContext(); 133} 134 135void GraphiteMetalWindowContext::activate(bool isActive) {} 136 137} // namespace skwindow::internal 138