Shader

Hardware- oder Software-Module, die bestimmte Bildsynthese-Effekte bei der 3D-Computergrafik implementieren
(Weitergeleitet von Shader-Cluster)

Shader („Schattierer“ von englisch shade für Schatten) sind Hardware- oder Software-Module, die bestimmte Rendering-Effekte bei der 3D-Computergrafik implementieren.

Hardware-Shader

Bearbeiten

Hardware-Shader (auch Shadereinheiten, Shader Units) sind kleine Recheneinheiten in aktuellen Grafikchips (unter Windows seit DirectX-Version 8, plattformunabhängig seit OpenGL 2.0 ansprechbar). Shader können zur Erzeugung von 3D-Effekten programmiert werden. Während Fragment-Shader die Fragmente verändern und somit letztendlich die resultierende Pixelfarbe berechnen können, dienen Vertex-Shader geometrischen Berechnungen und dynamischen Veränderungen von Objekten. So erzeugen z. B. beide Shader kombiniert den Wassereffekt im Computerspiel Far Cry. Sie können auch zur Simulation von Lava, Lack, Fell usw. eingesetzt werden. Seit DirectX 10 bzw. OpenGL 3.2 ist als dritter Shader-Typ der Geometry-Shader hinzugekommen, der die vom Vertex-Shader ausgegebenen Polygondaten erhält und diese noch weit flexibler bearbeiten kann, sogar weitere Geometrie zur Szene hinzufügen kann (der Vertex-Shader kann nur bestehende Geometrie manipulieren). Mit DirectX 11 bzw. OpenGL 4.0 ist der Tessellation Shader hinzugekommen, der in zwei Schritten (Tessellation Control und Tessellation Evaluation (OpenGL Terminologie) bzw. Hull und Domain Shader (DirectX Terminologie)) die Geometrie zwischen dem Vertex und dem Geometry Shader verfeinern kann.

Shadereinheiten dürfen nicht als vom Rest getrennte Recheneinheiten (wie bspw. Koprozessoren) verstanden werden, sondern als fester Teil des Grafikchips innerhalb seiner Rendering-Pipelines. So ist der Vertex-Shader lediglich eine programmierbare T&L-Einheit, der Pixel-Shader entstand historisch aus dem Combiner – der genaue Aufbau der Shader-Hardware ist nicht vollständig dokumentiert. Konformität dieser Shader-Einheiten zu den Standards DirectX und OpenGL wird über den Grafiktreiber hergestellt.

Da sich der Funktionsumfang von Vertex- und Pixel-Shadern mit der Zeit immer weiter erhöhte, wurde letztlich das Konzept der Unified Shader entwickelt, bei dem der hardwareseitige Unterschied zwischen Vertex- und Pixel-Shader verschwindet. Dies hatte zudem den Vorteil, dass für die später hinzugefügten Shaderarten (Geometry und Tessellation) keine spezielle Hardware nötig war, das heißt, sie werden mit der gleichen Hardware implementiert, die auch Vertex- und Pixel-Shader nutzen. Hierbei können alle Shader-Einheiten des Grafikchips nun dieselben Operationen ausführen, womit eine feste Trennung zwischen den Shader-Typen nicht mehr sinnvoll ist. Infolgedessen kann nun der Grafiktreiber selbst entscheiden, welche Shader-Einheit zu welchem Zeitpunkt wie eingesetzt wird, was potenziell eine bessere Leistungsausbeute als bei Grafikkarten mit fest eingeteilten Shader-Typen bedeutet.

Verarbeitungskette

