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