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