xref: /aosp_15_r20/external/skia/tools/window/GraphiteNativeMetalWindowContext.mm (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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