xref: /aosp_15_r20/external/skia/tools/window/MetalWindowContext.mm (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1/*
2 * Copyright 2019 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/MetalWindowContext.h"
9
10#include "include/core/SkCanvas.h"
11#include "include/core/SkSurface.h"
12#include "include/gpu/ganesh/GrBackendSurface.h"
13#include "include/gpu/ganesh/GrDirectContext.h"
14#include "include/gpu/ganesh/SkSurfaceGanesh.h"
15#include "include/gpu/ganesh/mtl/GrMtlBackendContext.h"
16#include "include/gpu/ganesh/mtl/GrMtlBackendSurface.h"
17#include "include/gpu/ganesh/mtl/GrMtlDirectContext.h"
18#include "include/gpu/ganesh/mtl/GrMtlTypes.h"
19#include "include/gpu/ganesh/mtl/SkSurfaceMetal.h"
20#include "src/base/SkMathPriv.h"
21#include "src/gpu/ganesh/GrCaps.h"
22#include "src/gpu/ganesh/GrDirectContextPriv.h"
23#include "src/image/SkImage_Base.h"
24
25using skwindow::DisplayParams;
26using skwindow::internal::MetalWindowContext;
27
28namespace skwindow::internal {
29
30MetalWindowContext::MetalWindowContext(std::unique_ptr<const DisplayParams> params)
31        : WindowContext(DisplayParamsBuilder(params.get()).roundUpMSAA().build())
32        , fValid(false)
33        , fDrawableHandle(nil) {}
34
35void MetalWindowContext::initializeContext() {
36    SkASSERT(!fContext);
37
38    fDevice.reset(MTLCreateSystemDefaultDevice());
39    fQueue.reset([*fDevice newCommandQueue]);
40
41    if (fDisplayParams->msaaSampleCount() > 1) {
42        if (@available(macOS 10.11, iOS 9.0, tvOS 9.0, *)) {
43            if (![*fDevice supportsTextureSampleCount:fDisplayParams->msaaSampleCount()]) {
44                return;
45            }
46        } else {
47            return;
48        }
49    }
50    fSampleCount = fDisplayParams->msaaSampleCount();
51    fStencilBits = 8;
52
53    fValid = this->onInitializeContext();
54
55    GrMtlBackendContext backendContext = {};
56    backendContext.fDevice.retain((GrMTLHandle)fDevice.get());
57    backendContext.fQueue.retain((GrMTLHandle)fQueue.get());
58    fContext = GrDirectContexts::MakeMetal(backendContext, fDisplayParams->grContextOptions());
59    if (!fContext && fDisplayParams->msaaSampleCount() > 1) {
60        auto newParams = DisplayParamsBuilder(fDisplayParams.get());
61        newParams.msaaSampleCount(fDisplayParams->msaaSampleCount() / 2);
62        // Don't call this->setDisplayParams because that also calls
63        // destroyContext() and initializeContext().
64        fDisplayParams = newParams.build();
65        this->initializeContext();
66        return;
67    }
68}
69
70void MetalWindowContext::destroyContext() {
71    if (fContext) {
72        // in case we have outstanding refs to this (lua?)
73        fContext->abandonContext();
74        fContext.reset();
75    }
76
77    this->onDestroyContext();
78
79    fMetalLayer = nil;
80    fValid = false;
81
82    fQueue.reset();
83    fDevice.reset();
84}
85
86sk_sp<SkSurface> MetalWindowContext::getBackbufferSurface() {
87    sk_sp<SkSurface> surface;
88    if (fContext) {
89        if (fDisplayParams->delayDrawableAcquisition()) {
90            surface = SkSurfaces::WrapCAMetalLayer(fContext.get(),
91                                                   (__bridge GrMTLHandle)fMetalLayer,
92                                                   kTopLeft_GrSurfaceOrigin,
93                                                   fSampleCount,
94                                                   kBGRA_8888_SkColorType,
95                                                   fDisplayParams->colorSpace(),
96                                                   &fDisplayParams->surfaceProps(),
97                                                   &fDrawableHandle);
98        } else {
99            id<CAMetalDrawable> currentDrawable = [fMetalLayer nextDrawable];
100            if (currentDrawable == nil) {
101                return nullptr;
102            }
103
104            GrMtlTextureInfo fbInfo;
105            fbInfo.fTexture.retain(currentDrawable.texture);
106
107            GrBackendRenderTarget backendRT =
108                    GrBackendRenderTargets::MakeMtl(fWidth, fHeight, fbInfo);
109
110            surface = SkSurfaces::WrapBackendRenderTarget(fContext.get(),
111                                                          backendRT,
112                                                          kTopLeft_GrSurfaceOrigin,
113                                                          kBGRA_8888_SkColorType,
114                                                          fDisplayParams->colorSpace(),
115                                                          &fDisplayParams->surfaceProps());
116
117            fDrawableHandle = CFRetain((GrMTLHandle) currentDrawable);
118        }
119    }
120
121    return surface;
122}
123
124void MetalWindowContext::onSwapBuffers() {
125    id<CAMetalDrawable> currentDrawable = (id<CAMetalDrawable>)fDrawableHandle;
126
127    id<MTLCommandBuffer> commandBuffer([*fQueue commandBuffer]);
128    commandBuffer.label = @"Present";
129
130    [commandBuffer presentDrawable:currentDrawable];
131    [commandBuffer commit];
132    // ARC is off in sk_app, so we need to release the CF ref manually
133    CFRelease(fDrawableHandle);
134    fDrawableHandle = nil;
135}
136
137void MetalWindowContext::setDisplayParams(std::unique_ptr<const DisplayParams> params) {
138    this->destroyContext();
139    fDisplayParams = std::move(params);
140    this->initializeContext();
141}
142
143}   //namespace skwindow::internal
144