Nachdem wir uns in den letzten Artikeln mit evolutionären Algorithmen und künstlichen Neuronalen Netzen beschäftigt haben, soll es heute in einen ganz anderen Bereich gehen, und zwar in den de Computergrafik. Ganz konkret wollen wir uns mit der Frage beschäftigen, woher der Monitor eigentlich weiß, was er anzeigen soll, sprich: wie kommt die Grafik auf den Bildschirm?

Hardwareseitig sieht das so aus, dass ein Monitor eine Menge von Bildpunkten, die sogenannten Pixel, darstellt. Ein Pixel ist dabei ein einzelner Punkt auf dem Monitor in einer bestimmten Farbe. Die Menge der dargestellten Pixel bestimmt dabei die Auflösung des Monitors; kann dieser etwa maximal 1024 Pixel in der breite und 768 in der Höhe darstellen, so spricht man von einer Auflösung von 1024×768.
Die Farbe eines Pixel ergibt sich im Normalfall aus der Mischung der Farben Rot, Grün und Blau (dem sogenannten RGB-Farbraum); jede Farbe wird dabei durch ein einzelnes Byte (wir erinnern uns: das sind 8 Bit), also den Werten von 0 bis 255 codiert. Je höher der Anteil einer einzelnen Farbe an der Gesamtfarbe ist, desto mehr erscheint der Pixel in der entsprechenden Farbe; schwarze Pixel können durch drei 0en, weiße Pixel durch drei 255en dargestellt werden. Das Scienceblogs.de-Logo in einfachster Form, etwas farblich und in einer 10×10-Auflösung würde demzufolge in etwa so aussehen:

i-a7e5780b5508ec1f57ca2f68b9ad015f-Pixel-Sb.png

Die Information, welcher Pixel auf der Monitoroberfläche in welcher Farbe dargestellt werden soll, erhält der Monitor für gewöhnlich über das Monitorkabel vom Grafikchip oder der Grafikkarte des Rechners übermittelt (entweder auf analogem Weg, z.B. über den VGA-Ausgang, oder auf digitalem Weg, also etwa per DVI oder HDMI). Die interessante Frage ist nun aber, woher die Grafikkarte weiß, welche Pixelfarbe an welcher Monitorstelle gezeigt werden soll.

Wie vielen sicherlich bekannt ist, besitzen Grafikkarten oft über einen eigenen Arbeitsspeicher, zusätzlich zu dem eigenen des Rechners (und getrennt von diesem). Ein bestimmter Bereich dieses Arbeitsspeichers der Grafikkarte ist dafür reserviert, lediglich Daten zu diesem Zweck (gewissermaßen das darzustellende Bild im Arbeitsspeicher) aufzunehmen. Alle in diesem Bereich gespeicherten Pixelfarben landen (mehr oder weniger) direkt auf dem Monitor des Nutzers, indem sie von der Grafikkarte automatisch ausgelesen und an den Monitor geleitet werden. Um also die Anzeige auf dem Monitor zu ändern, also das nächste Bild darzustellen, müssen die Werte in diesem speziellen Arbeitsbereich geändert werden.Der zum obigen Bild passende Arbeitsspeicher-Bereich würde etwa für die ersten 4 Zeilen folgendermaßen aussehen; jeweils drei Byte (für die Werte Rot, Grün und Blau) repräsentieren hierbei ein Pixel, wobei man sich die Arbeitsspeicher-Zeilen eigentlich als hintereinander geschrieben vorstellen muss:

i-18632b616e52a9c6ca1bad5f3a28229c-Pixel-Ram.png

Das ganze Vorgehen hat allerdings ein kleines Problem: während ein neues Bild in den Arbeitsspeicher “gemalt” (eigentlich ja geschrieben) wird, existiert zeitweise eine unfertige Version des Bildes, da das Schreiben einige Zeit in Anspruch nimmt; im Ergebnis würde das Bild beständig flimmern, da immer wieder diese unfertigen Zwischenbilder angezeigt würden.

Die Lösung hierfür ist ebenso einfach wie elegant. Statt eines einzigen Bereiches für die grafische Ausgabe verwenden moderne Grafikkarten und -chips zwei oder mehr Bereiche dafür. Der aktuell angezeigte Bereich wird als Frontbuffer bezeichnet, der oder die nicht angezeigten Bereiche folgerichtig als Backbuffer. Ein weiterer im Speicher der Grafikkarte abgelegte Wert zeigt an, welcher Bereich gerade als Frontbuffer zu betrachten ist, indem er die Startadresse des entsprechenden Speicherbereiches enthält.

