我试图让动画以显示器的刷新率平稳运行,而不会出现屏幕撕裂。动画是使用 Metal 渲染的。据我了解,Apple 告诉您为此使用基于 CVDisplayLink 的计时器,这就是我所做的。
当台式电脑和笔记本电脑连接到电源适配器时,一切正常。但是,当笔记本电脑使用电池运行时,尤其是当它们的电池未充满时,我可以在动画中看到非常明显的卡顿。不过,没有撕裂。似乎每次屏幕刷新时都不会触发计时器。
我很确定这不是因为 CPU 被限制了。 CPU利用率低于10%,动画计算和渲染时间不到2ms;在 60Hz 时,它需要 16ms 的时间。
对于它的值(value),这就是我设置计时器的方式:
private func makeDisplayLink(window: NSWindow) -> CVDisplayLink
{
func displayLinkOutputCallback(_ displayLink: CVDisplayLink, _ inNow: UnsafePointer<CVTimeStamp>, _ inOutputTime: UnsafePointer<CVTimeStamp>, _ flagsIn: CVOptionFlags, _ flagsOut: UnsafeMutablePointer<CVOptionFlags>, _ displayLinkContext: UnsafeMutableRawPointer?) -> CVReturn {
unsafeBitCast(displayLinkContext, to: MetalScreenSaverView.self).animateOneFrame()
return kCVReturnSuccess
}
var link: CVDisplayLink?
let screensID = UInt32(window.screen!.deviceDescription["NSScreenNumber"] as! Int)
CVDisplayLinkCreateWithCGDisplay(screensID, &link)
CVDisplayLinkSetOutputCallback(link!, displayLinkOutputCallback, UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()))
return link!
}
后来我通过调用
CVDisplayLinkStart
开始链接以链接作为参数。完整代码,如果您有兴趣,可以在以下位置找到:https://github.com/thoughtworks/dancing-glyphs/blob/master/Library/MetalScreenSaverView.swift有任何想法吗?我可以告诉 OS X 以确保在每次屏幕刷新时触发计时器吗?这是 Metal 的问题吗?我见过在电池上运行良好的游戏和屏幕保护程序,但我假设使用 OpenGL。
最佳答案
如果我正确阅读了您的代码,则您假设 CVDisplayLink
在某个不可更改的间隔被调用。这根本没有 promise 。系统完全可以自由修改刷新间隔或丢帧。所有实时系统都必须具备丢帧的能力。这就是“实时”的核心。
您已通过“当前显示”时间和“目标输出”时间。您应该使用它们来计算目标输出的正确帧。我没有看到您在代码中使用输出时间。
关于macos - 电池供电时 CVDisplayLink 定时器的稳定性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40070195/