• 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 "include/core/SkCanvas.h"
9#include "include/core/SkSurface.h"
10#include "include/gpu/GrBackendSurface.h"
11#include "include/gpu/GrContext.h"
12#include "include/gpu/mtl/GrMtlTypes.h"
13#include "src/core/SkMathPriv.h"
14#include "src/gpu/GrCaps.h"
15#include "src/gpu/GrContextPriv.h"
16#include "src/image/SkImage_Base.h"
17#include "tools/sk_app/MetalWindowContext.h"
18
19using sk_app::DisplayParams;
20using sk_app::MetalWindowContext;
21
22namespace sk_app {
23
24MetalWindowContext::MetalWindowContext(const DisplayParams& params)
25    : WindowContext(params)
26    , fValid(false) {
27
28    fDisplayParams.fMSAASampleCount = GrNextPow2(fDisplayParams.fMSAASampleCount);
29}
30
31void MetalWindowContext::initializeContext() {
32    SkASSERT(!fContext);
33
34    fDevice = MTLCreateSystemDefaultDevice();
35    fQueue = [fDevice newCommandQueue];
36
37    if (fDisplayParams.fMSAASampleCount > 1) {
38        if (![fDevice supportsTextureSampleCount:fDisplayParams.fMSAASampleCount]) {
39            return;
40        }
41    }
42    fSampleCount = fDisplayParams.fMSAASampleCount;
43    fStencilBits = 8;
44
45    fMetalLayer = [CAMetalLayer layer];
46    fMetalLayer.device = fDevice;
47    fMetalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
48
49    fValid = this->onInitializeContext();
50
51    fContext = GrContext::MakeMetal((__bridge void*)fDevice, (__bridge void*)fQueue,
52                                    fDisplayParams.fGrContextOptions);
53    if (!fContext && fDisplayParams.fMSAASampleCount > 1) {
54        fDisplayParams.fMSAASampleCount /= 2;
55        this->initializeContext();
56        return;
57    }
58}
59
60void MetalWindowContext::destroyContext() {
61    if (fContext) {
62        // in case we have outstanding refs to this guy (lua?)
63        fContext->abandonContext();
64        fContext.reset();
65    }
66
67    this->onDestroyContext();
68
69    fMetalLayer = nil;
70    fValid = false;
71
72    [fQueue release];
73    [fDevice release];
74}
75
76sk_sp<SkSurface> MetalWindowContext::getBackbufferSurface() {
77    sk_sp<SkSurface> surface;
78    if (fContext) {
79        // TODO: Apple recommends grabbing the drawable (which we're implicitly doing here)
80        // for as little time as possible. I'm not sure it matters for our test apps, but
81        // you can get better throughput by doing any offscreen renders, texture uploads, or
82        // other non-dependant tasks first before grabbing the drawable.
83        fCurrentDrawable = [fMetalLayer nextDrawable];
84
85        GrMtlTextureInfo fbInfo;
86        fbInfo.fTexture.retain((__bridge const void*)(fCurrentDrawable.texture));
87
88        if (fSampleCount == 1) {
89            GrBackendRenderTarget backendRT(fWidth,
90                                            fHeight,
91                                            fSampleCount,
92                                            fbInfo);
93
94            surface = SkSurface::MakeFromBackendRenderTarget(fContext.get(), backendRT,
95                                                             kTopLeft_GrSurfaceOrigin,
96                                                             kBGRA_8888_SkColorType,
97                                                             fDisplayParams.fColorSpace,
98                                                             &fDisplayParams.fSurfaceProps);
99        } else {
100            GrBackendTexture backendTexture(fWidth,
101                                            fHeight,
102                                            GrMipMapped::kNo,
103                                            fbInfo);
104
105            surface = SkSurface::MakeFromBackendTexture(
106                    fContext.get(), backendTexture, kTopLeft_GrSurfaceOrigin, fSampleCount,
107                    kBGRA_8888_SkColorType, fDisplayParams.fColorSpace,
108                    &fDisplayParams.fSurfaceProps);
109        }
110    }
111
112    return surface;
113}
114
115void MetalWindowContext::swapBuffers() {
116    id<MTLCommandBuffer> commandBuffer = [fQueue commandBuffer];
117    commandBuffer.label = @"Present";
118
119    [commandBuffer presentDrawable:fCurrentDrawable];
120    [commandBuffer commit];
121    fCurrentDrawable = nil;
122}
123
124void MetalWindowContext::setDisplayParams(const DisplayParams& params) {
125    this->destroyContext();
126    fDisplayParams = params;
127    this->initializeContext();
128}
129
130}   //namespace sk_app
131