Skip to content

Instantly share code, notes, and snippets.

@Oleksiy-Yakovenko
Last active July 14, 2024 10:34
Show Gist options
  • Save Oleksiy-Yakovenko/d20ff2536cd744474c1b8c3392dc0dbc to your computer and use it in GitHub Desktop.
Save Oleksiy-Yakovenko/d20ff2536cd744474c1b8c3392dc0dbc to your computer and use it in GitHub Desktop.
Minimalistic example of Metal NSView with CAMetalLayer
// 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