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#include "tools/window/mac/GraphiteDawnMetalWindowContext_mac.h" 8 9#include "tools/window/GraphiteDawnWindowContext.h" 10#include "tools/window/mac/MacWindowInfo.h" 11 12#import <Cocoa/Cocoa.h> 13#import <QuartzCore/CAConstraintLayoutManager.h> 14#import <QuartzCore/CAMetalLayer.h> 15 16using skwindow::DisplayParams; 17using skwindow::MacWindowInfo; 18using skwindow::internal::GraphiteDawnWindowContext; 19 20namespace { 21 22class GraphiteDawnMetalWindowContext_mac : public GraphiteDawnWindowContext { 23public: 24 GraphiteDawnMetalWindowContext_mac(const MacWindowInfo&, std::unique_ptr<const DisplayParams>); 25 26 ~GraphiteDawnMetalWindowContext_mac() override; 27 28 bool onInitializeContext() override; 29 void onDestroyContext() override; 30 void resize(int w, int h) override; 31 32private: 33 bool resizeInternal(); 34 35 NSView* fMainView; 36 CAMetalLayer* fMetalLayer; 37}; 38 39GraphiteDawnMetalWindowContext_mac::GraphiteDawnMetalWindowContext_mac( 40 const MacWindowInfo& info, std::unique_ptr<const DisplayParams> params) 41 : GraphiteDawnWindowContext(std::move(params), wgpu::TextureFormat::BGRA8Unorm) 42 , fMainView(info.fMainView) { 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->disableVsync() ? 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 fDevice = std::move(device); 85 fSurface = std::move(surface); 86 configureSurface(); 87 88 return true; 89} 90 91void GraphiteDawnMetalWindowContext_mac::onDestroyContext() {} 92 93void GraphiteDawnMetalWindowContext_mac::resize(int w, int h) { 94 if (!this->resizeInternal()) { 95 return; 96 } 97} 98 99bool GraphiteDawnMetalWindowContext_mac::resizeInternal() { 100 CGFloat backingScaleFactor = skwindow::GetBackingScaleFactor(fMainView); 101 CGSize backingSize = fMainView.bounds.size; 102 backingSize.width *= backingScaleFactor; 103 backingSize.height *= backingScaleFactor; 104 105 fMetalLayer.drawableSize = backingSize; 106 fMetalLayer.contentsScale = backingScaleFactor; 107 108 if (fWidth == backingSize.width && fHeight == backingSize.height) { 109 return false; 110 } 111 112 fWidth = backingSize.width; 113 fHeight = backingSize.height; 114 configureSurface(); 115 116 return true; 117} 118 119} // anonymous namespace 120 121namespace skwindow { 122 123std::unique_ptr<WindowContext> MakeGraphiteDawnMetalForMac( 124 const MacWindowInfo& info, std::unique_ptr<const DisplayParams> params) { 125 std::unique_ptr<WindowContext> ctx( 126 new GraphiteDawnMetalWindowContext_mac(info, std::move(params))); 127 if (!ctx->isValid()) { 128 return nullptr; 129 } 130 return ctx; 131} 132 133} // namespace skwindow 134