使用电池供电时 CVDisplayLink 计时器的稳定性
Steadiness of CVDisplayLink timer when on battery power
我正在努力使动画 运行 流畅,以显示器的刷新率不出现屏幕撕裂。动画是使用 Metal 渲染的。据我了解,Apple 告诉您为此使用基于 CVDisplayLink 的计时器,这就是我所做的。
连接到电源适配器后,在台式电脑和笔记本电脑上一切正常。但是,当笔记本电脑 运行 使用电池时,尤其是当它们的电池没有充满时,我可以在动画中看到非常明显的卡顿。但是,没有撕裂。似乎每次屏幕刷新时都不会触发计时器。
我很确定这不是因为 CPU 被限制了。 CPU 利用率低于 10%,动画计算和渲染时间不到 2 毫秒;在 60Hz 时,它需要 16 毫秒。
值得一提的是,我是这样设置计时器的:
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!
}
稍后,我通过以 link 作为参数调用 CVDisplayLinkStart
来启动 link。完整代码,如果您有兴趣可以在以下位置找到:https://github.com/thoughtworks/dancing-glyphs/blob/master/Library/MetalScreenSaverView.swift
有什么想法吗?我能以某种方式告诉 OS X 以确保在每次屏幕刷新时触发计时器吗?这是金属的问题吗?我见过 运行 电池供电良好的游戏和屏幕保护程序,但我假设使用 OpenGL。
如果我没看错你的代码,你就是在假设 CVDisplayLink
在某个不可更改的时间间隔内被调用。这根本没有承诺。系统完全可以自由修改刷新间隔或丢帧。所有实时系统都必须具备丢帧功能。这就是 "real-time."
的核心所在
您已经过了 "currently displayed" 时间和 "target output" 时间。您应该使用它们来计算目标输出的正确帧。我没有看到您在代码中使用输出时间。
我正在努力使动画 运行 流畅,以显示器的刷新率不出现屏幕撕裂。动画是使用 Metal 渲染的。据我了解,Apple 告诉您为此使用基于 CVDisplayLink 的计时器,这就是我所做的。
连接到电源适配器后,在台式电脑和笔记本电脑上一切正常。但是,当笔记本电脑 运行 使用电池时,尤其是当它们的电池没有充满时,我可以在动画中看到非常明显的卡顿。但是,没有撕裂。似乎每次屏幕刷新时都不会触发计时器。
我很确定这不是因为 CPU 被限制了。 CPU 利用率低于 10%,动画计算和渲染时间不到 2 毫秒;在 60Hz 时,它需要 16 毫秒。
值得一提的是,我是这样设置计时器的:
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!
}
稍后,我通过以 link 作为参数调用 CVDisplayLinkStart
来启动 link。完整代码,如果您有兴趣可以在以下位置找到:https://github.com/thoughtworks/dancing-glyphs/blob/master/Library/MetalScreenSaverView.swift
有什么想法吗?我能以某种方式告诉 OS X 以确保在每次屏幕刷新时触发计时器吗?这是金属的问题吗?我见过 运行 电池供电良好的游戏和屏幕保护程序,但我假设使用 OpenGL。
如果我没看错你的代码,你就是在假设 CVDisplayLink
在某个不可更改的时间间隔内被调用。这根本没有承诺。系统完全可以自由修改刷新间隔或丢帧。所有实时系统都必须具备丢帧功能。这就是 "real-time."
您已经过了 "currently displayed" 时间和 "target output" 时间。您应该使用它们来计算目标输出的正确帧。我没有看到您在代码中使用输出时间。