I have a layer-backed (not layer-hosted) subclass of NSView called MetalView:
import Cocoa
import Metal
class MetalView: NSView {
// MARK: Properties
var metalLayer: CAMetalLayer {
return layer as! CAMetalLayer
}
// MARK: - Overrides
override func awakeFromNib() {
super.awakeFromNib()
initialize()
}
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
render()
}
override func drawLayer(layer: CALayer, inContext ctx: CGContext) {
super.drawLayer(layer, inContext: ctx)
render()
}
override func displayLayer(layer: CALayer) {
super.displayLayer(layer)
render()
}
override func makeBackingLayer() -> CALayer {
return CAMetalLayer()
}
override var wantsUpdateLayer: Bool {
return false
}
// MARK: - Initialization
func initialize() {
// Layer
wantsLayer = true
metalLayer.delegate = self
metalLayer.device = MTLCreateSystemDefaultDevice()
metalLayer.pixelFormat = .BGRA8Unorm
metalLayer.framebufferOnly = true
}
// MARK: - Rendering
func render() {
// Rendering
metalLayer.frame = frame
NSLog("rendering")
}
}
The render method is not getting called. I tried setting wantsUpdateLayer to true. The render method gets called with I remove this part:
wantsLayer = true
metalLayer.delegate = self
metalLayer.device = MTLCreateSystemDefaultDevice()
metalLayer.pixelFormat = .BGRA8Unorm
metalLayer.framebufferOnly = true
From the wantsLayer
docs:
If the wantsUpdateLayer method returns NO, you should not interact with the underlying layer object directly.
Setting values on metalLayer
and modifying its frame count as "interact[ing] with the underlying layer object directly." You're not allowed to do that in this configuration. The layer doesn't belong to you. It belongs to the system. The system is free to create these caching layers any time it wants. It doesn't have to use it and there doesn't have to be just one. (Core Animation often creates extra layers; that's completely normal.)
If you want to interact with the layer directly, you should set wantsUpdateLayer
to be true
and then implement your drawing code in updateLayer
. You shouldn't try to mix drawRect:
with a layer you mess with directly.
For another version of this problem, see Why is an empty drawRect interfering with a simple animation?