Bearbeiten
  • CPU sendet Steuerbefehle und Geometrie-Daten an die Grafikkarte.
  • Im Vertex-Shader werden die Eckpunkte der Geometrie transformiert.
  • Im Tessellation-Shader (genauer: Tessellation-Control-Shader und Tessellation-Evaluation-Shader) können die Primitive (z. B. Dreiecke) weiter unterteilt werden.
  • Ist ein Geometry-Shader auf dem Grafikchip vorhanden und aktiv, durchlaufen die Geometriedaten nun diesen, hierbei werden weitere Veränderungen an der Szene vorgenommen.
  • Nun wird das Primitiv rasterisiert, wobei einzelne Fragmente erstellt werden. Die nur pro Eckpunkt (Vertex) vorliegende Informationen werden hierbei über die Dreiecksfläche interpoliert.
  • Im Fragment-Shader (Pixel-Shader) gibt es arithmetische Rechenwerke (Shader Units) und Textur-Einheiten (Texture Mapping Units, TMUs).
  • Nachdem die Fragmentberechnung abgeschlossen ist, wird der Test auf Sichtbarkeit (Z-Test) ausgeführt. Bei Sichtbarkeit findet ein Schreibvorgang in den Framebuffer statt. Dieser Schritt kann unter bestimmten Umständen bereits direkt nach der Rasterisierung vorgenommen werden (Early Z-Test).

Programmierung

Bearbeiten

Shader werden in speziell dafür vorgesehenen Sprachen geschrieben (in den Anfängen: Assemblersprache, heute: Cg, GLSL, HLSL) und zur Laufzeit der 3D-Anwendung vom Grafikkartentreiber in einen für die Grafikkarte verständlichen Maschinencode übersetzt, der dann in den Shadereinheiten ausgeführt wird. Bei Lowcost-Grafikchips werden die Shadereinheiten aber häufig weggelassen, wodurch die Shader mit Hilfe der CPU berechnet werden müssen, was wesentlich langsamer ist.

Damit die Funktionalität der Shader auch einheitlich von Anwendungen genutzt werden kann, bieten sowohl DirectX als auch OpenGL Schnittstellen für ihre Anwendung. Im Laufe der Zeit haben Funktionsumfang und Leistungsfähigkeit der anfangs noch ziemlich einfachen Shadereinheiten stark zugenommen; heute ist ihre Programmierbarkeit so weit fortgeschritten, dass man mit ihnen viele Berechnungen erledigen kann, die bisher nur CPUs ausführen konnten, oftmals sogar wesentlich schneller. Dies wird als General Purpose Computation on Graphics Processing Unit bezeichnet.

Problematik mit verschiedenen Versionen

Bearbeiten

Die ersten Direct3D und OpenGL Versionen unterstützten keine Hardware-Shader. OpenGL bot dies lediglich in Form von sogenannten herstellerspezifischen Extension an, was dazu führte, dass jeder Hardwarehersteller seine eigene OpenGL Extension hatte, um die herstellereigenen Hardware-Shader damit anzusprechen. In Direct3D war die Verwendung von Hardware-Shadern anfangs nicht möglich. Daher wurden mit späteren Direct3D und OpenGL Versionen ein standardisierter API Zugriff auf die Hardware-Shader geschaffen. Die Funktionalität der ersten Hardware-Shader war anfangs allerdings noch stark eingeschränkt, so gab es bspw. Längenbegrenzungen bezüglich der Anzahl der Befehle, die pro Shader Programm abgearbeitet werden konnten. Diese Beschränkungen wurden auch auf die APIs abgebildet, so dass spätere Hardware-Shader mit mehr Leistung und Funktionen auch eine Erweiterung der jeweiligen APIs erforderte, was dazu führte, dass dies in späteren API Versionen dann berücksichtigt wurde und bspw. jede neue Direct3d Version eine neue Shaderversion unterstützte. Infolgedessen unterstützt nicht jeder Grafikchip jede Shaderversion, es ist keine Aufwärtskompatibilität gegeben. Das bedeutet, dass man bei der Programmierung von 3D-Grafikanwendungen mit Shadern darauf achten muss, dass eine Ausweichlösung für ältere Grafikkarten existiert, die die eigentlich angestrebte Shaderversion nicht unterstützen, ansonsten können sie die Grafik gar nicht oder nur stark verändert darstellen. Wenn eine Anwendung mehrere Shader-Lösungen für verschiedene Shaderversionen bzw. verschiedene Grafikkarten enthält, nennt man diese Lösungen Renderpfade (englisch rendering path). Gerade in den Phasen, in denen die damaligen Grafikkarten-Hauptkonkurrenten ATI und Nvidia eigene spezielle Shader-Versionen veröffentlichten, war es häufig nötig und daher gängig, zwei (oder auch mehr) Renderpfade in Anwendungen einzubauen: einen ATI-optimierten und einen Nvidia-optimierten, ggf. auch noch weitere.

