1/* 2 * Copyright 2022 Google LLC 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/window/GraphiteDawnWindowContext.h" 9#include "tools/window/mac/WindowContextFactory_mac.h" 10 11#import <Cocoa/Cocoa.h> 12#import <QuartzCore/CAConstraintLayoutManager.h> 13#import <QuartzCore/CAMetalLayer.h> 14 15using skwindow::DisplayParams; 16using skwindow::MacWindowInfo; 17using skwindow::internal::GraphiteDawnWindowContext; 18 19namespace { 20 21class GraphiteDawnMetalWindowContext_mac : public GraphiteDawnWindowContext { 22public: 23 GraphiteDawnMetalWindowContext_mac(const MacWindowInfo&, const DisplayParams&); 24 25 ~GraphiteDawnMetalWindowContext_mac() override; 26 27 bool onInitializeContext() override; 28 void onDestroyContext() override; 29 void resize(int w, int h) override; 30 31private: 32 bool resizeInternal(); 33 34 NSView* fMainView; 35 CAMetalLayer* fMetalLayer; 36}; 37 38GraphiteDawnMetalWindowContext_mac::GraphiteDawnMetalWindowContext_mac(const MacWindowInfo& info, 39 const DisplayParams& params) 40 : GraphiteDawnWindowContext(params, wgpu::TextureFormat::BGRA8Unorm) 41 , fMainView(info.fMainView) { 42 43 CGFloat backingScaleFactor = skwindow::GetBackingScaleFactor(fMainView); 44 CGSize backingSize = fMainView.bounds.size; 45 this->initializeContext(backingSize.width * backingScaleFactor, 46 backingSize.height * backingScaleFactor); 47} 48 49GraphiteDawnMetalWindowContext_mac::~GraphiteDawnMetalWindowContext_mac() { 50 this->destroyContext(); 51} 52 53bool GraphiteDawnMetalWindowContext_mac::onInitializeContext() { 54 SkASSERT(nil != fMainView); 55 56 auto device = createDevice(wgpu::BackendType::Metal); 57 if (!device) { 58 SkASSERT(device); 59 return false; 60 } 61 62 // Create a CAMetalLayer that covers the whole window that will be passed to 63 // CreateSurface. 64 fMetalLayer = [CAMetalLayer layer]; 65 BOOL useVsync = fDisplayParams.fDisableVsync ? NO : YES; 66 fMetalLayer.displaySyncEnabled = useVsync; 67 fMainView.wantsLayer = YES; 68 fMainView.layer = fMetalLayer; 69 70 // Adjust fMetalLayer size based on window size. 71 this->resizeInternal(); 72 73 wgpu::SurfaceDescriptorFromMetalLayer surfaceChainedDesc; 74 surfaceChainedDesc.layer = fMetalLayer; 75 wgpu::SurfaceDescriptor surfaceDesc; 76 surfaceDesc.nextInChain = &surfaceChainedDesc; 77 78 auto surface = wgpu::Instance(fInstance->Get()).CreateSurface(&surfaceDesc); 79 if (!surface) { 80 SkASSERT(false); 81 return false; 82 } 83 84 85 fDevice = std::move(device); 86 fSurface = std::move(surface); 87 fSwapChain = this->createSwapChain(); 88 89 return true; 90} 91 92void GraphiteDawnMetalWindowContext_mac::onDestroyContext() {} 93 94void GraphiteDawnMetalWindowContext_mac::resize(int w, int h) { 95 if (!this->resizeInternal()) { 96 return; 97 } 98 fSwapChain = this->createSwapChain(); 99} 100 101bool GraphiteDawnMetalWindowContext_mac::resizeInternal() { 102 CGFloat backingScaleFactor = skwindow::GetBackingScaleFactor(fMainView); 103 CGSize backingSize = fMainView.bounds.size; 104 backingSize.width *= backingScaleFactor; 105 backingSize.height *= backingScaleFactor; 106 107 fMetalLayer.drawableSize = backingSize; 108 fMetalLayer.contentsScale = backingScaleFactor; 109 110 if (fWidth == backingSize.width && fHeight == backingSize.height) { 111 return false; 112 } 113 114 fWidth = backingSize.width; 115 fHeight = backingSize.height; 116 return true; 117} 118 119} // anonymous namespace 120 121namespace skwindow { 122 123std::unique_ptr<WindowContext> MakeGraphiteDawnMetalForMac(const MacWindowInfo& info, 124 const DisplayParams& params) { 125 std::unique_ptr<WindowContext> ctx(new GraphiteDawnMetalWindowContext_mac(info, params)); 126 if (!ctx->isValid()) { 127 return nullptr; 128 } 129 return ctx; 130} 131 132} // namespace skwindow 133