Last active
July 14, 2024 10:34
-
-
Save Oleksiy-Yakovenko/d20ff2536cd744474c1b8c3392dc0dbc to your computer and use it in GitHub Desktop.
Minimalistic example of Metal NSView with CAMetalLayer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// A simple view with CAMetalLayer | |
protocol MetalViewDelegate: AnyObject { | |
func viewDidResize() | |
} | |
class MetalView: NSView { | |
weak var delegate: MetalViewDelegate? | |
override var acceptsFirstResponder: Bool { | |
true | |
} | |
override var frame: NSRect { | |
didSet { | |
delegate?.viewDidResize() | |
} | |
} | |
override func viewDidChangeBackingProperties() { | |
delegate?.viewDidResize() | |
} | |
override func makeBackingLayer() -> CALayer { | |
return CAMetalLayer() | |
} | |
} | |
// ViewController class setup to use metal rendering | |
class MetalViewController: NSViewController { | |
init() { | |
super.init(nibName: nil, bundle: nil) | |
loadView() | |
} | |
required init?(coder _: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
override func loadView() { | |
let view = MetalView() | |
view.delegate = self | |
view.wantsLayer = true | |
view.layerContentsRedrawPolicy = .duringViewResize | |
if let metalLayer = view.layer as? CAMetalLayer { | |
metalLayer.pixelFormat = .bgra8Unorm | |
metalLayer.framebufferOnly = true | |
metalLayer.device = metalLayer.preferredDevice | |
metalLayer.delegate = self | |
} | |
self.view = view | |
viewDidLoad() | |
} | |
private var viewportSize: CGSize { | |
return view.convertToBacking(view.bounds.size) | |
} | |
private func draw() { | |
guard | |
let metalLayer = view.layer as? CAMetalLayer, | |
let drawable = metalLayer.nextDrawable() else { | |
return | |
} | |
metalLayer.drawableSize = viewportSize | |
let renderPass = MTLRenderPassDescriptor() | |
renderPass.colorAttachments[0].clearColor = .init(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0) | |
renderPass.colorAttachments[0].texture = drawable.texture | |
renderPass.colorAttachments[0].loadAction = .clear | |
renderPass.colorAttachments[0].storeAction = .store | |
autoreleasepool { | |
// render your scene here | |
} | |
} | |
private func resize() { | |
if let metalLayer = view.layer as? CAMetalLayer { | |
metalLayer.drawableSize = viewportSize | |
} | |
} | |
} | |
extension MetalViewController: MetalViewDelegate { | |
func viewDidResize() { | |
resize() | |
} | |
} | |
extension MetalViewController: CALayerDelegate { | |
func display(_: CALayer) { | |
draw() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment