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:
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:
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)