FramebufferUIView: disable CALayer implicit animations on frame updates

Every time Mac repainted a region we set imageLayer.contents to a new
CGImage. CALayer's default action for .contents is a 0.25s crossfade, so
big repaints (like after a click — cursor + button + window-focus) looked
like a pulse. Tap seemed "flickery"; actually the whole view was doing
quarter-second crossfades constantly, most just weren't big enough to
notice until a chunky repaint hit.

Override imageLayer.actions with NSNull for contents/contentsRect/frame/
transform so blits are instantaneous, and wrap apply() in a
CATransaction.setDisableActions(true) for safety.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey T
2026-04-17 14:21:33 -05:00
parent 4ff3e4b030
commit c1bed4f53b

View File

@@ -86,6 +86,17 @@ final class FramebufferUIView: UIView,
imageLayer.magnificationFilter = .nearest
imageLayer.minificationFilter = .linear
imageLayer.contentsGravity = .resize
// Kill CALayer's implicit animations we want every framebuffer
// update to be an instantaneous blit, not a 0.25s crossfade.
imageLayer.actions = [
"contents": NSNull(),
"contentsRect": NSNull(),
"position": NSNull(),
"bounds": NSNull(),
"frame": NSNull(),
"transform": NSNull(),
"backgroundColor": NSNull()
]
layer.addSublayer(imageLayer)
configureGestureRecognizers()
@@ -161,8 +172,11 @@ final class FramebufferUIView: UIView,
}
func apply(image: CGImage?, framebufferSize: CGSize) {
CATransaction.begin()
CATransaction.setDisableActions(true)
imageLayer.contents = image
applyLayerFrame()
CATransaction.commit()
}
private func applyLayerFrame() {