• 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/sk_app/DawnWindowContext.h"
9#include "tools/sk_app/mac/WindowContextFactory_mac.h"
10#include "common/SwapChainUtils.h"
11#include "dawn/dawncpp.h"
12#include "dawn/dawn_wsi.h"
13#include "dawn_native/DawnNative.h"
14#include "dawn_native/MetalBackend.h"
15
16#import <Metal/Metal.h>
17#import <QuartzCore/CAMetalLayer.h>
18#import <Cocoa/Cocoa.h>
19
20namespace sk_app {
21
22using sk_app::window_context_factory::MacWindowInfo;
23
24class DawnMTLWindowContext : public DawnWindowContext {
25public:
26    DawnMTLWindowContext(const MacWindowInfo& info, const DisplayParams& params);
27    ~DawnMTLWindowContext() override;
28    dawn::Device onInitializeContext() override;
29    void onDestroyContext() override;
30    DawnSwapChainImplementation createSwapChainImplementation(int width, int height,
31                                                              const DisplayParams& params) override;
32    void onSwapBuffers() override;
33private:
34    NSView*              fMainView;
35    id<MTLDevice>        fMTLDevice;
36    CAMetalLayer*        fLayer;
37};
38
39class SwapChainImplMTL {
40public:
41    typedef void WSIContext;
42    static DawnSwapChainImplementation Create(id<MTLDevice> device, CAMetalLayer* layer) {
43        auto impl = new SwapChainImplMTL(device, layer);
44        return CreateSwapChainImplementation<SwapChainImplMTL>(impl);
45    }
46
47    void Init(WSIContext* ctx) {}
48
49    SwapChainImplMTL(id<MTLDevice> device, CAMetalLayer* layer)
50      : fQueue([device newCommandQueue])
51      , fLayer(layer) {}
52
53    ~SwapChainImplMTL() {}
54
55    DawnSwapChainError Configure(DawnTextureFormat format, DawnTextureUsageBit,
56            uint32_t width, uint32_t height) {
57        if (format != DAWN_TEXTURE_FORMAT_RGBA8_UNORM) {
58            return "unsupported format";
59        }
60        SkASSERT(width > 0);
61        SkASSERT(height > 0);
62
63        return DAWN_SWAP_CHAIN_NO_ERROR;
64    }
65
66    DawnSwapChainError GetNextTexture(DawnSwapChainNextTexture* nextTexture) {
67        fCurrentDrawable = [fLayer nextDrawable];
68
69        nextTexture->texture.ptr = reinterpret_cast<void*>(fCurrentDrawable.texture);
70
71        return DAWN_SWAP_CHAIN_NO_ERROR;
72    }
73
74    DawnSwapChainError Present() {
75        id<MTLCommandBuffer> commandBuffer = [fQueue commandBuffer];
76        [commandBuffer presentDrawable: fCurrentDrawable];
77        [commandBuffer commit];
78        return DAWN_SWAP_CHAIN_NO_ERROR;
79    }
80private:
81    id<MTLCommandQueue>  fQueue;
82    CAMetalLayer*        fLayer;
83    id<CAMetalDrawable>  fCurrentDrawable = nil;
84};
85
86DawnMTLWindowContext::DawnMTLWindowContext(const MacWindowInfo& info, const DisplayParams& params)
87    : DawnWindowContext(params, dawn::TextureFormat::BGRA8Unorm)
88    , fMainView(info.fMainView) {
89    CGSize size = fMainView.bounds.size;
90    this->initializeContext(size.width, size.height);
91}
92
93DawnMTLWindowContext::~DawnMTLWindowContext() {
94    this->destroyContext();
95}
96
97DawnSwapChainImplementation DawnMTLWindowContext::createSwapChainImplementation(
98        int width, int height, const DisplayParams& params) {
99    return SwapChainImplMTL::Create(fMTLDevice, fLayer);
100}
101
102dawn::Device DawnMTLWindowContext::onInitializeContext() {
103    dawn::Device device = this->createDevice(dawn_native::BackendType::Metal);
104    if (!device) {
105        return nullptr;
106    }
107
108    fMTLDevice = dawn_native::metal::GetMetalDevice(device.Get());
109
110    CGSize size;
111    size.width = width();
112    size.height = height();
113
114    fLayer = [CAMetalLayer layer];
115    [fLayer setDevice:fMTLDevice];
116    [fLayer setPixelFormat: MTLPixelFormatBGRA8Unorm];
117    [fLayer setFramebufferOnly: YES];
118    [fLayer setDrawableSize: size];
119    [fLayer setColorspace: CGColorSpaceCreateDeviceRGB()];
120
121    [fMainView setWantsLayer: YES];
122    [fMainView setLayer: fLayer];
123
124    return device;
125}
126
127void DawnMTLWindowContext::onDestroyContext() {
128}
129
130void DawnMTLWindowContext::onSwapBuffers() {
131}
132
133namespace window_context_factory {
134
135std::unique_ptr<WindowContext> MakeDawnMTLForMac(const MacWindowInfo& winInfo,
136                                                 const DisplayParams& params) {
137    std::unique_ptr<WindowContext> ctx(new DawnMTLWindowContext(winInfo, params));
138    if (!ctx->isValid()) {
139        return nullptr;
140    }
141    return ctx;
142}
143
144}
145
146}   //namespace sk_app
147