• 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 "webgpu/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;
52    void resize(int width, int height) override;
53private:
54    NSView*              fMainView;
55    id<MTLDevice>        fMTLDevice;
56    CAMetalLayer*        fLayer;
57};
58
59class SwapChainImplMTL {
60public:
61    typedef void WSIContext;
62    static DawnSwapChainImplementation Create(id<MTLDevice> device, CAMetalLayer* layer) {
63        auto impl = new SwapChainImplMTL(device, layer);
64        return CreateSwapChainImplementation<SwapChainImplMTL>(impl);
65    }
66
67    void Init(WSIContext* ctx) {}
68
69    SwapChainImplMTL(id<MTLDevice> device, CAMetalLayer* layer)
70      : fQueue([device newCommandQueue])
71      , fLayer(layer) {}
72
73    ~SwapChainImplMTL() {}
74
75    DawnSwapChainError Configure(WGPUTextureFormat format, WGPUTextureUsage,
76            uint32_t width, uint32_t height) {
77        if (format != WGPUTextureFormat::WGPUTextureFormat_RGBA8Unorm) {
78            return "unsupported format";
79        }
80        SkASSERT(width > 0);
81        SkASSERT(height > 0);
82
83        return DAWN_SWAP_CHAIN_NO_ERROR;
84    }
85
86    DawnSwapChainError GetNextTexture(DawnSwapChainNextTexture* nextTexture) {
87        fCurrentDrawable = [fLayer nextDrawable];
88
89        nextTexture->texture.ptr = reinterpret_cast<void*>(fCurrentDrawable.texture);
90
91        return DAWN_SWAP_CHAIN_NO_ERROR;
92    }
93
94    DawnSwapChainError Present() {
95        id<MTLCommandBuffer> commandBuffer = [fQueue commandBuffer];
96        [commandBuffer presentDrawable: fCurrentDrawable];
97        [commandBuffer commit];
98        return DAWN_SWAP_CHAIN_NO_ERROR;
99    }
100private:
101    id<MTLCommandQueue>  fQueue;
102    CAMetalLayer*        fLayer;
103    id<CAMetalDrawable>  fCurrentDrawable = nil;
104};
105
106DawnMTLWindowContext::DawnMTLWindowContext(const MacWindowInfo& info, const DisplayParams& params)
107    : DawnWindowContext(params, wgpu::TextureFormat::BGRA8Unorm)
108    , fMainView(info.fMainView) {
109    CGFloat backingScaleFactor = sk_app::GetBackingScaleFactor(fMainView);
110    CGSize size = fMainView.bounds.size;
111    size.width *= backingScaleFactor;
112    size.height *= backingScaleFactor;
113    this->initializeContext(size.width, size.height);
114}
115
116DawnMTLWindowContext::~DawnMTLWindowContext() {
117    this->destroyContext();
118}
119
120DawnSwapChainImplementation DawnMTLWindowContext::createSwapChainImplementation(
121        int width, int height, const DisplayParams& params) {
122    return SwapChainImplMTL::Create(fMTLDevice, fLayer);
123}
124
125wgpu::Device DawnMTLWindowContext::onInitializeContext() {
126    wgpu::Device device = this->createDevice(wgpu::BackendType::Metal);
127    if (!device) {
128        return nullptr;
129    }
130
131    // We assume that Dawn is using the default device. This could be wrong on multi-GPU systems.
132    fMTLDevice = MTLCreateSystemDefaultDevice();
133
134    CGSize size;
135    size.width = width();
136    size.height = height();
137
138    fLayer = [CAMetalLayer layer];
139    [fLayer setDevice:fMTLDevice];
140    [fLayer setPixelFormat: MTLPixelFormatBGRA8Unorm];
141    [fLayer setFramebufferOnly: YES];
142    [fLayer setDrawableSize: size];
143    [fLayer setColorspace: CGColorSpaceCreateDeviceRGB()];
144    [fLayer setContentsScale: sk_app::GetBackingScaleFactor(fMainView)];
145    [fLayer setContentsGravity: kCAGravityTopLeft];
146    [fLayer setAutoresizingMask: kCALayerHeightSizable | kCALayerWidthSizable];
147
148    [fMainView setWantsLayer: YES];
149    [fMainView setLayer: fLayer];
150
151    return device;
152}
153
154void DawnMTLWindowContext::onDestroyContext() {
155}
156
157void DawnMTLWindowContext::onSwapBuffers() {
158}
159
160void DawnMTLWindowContext::resize(int w, int h) {
161    CGFloat backingScaleFactor = sk_app::GetBackingScaleFactor(fMainView);
162    CGSize size = fMainView.bounds.size;
163    size.width *= backingScaleFactor;
164    size.height *= backingScaleFactor;
165
166    fLayer.drawableSize = size;
167    fLayer.contentsScale = backingScaleFactor;
168
169    DawnWindowContext::resize(size.width, size.height);
170}
171
172namespace window_context_factory {
173
174std::unique_ptr<WindowContext> MakeDawnMTLForMac(const MacWindowInfo& winInfo,
175                                                 const DisplayParams& params) {
176    std::unique_ptr<WindowContext> ctx(new DawnMTLWindowContext(winInfo, params));
177    if (!ctx->isValid()) {
178        return nullptr;
179    }
180    return ctx;
181}
182
183}
184
185}   //namespace sk_app
186