Warum ist die Frame-Rate in WPF Unregelmäßig und Nicht Beschränkt Auf Monitor Refresh?
Ich bin das Messen der Zeit zwischen frames in einer einfachen WPF-animation. Perforator, sagt die app führt bei ~60fps, so erwartete ich die Zeit zwischen den frames auf ~16,6 ms mit wenig Abweichung.
public MainWindow()
{
...
CompositionTarget.Rendering += Rendering;
}
List<long> FrameDurations = new List<long>();
private long PreviousFrameTime = 0;
private void Rendering(object o, EventArgs args)
{
FrameDurations.Add(DateTime.Now.Ticks - PreviousFrameTime);
PreviousFrameTime = DateTime.Now.Ticks;
}
Zwei Dinge haben mich überrascht:
- Zeit zwischen den frames ist ziemlich unregelmäßig
- Zeit zwischen frames von ~8ms. Ich hatte erwartet, dass die Bildwiederholrate des Monitors würde eine untere Schranke für die Zeit zwischen frames (ie. 60 Hz = 16,6 ms zwischen jedem frame, und alles, was schneller ist sinnlos).
Y - Zeit zwischen frames in Zecken (in 10.000 ticks = 1ms)
X - Frame-count -
Mögliche Störfaktoren
- Timer-Ungenauigkeit
- Wenn CompositionTarget.Rendering nicht wirklich korrelieren die Zeichnung der single-frame
Das Projekt, das ich verwende: SimpleWindow.zip
===Edit
Markus darauf hingewiesen, ich könnte mit RenderingEventArgs.RenderingTime.Zecken anstelle von DateTime.Nun.Zecken. Ich wiederholte den Lauf und bekam sehr unterschiedliche Ergebnisse. Der einzige Unterschied ist das timing-Methode:
DateTime.Nun.Zecken
RenderingEventArgs.RenderingTime.Zecken
Daten aus RenderingEventArgs produziert Daten, die viel näher der erwartete 16,6 ms/frame, und es ist konsistent.
- Ich bin mir nicht sicher, warum DateTime.Jetzt und RenderingEventArgs würde produzieren, die sehr unterschiedliche Daten.
- Vorausgesetzt RenderingEventArgs ist die Herstellung von korrekten Zeiten, es ist noch ein wenig befremdlich ist, dass diese Zeiten nicht den erwarteten 16,6 ms.
Wenn die Anzeige aktualisieren alle 16,6 ms und WPF aktualisiert wird jeden mit 14,9 ms, können wir erwarten, dass eine race-condition führen würde reißen. Das heißt, etwa jeden 10ten frame WPF wird versucht, zu schreiben sein Bild während der Anzeige zu Lesen versucht, das Bild.
- Die Stopwatch-Klasse ist der Weg zu gehen, um zu vermeiden, timer-Ungenauigkeit
- diese "könnten" nützlich sein: rhnatiuk.wordpress.com/2008/12/21/wpf-video-playback-problems - ich bin nicht sicher, wie relevant dieses Problem ist, aber ich denke, es existiert noch heute.
- Zeit der Messung gar nicht gebraucht! Sie können cast EventArgs zu RenderingEventArgs, um die RenderTime
- Ich vermute Roman ist auf etwas. Ich möchte seinen Artikel enthalten Daten. Ohne Daten, seine Artikel liest sich wie eine Meinung (Urteil, aber noch nicht 'Tat').
- Natürlich! Ich fühle mich dumm. Danke 🙂
- Generiert man ein video frame in WPF und die Anzeige-Ausgabe-Gerät ist in der Mitte des Rahmens, wird WPF Verzögerung der Anwendung code bis zum start des nächsten Rahmens und dann die Daten anzeigen, oder wird WPF sofort einen snapshot der Anzeige von Daten und zur Rückkehr, so dass eine Treiber-task zum kopieren der Daten in den display-Puffer auf die entsprechende Zeit? Meine Vermutung wäre, dass es tut letzteres, was bedeuten würde, dass die Zeiten, in denen die macht ergänzen wäre random, auch wenn Sie angezeigt wird, synchronisiert mit der physischen Ausgabe.
- irgendeine Idee, wie ich testen kann Theorie?
- Überprüfen Sie die Ergebnisse mit einer Stoppuhr-Objekt. Die Zeit zurückgegeben, die von DateTime.Nun kann man nicht mehr genau; ein Stoppuhr-Objekt, auf einem einzelnen CPU-Kern soll vieles besser werden. Beachten Sie, dass auf einigen multi-core-Maschinen, ein Stoppuhr-Objekt erstellt auf einem Kern und Lesen auf einem anderen kann ausgeschaltet werden durch einen bestimmten Betrag die in der Regel konstant für ein gegebenes paar von Kernen, es sei denn, die Maschine neu gestartet wird.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich diese Frage mit dem WPF-team und hier ist eine Zusammenfassung der Antwort, die ich erhielt:
Besonderen Dank an Dwayne Müssen für die Erklärung dieses für mich.
Ersten - 'Christopher Bennage s-Antwort hat eine gute Erklärung und stellt einen Hinweis für eine Lösung:
"Nur "pro-frame" - Arbeit, wenn das gemeldete frame-Zeit verpasst"
Dies ist ein wenig schwer, da die RenderingEventArgs versteckt sind als die normalen EventArgs und ein cast durchgeführt werden muss.
Machen Sie diese ein wenig easyer, eine passende Lösung gefunden werden kann, in "EVAN' S CODE ABWRACKPRÄMIE"
http://evanl.wordpress.com/2009/12/06/efficient-optimal-per-frame-eventing-in-wpf/
Nahm ich seinen code und modifiziert ihn ein wenig. Jetzt nimm einfach meine geschnippelt, fügen Sie die Klasse in Ihrem Projekt verwenden CompositionTargetEx wurden Sie verwendet CompositionTarget und Sie sind gut 🙂
WPF ist nicht entworfen, um eine Konstante frame rate rendering-system. WPF rendert Bildschirm, wenn die Elemente im Bildschirm werden als geändert markiert. Das rendering-system läuft als ein message-loop, so gibt es keinen Weg, um sicherzustellen, dass ein frame gerendert wird in bestimmten Intervallen.