I tried a similar way with MTKView as I'm more used to it.
class ViewController: UIViewController, MTKViewDelegate {
var mtkView: MTKView!
override func viewDidLoad() {
super.viewDidLoad()
mtkView = MTKView(frame: view.bounds, device: MTLCreateSystemDefaultDevice()!)
mtkView.preferredFramesPerSecond = 120
mtkView.autoResizeDrawable = true
mtkView.delegate = self
mtkView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(mtkView)
NSLayoutConstraint.activate([
mtkView.leftAnchor.constraint(equalTo: view.leftAnchor),
mtkView.rightAnchor.constraint(equalTo: view.rightAnchor),
mtkView.topAnchor.constraint(equalTo: view.topAnchor),
mtkView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {}
func draw(in view: MTKView) {
let startTime = CACurrentMediaTime()
let drawable = view.currentDrawable
let timeUsed = CACurrentMediaTime() - startTime
if (timeUsed > 0.003) {
print("CAMetalLayer.nextDrawable take much time!! -> \(String(format: "%.2f", timeUsed * 1000)) ms")
}
guard let drawable else {
print("no drawable available")
return
}
drawable.present()
}
}
and it gives similar logs. However, looking at the profiling trace I don't think there's an issue at all:
You can see with "LCD" line that surface is regularly displayed every 16ms, and with "Time Profiler" line that CPU isn't busy. This shows that getting the current/next drawable is not slow but is just blocking because it's too early. My understanding is that the draw() method (or in your case the onDisplayLink() method) is called "too early". In fact it's not really too early: it's a bit ahead of time to let you perform some work in advance before you actually need the drawable. This is described in more details there: https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/MTLBestPracticesGuide/Drawables.html