Was heißt "VSync" - und wie wendet man es an?
12. März 2004 / von aths / Seite 1 von 2
VSync, Triple Buffer, Prerender Limit: Was heißt das konkret? Dies soll heute unser Thema sein.
VSync ist die Abkürzung für "Vertical Synchronization". Um zu verstehen, was damit gemeint ist, muss man die Arbeitsweise des Monitors kennen. Auf der Grafikkarte gibt es einen so genannten RAMDAC. Das ist der RAM Digital-Analog-Converter. Dieser Baustein (der seit längerem direkt in der GPU integriert ist) liest den Grafikkarten-Framebuffer aus und wandelt die dortigen Farbwerte in ein analoges Signal um. Die Auslesegeschwindigkeit beim "Scanout" hängt direkt von der Monitorfrequenz ab. Angenommen, wir fahren die Auflösung 1024x768 bei 85 Hz. Dann hat man pro Bild 1/85-tel Sekunde Zeit. In dieser Zeit sind 768 Zeilen zu lesen.
Pro Zeile werden 1024 Pixel aus dem Grafikkarten-RAM vom RAMDAC eingelesen und in ein analoges Signal gewandelt. Die Zeile wird vom Röhrenmonitor mittels einem Kathodenstrahl aufgebaut. Am Ende der Röhre befindet sich eine Kathode, dort werden Elektronen freigesetzt und mit Hilfe von Elektromagneten beschleunigt. Durch elektrisch gesteuerten Magnetismus kann der Strahl von der Steuerlogik im Monitor abgelenkt werden.
Der aus Elektronen bestehende Kathodenstrahl wird nun so geführt, dass er die erste Zeile abstreift. Die jeweilige Stärke des Strahls hängt vom Signal ab, welches am Monitor anliegt. Genau dieses Signal erzeugt der RAMDAC aus dem Framebuffer. Der Kathodenstrahl regt die Leuchtschicht der Röhre an. Die Elektronen schießen dabei nicht etwa durch, sondern die Schicht sendet Photonen aus – also Licht. Das Leuchten nimmt unser Auge wahr - und wir sehen schließlich etwas auf dem Monitor.
Wenn der Strahl die erste Zeile abgefahren hat, schaltet der Monitor ihn ab. Die Elektromagneten in der Röhre fahren die Position an den Anfang der nächsten Zeile. Der Strahl wird wieder aktiviert, und er überstreicht die nächste Zeile. Das geht bis zum Ende der letzten Zeile. Dort angelangt, wird der Strahl abgeschaltet und an den Anfang der obersten Zeile positioniert, um das nächste Bild aufzubauen.
Der Monitor schickt den Strahl für jede Zeile von links nach rechts und pro Zeile ein Stücken weiter nach unten. Kennt man die Zeilenfrequenz eines Monitors, kann man zurückzurechnen, welche Wiederholrate er bei einer gegebenen Auflösung schafft. Angenommen, wir wollen 1024x768 fahren. Die 768 multiplizieren wir mit 1,1 (stark vereinfacht gesagt sind die 10% für unsichtbare Zeilen). Wir haben also rund 845 "effektive" Zeilen pro Bild, von denen aber nur 768 wirklich nutzbar sind. 100 kHz Zeilenfrequenz entsprechen 100000 Hz. Die Rechnung lautet damit 100000 / 845. Als Ergebnis bekommt man 118 Hz Bild-Frequenz. Mit etwas Quälerei wären 120 Hz drin, aber es wird empfohlen, einen Monitor nur zu 85% auszunutzen. Wir kommen dann auf ziemlich genau 100 Hz als optimalen Wert für unser Beispiel.
Das beste wäre in diesem Fall, wenn die Grafik-Engine mit genau 100 fps liefe. Das ist natürlich fast nie der Fall. Hier kommt nun VSync ins Spiel. Meistens arbeiten die Grafikkarten mit Double Buffering. Dann gibt es einen Front- und einen Backbuffer. Während der Frontbuffer angezeigt wird, rendert die Karte das neue Bild in den Backbuffer. Ist das Bild fertig, sendet die Engine ein Signal zum "Swap". Die Grafikhardware vertauscht nun die Adressen von Front- und Backbuffer. Der RAMDAC liest dann aus dem ehemaligen Backbuffer, der dank Adressentausch jetzt Frontbuffer ist.
Dabei interessiert den RAMDAC jedoch nicht, wann der Swap erfolgte, er macht ungerührt weiter. Das heißt, ist der Bildaufbau gerade in der Mitte, wird ab dort das neue Frame angezeigt - das letztlich auf dem Monitor angezeigte Bild stammt also eigentlich aus zwei unterschiedlichen Frames. Vor allem bei links-rechts-Bewegung resultiert das in "Tearing", da man an dieser Stelle einen "Riss" erkennt: Obere und untere Hälfte sind (an der Bruchstelle der beiden Frames) zueinander versetzt.
Aktiviertes VSync verhindert nun dieses Tearing. Wenn die Engine den "Swap"-Befehl gibt, verzögert die Grafikkarte die Ausführung des Befehls solange, bis der RAMDAC die letzte Zeile des Bildes gelesen und in das Monitorsignal umgewandelt hat. Dann sendet er nämlich ein Signal, welches abgefragt werden kann. Bei "VSync on" wird nun in der Zeit, während der Kathodenstrahl nach links oben positioniert wird, geswappt. Man sieht auf dem Monitor immer nur ganze Frames, ohne Risse. Doch dieses Verfahren hat auch Nachteile.
Liefe das Spiel ansonsten mit 110 fps, sehen wir jetzt nur noch 100 Bilder pro Sekunde. Das ist natürlich kein echtes Problem. Aber wenn die Grundgeschwindigkeit unter 100 fps sinkt, bekommen wir nur noch 50 fps auf dem Monitor zu sehen. Warum das?
Sagen wir, die Grundgeschwindigkeit wäre 80 fps und wir haben den Monitor auf 100 Hz gestellt und VSync aktiviert. Das heißt, alle 12,5 Millisekunden würde ein neues Bild fertig, und alle 10 Millisekunden könnte ein neues Bild angezeigt werden. 12,5 Millisekunden Rechnenzeit und 10 Millisekunden Anzeige heißt, ein Bild wird jetzt zwei Zyklen lang angezeigt. Denn wenn schon geswappt werden könnte, ist das neue Bild noch nicht fertig. Also wird der Swap verzögert.
Jedesmal gehen 7,5 Millisekunden verloren, in denen die Grafikkarte wartet, um vertikal zu synchronisieren. Die vertikale Richtung ist die von unten nach oben (oder anders herum). Der Kathodenstrahl wird am Ende des Scanouts von unten nach oben positioniert, hiermit wird nun synchronisiert. Horizontale Sychronisation (HSync) fragt ab, wann der Kathodenstrahl auf eine neue Zeile springt, doch das soll unser Thema heute nicht sein.
Pro Bild haben wir jetzt 12,5 Millisekunden Rechen- und 7,5 Millisekunden Wartezeit, was 20 Millisekunden pro Frame ergibt. Das heißt, 50 fps. Sinkt die Grundgeschwindigkeit unter 50 fps, resultiert die tatsächliche Geschwindigkeit in 33,3 fps: Jedes Bild wird drei Zyklen lang anzeigt. Es läuft also auf ganzzahlige Vielfache hinaus.
Bildwiederholrate | entsprechend mögliche fps: |
60 Hz | 60, 30, 20, 15, 12, ... fps |
75 Hz | 75, 38, 25, 19, 15, ... fps |
85 Hz | 85, 42, 28, 21, 17, ... fps |
100 Hz | 100, 50, 33, 25, 20, ... fps |
120 Hz | 120, 60, 40, 30, 24, ... fps |
Tatsächlich ereichbare Geschwindigkeiten mit VSync und Double Buffering |
Der große Nachteil von VSync ist nicht das Abschneiden "oben", sondern der große Performance-Verlust, wenn man fps-mäßig zwar in der Nähe der Bildwiederholfrequenz ist, aber eben knapp darunter. Um diesen Effekt abzufangen, gibt es Triple Buffering.
Triple Buffering arbeitet mit zwei Backbuffern, nennen wir sie A und B. Das erste Bild wird in Backbuffer A gerendert. Ist es fertig, kommt das nächste Bild sofort in Backbuffer B (die Backbuffer werden also geswappt). Wenn der RAMDAC das neue Bild anfängt, nimmt er automatisch den aktuellsten Backbuffer. Das heißt, bei 90 fps und 100 Hz werden auch 90 Bilder pro Sekunde angezeigt. 10 davon (also jedes 9) sind zwei Zyklen lang sichtbar.
Mehr als 100 fps sind logischerweise nicht drin, da jedes Bild mindestens einen vollen Bildaufbau lang angezeigt wird. Die GPU muss aber nur noch dann warten, wenn sie mehr fps rendert, als der Monitor Bilder pro Sekunde aufbaut. Ansonsten kann sie in den zweiten Backbuffer rendern. Da wir davon ausgehen, dass der Monitor häufiger das Bild aufbaut, als die Engine an fps liefert, ist garantiert immer ein Backbuffer frei.
Natürlich gibt es mit Triple Buffering auch Nachteile. Einerseits wird die Bildausgabe um ein weiteres Frame verzögert. Andererseits steht weniger Speicher für Texturen zur Verfügung, da ein kompletter Backbuffer nicht gerade klein ist. Bei 1024x768 verbraucht man mit Triple Buffering immerhin 3 MB zusätzlichen Framebuffer-Speicherplatz, bei 4x Anti-Aliasing "on Scanout" (auf GeForceFX ab NV35) sind es sogar 12 MB.
Dieser Unterschied erklärt sich im übrigen folgermaßen: "Normalerweise" wird sofort downgefiltert. Dazu werden bei 4x Anti-Aliasing die vier Farbwerte gelesen und die Mischfarbe als Pixel wird wieder geschrieben. Beim "Downfilter on Scanout" liest die RAMDAC-Logik die vier Farbwerte und mischt sozusagen on-the-fly das finale Pixel zusammen. Man spart sich dabei den Schreibzugriff des fertig gefilterten Pixels in den Framebuffer.
Falls die Framerate deutlich unter die Bildwiederholrate des Monitors sinkt, ist der Gesamt-Speicherbandbreitenverbrauch natürlich größer, da der RAMDAC für jedes angezeigte Bild dann immer vier Subpixel lesen muss, statt einem Pixel. Übrigens wurde die "on Scanout"-Filtertechnik für 2x FSAA mit Voodoo4 und 5 eingeführt, und fand dann in die GeForce4 Ti Einzug. Ab GeForceFX 5900 wie gesagt wird auch 4x AA on-the-fly gefiltert.
Nicht immer führt Triple Buffering auch wirklich dazu, die großen Performance-Sprünge umgehen zu können. Zum Beispiel hat diese Option keinen Effekt, wenn zwei Bildschirme aktiv sind.
Ansonsten jedoch ist der Effekt von "Enable Triple Buffering" (beispielsweise im aTuner aktivierbar) in Quake III einwandfrei nachzuweisen. Hierzu muss in der Konsole /r_swapinterval 1 gesetzt werden, und im Treiber (oder aTuner) VSync auf "Standardeinstellung ein" (bzw. "default on"). In Max Payne bzw. Max Payne 2 kann man Triple Buffering im Optionen-Menü anfordern, VSync muss dabei im Treiber aktiviert werden:
Ein Klick, der sich lohnt.