Unter Direct3D, der 3D-Grafikschnittstelle von DirectX, werden Shader in der Sprache HLSL programmiert, wobei je nach DirectX-Version verschiedene Shader-Versionen angeboten werden. Die folgende Tabelle zeigt den Zusammenhang zwischen den einzelnen DirectX- und Shader-Versionen:

DirectX
Version
Shader Bemerkungen
 Pixel  Vertex Geometry Domain  Hull 
08.0 1.0 1.0 war für den 3dfx Rampage vorgesehen, der jedoch nie auf den Markt kam
1.1 1.0 kleinster gemeinsamer Nenner für alle DirectX-8-Grafikchips (z. B. ATI-Radeon-7000-Serie)
08.0a 1.2 1.0 speziell von den 3DLabs-Grafikchips P9 und P10 unterstützt
1.3 speziell von der Nvidia-GeForce-4-Ti-Serie, der Matrox Parhelia und dem SiS Mirage 2[1] unterstützt
08.1 1.4 speziell von der Radeon-8000-Serie und der XGI-Volari-V3-Serie unterstützt
09.0 2.0 2.0 kleinster gemeinsamer Nenner für alle DirectX-9-Grafikchips
09.0a 2_A 2.x speziell von der Nvidia-GeForce-FX-Serie unterstützt
09.0b 2_B speziell von der ATI Radeon X7xx und X8xx unterstützt
09.0c 3.0 3.0 gemeinsamer Nenner für modernere DirectX-9-Grafikchips (bspw. ab Nvidia-GeForce-6-Serie)
10.0 4.0 4.0 4.0 Unified Shader Model, Geometry-Shader (bspw. ab Nvidia-GeForce-8-Serie)
10.1 4.1 4.1 4.1 Gather4, lesen von Z-Werten aus Buffern mit Anti-Aliasing
11 5.0 5.0 5.0 5.0 5.0 Unterstützung für Tesselation durch Domain- und Hull-Shader in Verbindung mit einer Tesselationseinheit

In OpenGL ist ab Version 2.0 eine eigene C-ähnliche Shader-Sprache integriert, die OpenGL Shading Language, kurz GLSL.[2] Zuvor war Shaderprogrammierung nur durch herstellerspezifische OpenGL Extensions möglich. Durch den Einsatz von GLSL ist man für den Zugriff auf Shadern nicht mehr auf die Verwendung herstellerspezifischer OpenGL Extensions beschränkt.

Literatur

Bearbeiten
  • Uli Theuerjahr: Direct3D Real Time Rendering für Computerspiele. DirectX-Programmierung in C++. Roulio Press, Schönberg 2007, ISBN 978-3-00-022340-2.
Bearbeiten

Einzelnachweise

Bearbeiten
  1. AnandTech: A Place for SiS; New Athlon64, P4 and Integrated Graphics Chipsets, Artikel vom 27. Juli 2004 (englisch)
  2. OpenGL.org: OpenGL Shading Language (Memento des Originals vom 22. Oktober 2016 im Internet Archive)  Info: Der Archivlink wurde automatisch eingesetzt und noch nicht geprüft. Bitte prüfe Original- und Archivlink gemäß Anleitung und entferne dann diesen Hinweis.@1@2Vorlage:Webachiv/IABot/www.opengl.org, Dokumentation zur GLSL