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