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