Welches Problem löst die doppelte oder dreifache Pufferung in modernen Spielen?

31

Ich möchte überprüfen, ob ich die Ursachen für die Verwendung der doppelten (oder dreifachen) Pufferung richtig verstanden habe:

Bei einem Monitor mit 60-Hz-Aktualisierung wird der Monitor 60 Mal pro Sekunde angezeigt. Wenn der Monitor die Monitoranzeige aktualisiert, aktualisiert er Pixel für Pixel und Zeile für Zeile. Der Monitor fordert die Farbwerte für die Pixel aus dem Videospeicher an.

Wenn ich jetzt ein Spiel starte, dann manipuliert dieses Spiel ständig diesen Videospeicher.

Wenn dieses Spiel keine Pufferstrategie verwendet (Doppelpufferung usw.), kann das folgende Problem auftreten:

Der Monitor aktualisiert nun seine Monitoranzeige. Zu diesem Zeitpunkt hatte der Monitor die erste Bildschirmhälfte bereits aktualisiert. Gleichzeitig hatte das Spiel den Videospeicher mit neuen Daten manipuliert. Nun greift der Monitor für die zweite Monitorhälfte auf diese neu manipulierten Daten aus dem Videospeicher zu. Die Probleme können reißen oder flackern.

Ist mein Verständnis der Fälle der Verwendung der Pufferstrategie korrekt? Gibt es noch andere Gründe?

krokvskrok
quelle

Antworten:

62

Grundsätzlich ist es ein zentrales Ziel beim Rendern, dass jedes auf dem Monitor angezeigte Bild ein einziges zusammenhängendes Bild darstellt. Um dies zu erreichen, gibt es verschiedene Strategien, die angewendet werden oder wurden.

Im Folgenden erwähne ich "vsync". Vsync ist der Moment, in dem der Monitor ein neues Bildschirmbild zeichnet. Dies ist der Punkt, an dem "vblank" auf einem herkömmlichen CRT-Bildschirm beginnt, an dem die Scanlinie vorübergehend aufhört zu zeichnen und zum oberen Rand des Monitors zurückkehrt. Dieser Moment ist für viele Ansätze zur Rahmenkohärenz sehr wichtig.

"Zerreißen" ist das, was wir als "Zerreißen" bezeichnen, wenn ein Bildschirm aus zwei verschiedenen Bildern in einem einzigen Bild gerendert wird. Wenn ich zum Beispiel zwei Bildschirmbilder gezeichnet habe, die nacheinander angezeigt werden sollen, aber der Monitor stattdessen die obere Hälfte von Frame eins und die untere Hälfte von Frame zwei angezeigt hat, ist das "zerreißend". Dies ist darauf zurückzuführen, dass sich die Daten ändern, aus denen der Monitor liest, während er zeichnet, und nicht, während er leer ist. (In modernen Programmen geschieht dies normalerweise, weil der Benutzer das Warten auf vsync in seinen Treibereinstellungen deaktiviert hat.)

Null-Puffer

Auf der ältesten Hardware war häufig nicht genügend Speicherplatz vorhanden, um ein Vollbild aufzunehmen. Anstatt ein Bildschirmbild zu zeichnen, mussten Sie die Farben für jede Scanlinie einzeln festlegen, während der Monitor diese Linie zeichnete. Auf dem Atari 2600 hatten Sie zum Beispiel nur 76 Maschinenbefehlszyklen, um anzugeben, welche Farbe in jedes Pixel der Scanlinie fließt, bevor der Fernseher diese Scanlinie tatsächlich zeichnet. Und dann hatten Sie 76 Anweisungszyklen, um den Inhalt für die nächste Scanzeile bereitzustellen , und so weiter.

Einzelpuffer

Wenn Sie in einem "Einzelpuffer" -Kontext zeichnen, zeichnen Sie direkt in den VRAM, der vom Monitor gelesen wird. In diesem Ansatz "rennen Sie die Scanline". Die allgemeine Idee ist, dass, wenn die Scanlinie beginnt, den Inhalt des vorherigen Frames oben auf dem Bildschirm zu zeichnen, Sie dahinter in den VRAM zeichnen . Während die Scanlinie das Bildschirmbild für das letzte Bild zeichnet, zeichnen Sie das nächste Bild hinter der Scanlinie.

Im Allgemeinen versuchen Sie, das nächste Einzelbild fertig zu zeichnen, bevor die Scanlinie Sie "überlappt", indem Sie erneut vorbeikommen und die Pixel, die Sie zeichnen, überholen, und auch, um der Scanlinie oder Ihrer neuen niemals einen Schritt voraus zu sein Der Rahmen wird möglicherweise in den vorherigen Rahmen gezogen.

Aus diesem Grund hat sich das Rendern mit einem einzelnen Puffer in der Regel von selbst bewährt, indem Scanlinien von oben nach unten und von links nach rechts gezeichnet wurden. Wenn Sie in einer anderen Reihenfolge gezeichnet haben, ist es wahrscheinlich, dass die Scanlinie erneut auftritt und Teile des "nächsten" Bilds erkennt, die Sie noch nicht gezeichnet haben.

Beachten Sie, dass Sie in modernen Betriebssystemen in der Regel nie die Möglichkeit haben, einfach gepuffert zu zeichnen, obwohl dies vor dreißig Jahren ziemlich häufig war. (Meine Güte, fühle ich mich jetzt alt - genau das tat ich, als ich mit der Spieleentwicklung anfing?)

