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.