| /* | |
| * Copyright 2021 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "tools/window/GraphiteNativeMetalWindowContext.h" | |
| #include "include/core/SkSurface.h" | |
| #include "include/gpu/graphite/BackendTexture.h" | |
| #include "include/gpu/graphite/Context.h" | |
| #include "include/gpu/graphite/ContextOptions.h" | |
| #include "include/gpu/graphite/Recorder.h" | |
| #include "include/gpu/graphite/Recording.h" | |
| #include "include/gpu/graphite/Surface.h" | |
| #include "include/gpu/graphite/mtl/MtlBackendContext.h" | |
| #include "include/gpu/graphite/mtl/MtlGraphiteTypes.h" | |
| #include "src/core/SkMathPriv.h" | |
| #include "src/gpu/graphite/ContextOptionsPriv.h" | |
| #include "tools/graphite/GraphiteToolUtils.h" | |
| #include "tools/graphite/TestOptions.h" | |
| #include "tools/window/GraphiteDisplayParams.h" | |
| using skwindow::DisplayParams; | |
| using skwindow::internal::GraphiteMetalWindowContext; | |
| namespace skwindow::internal { | |
| GraphiteMetalWindowContext::GraphiteMetalWindowContext(std::unique_ptr<const DisplayParams> params) | |
| : WindowContext(DisplayParamsBuilder(params.get()).roundUpMSAA().detach()) | |
| , fValid(false) | |
| , fDrawableHandle(nil) {} | |
| void GraphiteMetalWindowContext::initializeContext() { | |
| #if defined(SK_GANESH) | |
| SkASSERT(!fContext); | |
| #endif | |
| SkASSERT(!fGraphiteContext); | |
| fDevice.reset(MTLCreateSystemDefaultDevice()); | |
| fQueue.reset([*fDevice newCommandQueue]); | |
| if (fDisplayParams->msaaSampleCount() > 1) { | |
| if (@available(macOS 10.11, iOS 9.0, tvOS 9.0, *)) { | |
| if (![*fDevice supportsTextureSampleCount:fDisplayParams->msaaSampleCount()]) { | |
| return; | |
| } | |
| } else { | |
| return; | |
| } | |
| } | |
| fSampleCount = fDisplayParams->msaaSampleCount(); | |
| fStencilBits = 8; | |
| fValid = this->onInitializeContext(); | |
| skgpu::graphite::MtlBackendContext backendContext = {}; | |
| backendContext.fDevice.retain((CFTypeRef)fDevice.get()); | |
| backendContext.fQueue.retain((CFTypeRef)fQueue.get()); | |
| SkASSERT(fDisplayParams->graphiteTestOptions()); | |
| skiatest::graphite::TestOptions opts = *fDisplayParams->graphiteTestOptions(); | |
| opts.fContextOptions.fRequireOrderedRecordings = true; | |
| // Needed to make synchronous readPixels work: | |
| opts.fOptionsPriv.fStoreContextRefInRecorder = true; | |
| fDisplayParams = | |
| GraphiteDisplayParamsBuilder(fDisplayParams.get()).graphiteTestOptions(opts).detach(); | |
| fGraphiteContext = skgpu::graphite::ContextFactory::MakeMetal( | |
| backendContext, fDisplayParams->graphiteTestOptions()->fContextOptions); | |
| fGraphiteRecorder = fGraphiteContext->makeRecorder(ToolUtils::CreateTestingRecorderOptions()); | |
| // TODO | |
| // if (!fGraphiteContext && fDisplayParams->msaaSampleCount() > 1) { | |
| // fDisplayParams->msaaSampleCount() /= 2; | |
| // this->initializeContext(); | |
| // return; | |
| // } | |
| } | |
| void GraphiteMetalWindowContext::destroyContext() { | |
| if (fGraphiteContext) { | |
| fGraphiteRecorder.reset(); | |
| fGraphiteContext.reset(); | |
| } | |
| this->onDestroyContext(); | |
| fMetalLayer = nil; | |
| fValid = false; | |
| fQueue.reset(); | |
| fDevice.reset(); | |
| } | |
| sk_sp<SkSurface> GraphiteMetalWindowContext::getBackbufferSurface() { | |
| sk_sp<SkSurface> surface; | |
| id<CAMetalDrawable> currentDrawable = [fMetalLayer nextDrawable]; | |
| if (currentDrawable == nil) { | |
| return nullptr; | |
| } | |
| auto backendTex = skgpu::graphite::BackendTextures::MakeMetal( | |
| this->dimensions(), (CFTypeRef)currentDrawable.texture); | |
| surface = SkSurfaces::WrapBackendTexture(this->graphiteRecorder(), | |
| backendTex, | |
| fDisplayParams->colorSpace(), | |
| &fDisplayParams->surfaceProps()); | |
| fDrawableHandle = CFRetain((CFTypeRef)currentDrawable); | |
| return surface; | |
| } | |
| void GraphiteMetalWindowContext::onSwapBuffers() { | |
| this->submitToGpu(); | |
| id<CAMetalDrawable> currentDrawable = (id<CAMetalDrawable>)fDrawableHandle; | |
| id<MTLCommandBuffer> commandBuffer([*fQueue commandBuffer]); | |
| commandBuffer.label = @"Present"; | |
| [commandBuffer presentDrawable:currentDrawable]; | |
| [commandBuffer commit]; | |
| // ARC is off in sk_app, so we need to release the CF ref manually | |
| CFRelease(fDrawableHandle); | |
| fDrawableHandle = nil; | |
| } | |
| void GraphiteMetalWindowContext::setDisplayParams(std::unique_ptr<const DisplayParams> params) { | |
| this->destroyContext(); | |
| fDisplayParams = std::move(params); | |
| this->initializeContext(); | |
| } | |
| void GraphiteMetalWindowContext::activate(bool isActive) {} | |
| } // namespace skwindow::internal |