Der Backbuffer wird nun genutzt, um das als nächstes anzuzeigende Bild aufzunehmen, ohne dabei jedoch das aktuell angezeigte schon zu ändern. Während also das aktuelle Bild störungsfrei über den Frontbuffer angezeigt wird, kann in den Backbuffer bereits das nächste Bild geschrieben werden. Ist der Schreibvorgang beendet, wird einfach der Wert, welcher die Adresse des Frontbuffers anzeigt, auf die Adresse des Backbuffers gesetzt (das nennt man dann Page Flipping). Front- und Backbuffer wechseln also ihre Funktion und das soeben geschriebene Bild kann ohne Flimmern sofort angezeigt werden. Das nächste anzuzeigende Bild kann nun in den neuen Backbuffer (den vormaligen Frontbuffer) geschrieben werden, womit das Verfahren von vorne beginnt. Je nach Bedarf können auch mehrere Backbuffer zum Einsatz kommen, die parallel und zeitlich leicht versetzt geschrieben werden, so dass ein schnellerer Austausch der Front- und Backbuffer möglich ist. Kommen insgesamt 2 Buffer zum Einsatz (also ein Front- und ein Backbuffer), so spricht man vom Double Buffering; bei drei Buffern entsprechend vom Tripple Buffering. Die Rate, mit welcher der Austausch zwischen den Buffern erfolgt, bestimmt maßgeblich die sogenannte Framerate, also die Anzahl an Bildern, die pro Sekunde gezeigt werden. Je länger das vollständige Füllen eines Buffers dauert, desto langsamer können die Buffer vertauscht werden und desto geringer ist die Anzahl an Bildern, die pro Sekunde angezeigt werden.

Normalerweise übernimmt das Betriebssystem die Aufgabe, grafische Benutzeroberflächen (auch GUIs – Graphical User Interfaces genannt) darzustellen, indem es die Oberflächen entsprechend einer vorgegebenen Beschreibung über das oben beschriebene Verfahren in den Backbuffer malt und damit anzeigt. Dazu werden durch das Betriebssystem dynamisch berechnete oder vorgefertigte Farbmuster (gemeinhin bekannt als Bilder) für die entsprechenden Bestandteile der GUI (inklusive Buchstaben von Texten) an ihre jeweils passenden Stellen gezeichnet.

Manchmal reichen diese vorgefertigten Routinen des Betriebssystems jedoch nicht aus und ein Programm benötigt seine eigenen Funktionen, um grafische Inhalte darzustellen – das prominenteste Beispiel hierfür sind sicherlich die Computerspiele. Zu diesem Zweck stehen umfangreiche Programmbibliotheken zur Verfügung, so etwa die bekannten Grafikbibliotheken DirectX und OpenGL, welche ein Programm dabei unterstützen, Grafiken nach ganz individuellen Vorgaben möglichst performant auf den Bildschirm zu bringen.

Schauen wir uns das einmal am Beispiel eines 2D-Computerspiels an. Dem Spiel selber ist bekannt, welche Grafik an welcher Stelle auf dem Bildschirm angezeigt werden soll. Jede Grafik liegt dabei z.B. in Form einer einfachen Bitmap, also als simple Sammlung von Farbwerten für die Pixel der Grafik (nicht zu verwechseln mit dem BMP-Format), vor. Das Spiel zeichnet nun mit Hilfe von z.B. DirectX seine Grafiken an die gewünschte Position, indem es die Bitmaps an die passenden Stellen im Arbeitsspeicher der Grafikkarte schreiben lässt. Die verwendete Grafikbibliothek unterstützt hier insofern, als dass sie dieses Schreiben möglichst performant und mit geringem Programmieraufwand für den Programmierer erlaubt; so werden oft zu zeichnende Bitmaps zum Beispiel bereits “vorgeladen” und in freien Stellen des Grafikkarten-Arbeitsspeichers zwischengespeichert. Von diesen müssen sie nur noch an die gewünschte Stelle im Backbuffer kopiert werden, was weitaus schneller funktioniert als ein Laden und Schreiben aus dem Hauptspeicher oder, noch schlimmer, der Festplatte oder CD (dieser Vorgang wird auch Blitting genannt).

