• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/GrBackendSurface.h"
13#include "include/gpu/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(const DisplayParams& params)
31        : WindowContext(params)
32        , fValid(false)
33        , fDrawableHandle(nil) {
34    fDisplayParams.fMSAASampleCount = GrNextPow2(fDisplayParams.fMSAASampleCount);
35}
36
37void MetalWindowContext::initializeContext() {
38    SkASSERT(!fContext);
39
40    fDevice.reset(MTLCreateSystemDefaultDevice());
41    fQueue.reset([*fDevice newCommandQueue]);
42
43    if (fDisplayParams.fMSAASampleCount > 1) {
44        if (@available(macOS 10.11, iOS 9.0, tvOS 9.0, *)) {
45            if (![*fDevice supportsTextureSampleCount:fDisplayParams.fMSAASampleCount]) {
46                return;
47            }
48        } else {
49            return;
50        }
51    }
52    fSampleCount = fDisplayParams.fMSAASampleCount;
53    fStencilBits = 8;
54
55    fValid = this->onInitializeContext();
56
57    GrMtlBackendContext backendContext = {};
58    backendContext.fDevice.retain((GrMTLHandle)fDevice.get());
59    backendContext.fQueue.retain((GrMTLHandle)fQueue.get());
60    fContext = GrDirectContexts::MakeMetal(backendContext, fDisplayParams.fGrContextOptions);
61    if (!fContext && fDisplayParams.fMSAASampleCount > 1) {
62        fDisplayParams.fMSAASampleCount /= 2;
63        this->initializeContext();
64        return;
65    }
66}
67
68void MetalWindowContext::destroyContext() {
69    if (fContext) {
70        // in case we have outstanding refs to this (lua?)
71        fContext->abandonContext();
72        fContext.reset();
73    }
74
75    this->onDestroyContext();
76
77    fMetalLayer = nil;
78    fValid = false;
79
80    fQueue.reset();
81    fDevice.reset();
82}
83
84sk_sp<SkSurface> MetalWindowContext::getBackbufferSurface() {
85    sk_sp<SkSurface> surface;
86    if (fContext) {
87        if (fDisplayParams.fDelayDrawableAcquisition) {
88            surface = SkSurfaces::WrapCAMetalLayer(fContext.get(),
89                                                   (__bridge GrMTLHandle)fMetalLayer,
90                                                   kTopLeft_GrSurfaceOrigin,
91                                                   fSampleCount,
92                                                   kBGRA_8888_SkColorType,
93                                                   fDisplayParams.fColorSpace,
94                                                   &fDisplayParams.fSurfaceProps,
95                                                   &fDrawableHandle);
96        } else {
97            id<CAMetalDrawable> currentDrawable = [fMetalLayer nextDrawable];
98            if (currentDrawable == nil) {
99                return nullptr;
100            }
101
102            GrMtlTextureInfo fbInfo;
103            fbInfo.fTexture.retain(currentDrawable.texture);
104
105            GrBackendRenderTarget backendRT =
106                    GrBackendRenderTargets::MakeMtl(fWidth, fHeight, fbInfo);
107
108            surface = SkSurfaces::WrapBackendRenderTarget(fContext.get(),
109                                                          backendRT,
110                                                          kTopLeft_GrSurfaceOrigin,
111                                                          kBGRA_8888_SkColorType,
112                                                          fDisplayParams.fColorSpace,
113                                                          &fDisplayParams.fSurfaceProps);
114
115            fDrawableHandle = CFRetain((GrMTLHandle) currentDrawable);
116        }
117    }
118
119    return surface;
120}
121
122void MetalWindowContext::onSwapBuffers() {
123    id<CAMetalDrawable> currentDrawable = (id<CAMetalDrawable>)fDrawableHandle;
124
125    id<MTLCommandBuffer> commandBuffer([*fQueue commandBuffer]);
126    commandBuffer.label = @"Present";
127
128    [commandBuffer presentDrawable:currentDrawable];
129    [commandBuffer commit];
130    // ARC is off in sk_app, so we need to release the CF ref manually
131    CFRelease(fDrawableHandle);
132    fDrawableHandle = nil;
133}
134
135void MetalWindowContext::setDisplayParams(const DisplayParams& params) {
136    this->destroyContext();
137    fDisplayParams = params;
138    this->initializeContext();
139}
140
141}   //namespace skwindow::internal
142