2016-10-16 4 views
2

Ich versuche eine Animation zu bekommen, die reibungslos läuft, mit der Bildwiederholfrequenz des Bildschirms ohne Bildschirmreißen. Die Animation wird mit Metal gerendert. Soweit ich weiß, sagt Ihnen Apple, dass Sie dafür CVDisplayLink-basierte Timer verwenden sollen, und das habe ich getan.Steadyess des CVDisplayLink Timers im Akkubetrieb

Alles funktioniert gut auf Desktop-Computern und Laptops, wenn sie an ein Netzteil angeschlossen sind. Allerdings, wenn die Laptops im Akkubetrieb laufen, besonders wenn der Akku nicht voll ist, kann ich in der Animation sehr auffälliges Stottern sehen. Es gibt jedoch kein Reißen. Es scheint, als ob der Timer nicht bei jeder Bildschirmaktualisierung ausgelöst wird.

Ich bin ziemlich sicher, dass dies nicht ist, weil die CPU gedrosselt wird. Die CPU-Auslastung liegt unter 10% und die Animation benötigt weniger als 2 ms zum Berechnen und Rendern. und bei 60 Hz hätte es 16ms zu tun.

Für das, was es wert ist, das ist, wie ich den Timer einstellen:

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! 
} 

Und später den Link Ich fange von CVDisplayLinkStart mit dem Link als Argument aufgerufen wird. Der vollständige Code, wenn Sie interessiert sind, finden Sie unter: https://github.com/thoughtworks/dancing-glyphs/blob/master/Library/MetalScreenSaverView.swift

Irgendwelche Ideen? Kann ich OS X irgendwie sagen, dass der Timer bei jeder Bildschirmaktualisierung ausgelöst wird? Ist das ein Problem mit Metal? Ich habe Spiele und Bildschirmschoner gesehen, die im Akkubetrieb gut laufen, aber ich gehe von OpenGL aus.

Antwort

1

Wenn ich Ihren Code richtig lese, gehen Sie davon aus, dass CVDisplayLink in einem unveränderlichen Intervall aufgerufen wird. Das ist überhaupt nicht versprochen. Das System ist absolut frei, das Aktualisierungsintervall zu ändern oder Frames zu löschen. Alle Echtzeitsysteme müssen die Möglichkeit haben, Frames zu löschen. Das ist das Herz dessen, was es heißt, "Echtzeit" zu sein.

Sie haben die Zeit "aktuell angezeigt" und die Zeit "Zielausgabe" überschritten. Sie sollten diese verwenden, um den richtigen Frame für die Zielausgabe zu berechnen. Ich sehe nicht, dass Sie die Ausgabezeit in Ihrem Code verwenden.

+0

Danke. Ich verstehe, was Sie schreiben, und obwohl ich die Animation auf die verstrichene Zeit basiere, abgerufen mit 'CACurrentMediaTime', werde ich versuchen zu sehen, ob die Verwendung der Zeit, die als Argument für den Rückruf vergangen ist, einen Unterschied machen wird. Das heißt, meine eigentliche Frage ist, welchen Ansatz Sie wählen sollten, wenn Sie einen Timer bekommen wollen, der Frames nicht überspringt, solange mein Code schnell genug ist und das System sonst nicht stark belastet wird. Spielentwickler müssen einen Weg haben, dies zu tun, oder ihre Spiele würden auch Frames im Akkubetrieb verpassen, richtig? –

+0

Das System kann Frames zur Energieeinsparung freilassen. Ich glaube, man kann eine Aussage über die Stromversorgung machen, um zu verlangen, dass das System nicht in den Modus mit niedrigerer Leistung geht, aber dies ist beleidigend, es sei denn, man muss es wirklich haben (da du den Akku viel schneller verbrennst). Im Allgemeinen, wenn Sie die Ausgabezeit (nicht aktuelle Zeit) verwenden, sollte es glatt sein. https://developer.apple.com/videos/play/wwdc2012/711/ –

+0

Um ehrlich zu sein, kann ich das Stottern jetzt nicht reproduzieren, selbst wenn ich 'CACurrentMediaTime' verwende. In jedem Fall ist die Verwendung der Ausgabezeit, die an den Rückruf übergeben wurde, wie in Ihrer Antwort vorgeschlagen, eine Verbesserung und ich habe sie jetzt implementiert. Also werde ich das als die richtige Antwort (für mich) akzeptieren. –

Verwandte Themen