• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1
2/*
3 * Copyright 2019 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "MetalWindowContext.h"
10#include "GrBackendSurface.h"
11#include "GrCaps.h"
12#include "GrContext.h"
13#include "GrContextPriv.h"
14#include "SkCanvas.h"
15#include "SkImage_Base.h"
16#include "SkMathPriv.h"
17#include "SkSurface.h"
18#include "mtl/GrMtlTypes.h"
19
20namespace sk_app {
21
22static int kMaxBuffersInFlight = 3;
23
24MetalWindowContext::MetalWindowContext(const DisplayParams& params)
25    : WindowContext(params)
26    , fValid(false)
27    , fSurface(nullptr) {
28    fDisplayParams.fMSAASampleCount = GrNextPow2(fDisplayParams.fMSAASampleCount);
29}
30
31void MetalWindowContext::initializeContext() {
32    SkASSERT(!fContext);
33
34    // The subclass uses these to initialize their view
35    fDevice = MTLCreateSystemDefaultDevice();
36    fQueue = [fDevice newCommandQueue];
37
38    fInFlightSemaphore = dispatch_semaphore_create(kMaxBuffersInFlight);
39
40    fValid = this->onInitializeContext();
41    fContext = GrContext::MakeMetal(fDevice, fQueue, fDisplayParams.fGrContextOptions);
42    if (!fContext && fDisplayParams.fMSAASampleCount > 1) {
43        fDisplayParams.fMSAASampleCount /= 2;
44        this->initializeContext();
45        return;
46    }
47}
48
49void MetalWindowContext::destroyContext() {
50    fSurface.reset(nullptr);
51
52    if (fContext) {
53        // in case we have outstanding refs to this guy (lua?)
54        fContext->abandonContext();
55        fContext.reset();
56    }
57
58    // TODO: Figure out who's releasing this
59    // [fQueue release];
60    [fDevice release];
61
62    this->onDestroyContext();
63}
64
65sk_sp<SkSurface> MetalWindowContext::getBackbufferSurface() {
66    sk_sp<SkSurface> surface;
67    if (fContext) {
68        GrMtlTextureInfo fbInfo;
69        fbInfo.fTexture = [[fMTKView currentDrawable] texture];
70
71        GrBackendRenderTarget backendRT(fWidth,
72                                        fHeight,
73                                        fSampleCount,
74                                        fbInfo);
75
76        surface = SkSurface::MakeFromBackendRenderTarget(fContext.get(), backendRT,
77                                                          kTopLeft_GrSurfaceOrigin,
78                                                          kBGRA_8888_SkColorType,
79                                                          fDisplayParams.fColorSpace,
80                                                          &fDisplayParams.fSurfaceProps);
81    }
82
83    return surface;
84}
85
86void MetalWindowContext::swapBuffers() {
87    // Block to ensure we don't try to render to a frame that hasn't finished presenting
88    dispatch_semaphore_wait(fInFlightSemaphore, DISPATCH_TIME_FOREVER);
89
90    id<MTLCommandBuffer> commandBuffer = [fQueue commandBuffer];
91    commandBuffer.label = @"Present";
92
93    __block dispatch_semaphore_t block_sema = fInFlightSemaphore;
94    [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer)
95     {
96         dispatch_semaphore_signal(block_sema);
97     }];
98
99    id<MTLDrawable> drawable = [fMTKView currentDrawable];
100    [commandBuffer presentDrawable:drawable];
101    [commandBuffer commit];
102}
103
104void MetalWindowContext::resize(int w, int h) {
105    this->destroyContext();
106    this->initializeContext();
107}
108
109void MetalWindowContext::setDisplayParams(const DisplayParams& params) {
110    this->destroyContext();
111    fDisplayParams = params;
112    this->initializeContext();
113}
114
115}   //namespace sk_app
116