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