使用电池供电时 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" 时间。您应该使用它们来计算目标输出的正确帧。我没有看到您在代码中使用输出时间。