Neben den Werten für die Rot-, Grün- und Blauanteile eines Pixels kann eine Bitmap (und auch Front- und Backbuffer) übrigens auch über einen sogenannten Alpha-Wert verfügen, mit welchem die Transparenz eines Pixels bestimmt wird. Auf diese Art lassen sich auch überlappende Grafiken problemlos darstellen.

Von Interesse ist nun sicherlich für viele Leser, wie denn nicht nur 2D-, sondern auch 3D-Grafiken auf den Bildschirm kommen. Damit beschäftigen wir uns aber das nächste mal, da hierfür (mal wieder) einige mathematische Grundlagen notwendig sind.

Kommentare (8)

  1. #1 MartinB
    Juni 22, 2012

    Interessant, wieder was gelernt.

  2. #2 Fliegenschubser
    Juni 22, 2012

    Diese Serie verspricht, wie die anderen, sehr interessant zu werden. Ich freu mich auf die nächsten Artikel. 🙂

  3. #3 Geralt
    Juni 22, 2012

    Danke für den Artikel, wieder sehr interessant. Hast du evtl. mal die Muße eine Übersicht der Artikelserien einzustellen? evtl. so wie bei “hier wohnen drachen”:
    http://www.scienceblogs.de/hier-wohnen-drachen/artikelserien.php
    Damit würdest du meiner Faulheit sehr entgegenkommen 😉

  4. #4 Marcus Frenkel
    Juni 22, 2012

    @Geralt
    Oh, ja, das ist eine gute Idee. Sobald ich herausgefunden habe, wie das geht, werde ich das anlegen. 😉

  5. #5 Dr. Webbaer
    Juni 23, 2012

    Sie können’s in “Über das Blog” unten reinpacken oder einen Artikel schreiben, der Zusammenfassungen enthält unter wieder an zentraler Stelle dementsprechend verweisen.

    Ob und wie das hiesige Publikationssystem Strukturen direkt unterstützt, bleibt natürlich eine spannende Frage.

  6. #6 Marcus Frenkel
    Juni 23, 2012

    Im Hier wohnen Drachen-Blog gibt es einen separaten Punkt dafür in der Menüleiste. Ich suche noch, wie man den erstellt…

  7. #7 Stefan W.
    Juni 24, 2012

    {{{#!vorlage befehl
    da das Schreiben einige Zeit in Anspruch nimmt; im Ergebnis würde das Bild beständig flimmern, da ständig neue Pixelinformationen in den Speicher geschrieben werden und damit über den Monitor wandern würden.
    }}}
    So ist es nicht.

    Wenn die neuen Pixel langsamer bzw. asynchron in den Puffer geschrieben werden, wie dieser auf den Bildschirm gemalt wird, dann wird ja nach einem ersten Malen des oberen Bereichs des neuen Bildes, während im unteren noch das alte ist, nicht oben wieder das alte gemalt, also wieso sollte das flimmern?

    Es können lediglich Artefakte entstehen, wenn oben das neue Bild gemalt wird, aber unten noch nicht, weil die Berechnung des unteren Bildes so lange dauert.

    Selbst bei alten Bildschirmen war die Bildwiederholrate ja höher als die 21 Bilder/s, die flüssige Bewegungen sehen lassen.

    Das Flimmern kommt zustande, wenn man bewegte Bilder hat, und zwischen 2 Bildern das alte Bild löscht, weil man nicht mit Pixeln arbeitet, sondern beispielsweise einen Kreis bewegt, und nur Mittelpunkt und Radius kennt.

    Man könnte jetzt den schwarzen Kreis auf weißem Grund übermalen mit einem weißen Kreis, oder man malt den ganzen Bildschirm weiß, und dann den um 1 oder 3 oder wieviel auch immer versetzte Pixel. Und das ganz weiße Zwischenbild, wenn es zulange steht, kann dann sichtbar werden, und zum Flimmern führen.

    Deswegen malt man das ganz weiße Bild in den 2. Puffer, und da den Kreis versetzt gegenüber Puffer 1, und erst wenn man fertig ist, das ganze Bild neu, so dass nie zwischendurch die reine, weiße Leinwand gemalt wird.

  8. #8 Marcus Frenkel
    Juni 24, 2012

    @Stefan W.
    Ich habe die fragliche Textstelle einmal umformuliert, damit sie jetzt nicht mehr missverständlich sein kann…