Doppelpuffer

Dies ist viel, viel einfacher als jede der Strategien, die vorher kamen.

In einem Doppelpuffersystem haben wir genug Speicher, um zwei verschiedene Bildschirmbilder zu speichern, und so bezeichnen wir einen von ihnen als den "vorderen Puffer" und den anderen als den "hinteren Puffer". Der "vordere Puffer" ist das, was gerade angezeigt wird, und der "hintere Puffer" ist das, was gerade gezeichnet wird.

Nachdem wir ein Bildschirmbild in den Hintergrundpuffer gezeichnet haben, warten wir bis vsync und tauschen dann die beiden Puffer aus. Auf diese Weise wird der hintere Puffer zum vorderen Puffer und umgekehrt, und der gesamte Swap fand statt, während der Monitor nichts zeichnete.

Dreifachpuffer

Ein bei Doppelpuffer-Ansätzen häufig auftretendes Problem besteht darin, dass wir nach dem Zeichnen im Hintergrundpuffer nur noch auf vsync warten müssen, bevor wir die Puffer austauschen und weiterarbeiten können. wir hätten in dieser Zeit rechnen können! Darüber hinaus wird das Bild in diesem Rückpuffer immer älter, während wir darauf warten, zwischen den Puffern zu wechseln, wodurch die vom Benutzer wahrgenommene Latenzzeit erhöht wird.

In Dreifachpuffersystemen erstellen wir uns drei Puffer - einen vorderen Puffer und zwei hinteren Puffer. Die Idee ist folgende:

Der Monitor zeigt den vorderen Puffer an, und wir ziehen in den hinteren Puffer # 1. Wenn wir das Zeichnen in den hinteren Puffer Nr. 1 beenden, bevor der Monitor das Zeichnen des vorderen Puffers beendet, dann beginnen wir statt auf vsync zu warten sofort mit dem Zeichnen des nächsten Frames in den hinteren Puffer Nr. 2. Wenn wir fertig sind und vsync noch nicht gekommen ist, ziehen wir uns zurück in den Backbuffer # 1 und so weiter. Die Idee ist, dass wenn vsync irgendwann passiert, der eine oder andere unserer hinteren Puffer vollständig ist und einer gegen den vorderen Puffer getauscht werden kann.

Der Vorteil der Dreifachpufferung ist, dass wir nicht die Zeit verlieren, die wir beim Doppelpufferungsansatz für das Warten auf vsync aufgewendet haben, und das auf den vorderen Puffer ausgelagerte Bild möglicherweise "frischer" ist als das, auf das vsync gewartet hat 8ms. Die Kehrseite der Dreifachpufferung ist, dass wir zusätzlichen Speicher zum Speichern des zusätzlichen Bildschirmbilds benötigen und dass unsere CPU / GPU-Auslastung höher sein wird (wieder, da wir nicht langsamer werden, um auf vsync zu warten).

In der Regel führen moderne Treiber hinter den Kulissen häufig eine transparente Dreifachpufferung durch. Sie schreiben Ihren Code, um eine doppelte Pufferung durchzuführen, und der Treiber gibt die Kontrolle tatsächlich frühzeitig an Sie zurück und verwaltet nur den Austausch zwischen so vielen Backpuffern, wie er verwenden möchte, ohne dass Ihr Code dies jemals bemerkt.

GPU-Anbieter empfehlen derzeit, die Dreifachpufferung nicht selbst zu implementieren - der Treiber erledigt dies automatisch für Sie.

Trevor Powell
quelle
7
Dies ist eine unglaublich detaillierte Antwort und erklärt, warum viele Dinge so gemacht werden, wie sie sind (wie der Bildschirmkoordinatenraum usw.). Beantwortete auch meine Frage "Warum nicht vierfache Puffer? Fünffach?" Ich habe nicht bemerkt, dass das Austauschen von Puffern im Hintergrund stattgefunden hat, was bedeutet, dass maximal zwei Back-Buffer erforderlich sind. Upvoted.
lunchmeat317
Tatsächlich gibt es eine Quad-Pufferung. Dies ist eine doppelte Pufferung für die stereoskopische Ansicht. swiftless.com/tutorials/opengl/smooth_rotation.html
Narek
@Narek Nein. Zitat aus Ihrem Link: "In Computergrafikumgebungen können Sie die tatsächliche Quad-Pufferung nicht aktivieren, da es keinen wirklichen Grund gibt." Zu behaupten, Doppelpufferung in zwei verschiedenen Ansichten gleichzeitig wäre "Vierfachpufferung", ist nur ein amüsantes Wortspiel. nicht etwas echtes.
Trevor Powell
@TrevorPowell Fügen Sie einen Teil hinzu, den Sie vergessen haben: "Normalerweise bezieht sich Vierfachpufferung auf Doppelpufferung in einer stereoskopischen Umgebung. Beispiel: Sie haben zwei Anzeigen, normalerweise für 3D-Zwecke, und jedes Auge ist doppelt gepuffert." Jetzt könnte der Kontext klarer sein.
Narek
@ TrevorPowell Dein Punkt ist aber völlig klar. Es ist nicht sinnvoll, mehr als 3 Puffer für einen Renderpuffer zu haben.
Narek