Review

Kampf der Titanen OpenGL 1.3 vs. DirectX 8.1 (Direct3D) !

Die Gegner


DirectX wurde von Microsoft entwickelt, um Windows für Spieleentwickler leichter und nutzbar zu machen. Man brauchte u.a. eine Schnittstelle für die 3D-Beschleunigerkarten - Direct3D. Microsoft kaufte also 1995 Rendermorphics Ltd - welche die RealityLab API entwickelten. Man bearbeitete diese ein wenig (Treiber Modell) und nannte sie Direct3D Immediate-Mode. Heute ist man bei Version 8.1 angelangt und die API hat nicht mehr viel mit der ersten Version gemein.
Im Folgenden werde ich zwar oft von DirectX (DirectDraw, DirectInput, Direct3D, DirectSound, DirectPlay) reden, meine aber meistens Direct3D. Leider läuft DirectX nur auf Microsoft Windows Systemen. Der Funktionsumfang der jeweiligen DirectX Version wird von Microsoft und ein paar Hardwareherstellern (NVIDIA, ATI, ...) festgelegt.
Die Neuerungen in Version 8.1 gegenüber Version 7.0 lassen sich recht kurz zusammenfassen.
  • Der Overhead der Vorgängerversionen wurde verringert
  • neue Textureformate
  • 3D Texturen
  • Unterstützung von High Order Surfaces
  • Pixel Shader (ersetzen die festen Textureoperationen (MODULATE, etc) -> eigene Programme können geschrieben werden)
  • Vertex Shader (ersetzen die feste T&L Einheit -> Vertexdaten können nun vom GPU verändert werden)


Vor einigen Tagen, am 14. August 2001 war es soweit, eine neuen Version (1.3) von OpenGL wurde vorgestellt. OpenGL wurde von SGI, in Zusammenarbeit mit anderen Hardware/Softwareherstellern, entwickelt. Es läuft auf Großrechnern, verteilten Systemen, Mac's, PC's uva. Der Funktionsumfang wird von einem
Konsortium (ARB - Architectural Review Board) verabschiedet, dem viele Hardware-/Softwarehersteller angehören.
Hier die Neuerungen:
  • Compressed Textures (komprimierte Texturen)
  • Cube Map Textures (6 2D Texturen, welche alle Seiten eines Würfels repräsentieren)
  • Multisample (für Anti-Aliasing benötigt, ein Bildschirmpixel wird aus mehreren Subpixeln berechnet)
  • Multitexture (es werden mehrere Texturen auf einen Pixel abgebildet)
  • Texture Add Environment Mode (neue Texturefunktion "ADD", Texturepixels können addiert werden)
  • Texture Combine Environment Mode (neue Texturefunktion "COMBINE", verscheidene Texturepixels können mittels math. Operationen kombiniert werden)
  • Texture Dot3 Environment Mode (neue Texturefunktion "DOT PRODUCT", RGB Skalarprodukt der Texturepixel)
  • Texture Border Clamp (neue Texturefunktion "CLAMP", Texturekoordinaten werden auf einen Bereich beschränkt, über den sie nicht hinaus können -> saubere Textureränder etc.)
  • Transpose Matrix (erlaubt es transponierte(aus Spalte wird Reihe!) Matrizen mit OpenGL zu verwenden, schnellere Speicheradressierung)


Quake 3 Arena hatte aber auch schon Multitexturing unter OpenGL bevor es die Version 1.3 gab!!!?!?!?


Wie der Name ("Open Graphics Library") bereits sagt, handelt es sich bei OpenGL um eine offene Schnittstelle. Unter der Verwendung von sogenannten Extensionen kann jeder Hersteller seine eigenen Funktionen einbauen.

Extensionen:

  • EXT_<Name> - herstellerspezifische Erweiterungen, nicht vom ARB abgenommen
  • ARB_<Name> - Erweiterungen, die vom ARB abgenommen wurden (werden von mehreren Herstellern unterstützt, können in späteren OpenGL Versionen zur Kernfunktionalität erhoben werden)
  • xxx_<Name> - andere herstellerspezifische Erweiterungen, z.B. WGL (Windows), NV (NVIDIA), ATI/ATIX (ATi), SGIS/SGIX (SGI), IBM (IBM), ....
Diese Funktionalität ist natürlich ein zweischneidiges Schwert. Einerseits lassen sich somit die gesamten Fähigkeiten einer bestimmten Hardware ausnutzten (z.B: Geforce 3 : Shadow Mapping - nur per OpenGL, da nicht in DX8 vorgesehen ist!!!), andererseits muss man auf viele Hersteller Rücksicht nehmen und ein eigenes Renderer-Backend schreiben, wenn man mehrere Karten unterstützten möchte. Genau dies tut auch die Quake 3 Engine - sie benutzt NVIDIA's, ATI's, 3dfx's, Matrox's OpenGL Erweiterungen.


Ist Microsoft's DirectX mit Version 8 nun also einfacher?

Eigentlich sollte man meinen "JA". Leider befinden wir uns aber bei Version 8 / 8.1.
Es fing alles so schön an. Mit der Freigabe von DirectX 8 wurden Spezifikationen für die Pixel und Vertex Shader herausgegeben.

Hier ein kurzer Überblick:

  • 4 Befehle werden simultan ausgeführt
  • 17 Befehle gibt es
    • ARL, RSQ, SLT, MOV, DP3, SGE, MUL, DP4, EXP, ADD, DST, LOG, MAD, MIN, LIT, RCP, MAX
  • Eingaberegister sind Verktoren (X,Y,Z,W)
  • das Vertexprogramm besteht aus max. 128 Befehlen
Vertex Shader

Mit den Vertex Attribut Registern werden Dinge wie Geschwindigkeit, Gewicht, Dichte ..... der einzelnen Eckpunkte festgelegt. Das Vertex Programm führt dann math. Operationen auf den Vertices aus, erzeugt allerdings keinerlei neue. Zum Schluss werden die bearbeiteten Vetices geclipped und kommen in die Vertex Resultat Register.
Die Vertex Shader machen auch keine Probleme, obwohl es laut Gerüchten 3 verschiedene Versionen/Spezifikationen geben soll.

Das Problem machen die Pixel Shader. Mit DirectX 8.1 sind die Versionen 1.0 bis 1.4 auf dem Markt. Bevor ich genauer auf die Pixel Shader eingehe, hier noch ein paar notwendige Informationen:

So werden aus S,T,R,Q die Texturekoordinaten gewonnen:

Texturekoordinaten 1D

Texturekoordinaten 2D

Texturekoordinaten 3D


Die Register

Name (# index)
I/O Berechtigung
min. Anzahl (für DX8)
max. Anzahl,
die pro Befehl verwendet werden dürfen

Quelle
c# nur lesen
8
2
API Aufruf
r# lesen / schreiben
2
2
Programm
t#
lesen / schreiben
4
1
Texture
v#
nur lesen
2
1
Vertex Farbe

Es gibt drei Arten von Befehlen:
  • Konstanten definieren
    • def c#, x, y, z, w (# geht von 0-7)
  • Texture Adressierungs Operationen
    • tex t0 (holt eine gefilterte Texture)
    • texbem tDest, tSrc0 (Bump Environment Map)
    • texbeml tDest, tSrc0 (Bump Environment Map mit Luminanz)
    • texcoord tDest (wandelt Texturekoordinate in Farbe um)
    • texkill tDest (löscht alle Texels, wo min. ein Parameter (s,t,r,q) kleiner 0 ist)
    • texm3x2pad tDest, tSrct0 (Füllbefehl, wird in Verbindung mit anderen OP's verwendet, um eine 2x3 Matrix zu füllen)
    • texm3x2tex tDest, tSrc0 (führt eine 3x2 Matrixoperation der Eingangsfarbvektoren aus )
    • texreg2ar tDest, tSrc0 (holt Texturesample, welcher durch Aplha / Rot Komponenten adressiert wird)
    • texreg2gb tDest, tSrc0 (holt Texturesample, welcher durch Grün / Blau Komponenten adressiert wird)
    • texm3x3pad tDest, tSrct0 ( Füllbefehl, wird in Verbindung mit anderen OP's verwendet, um eine 3x3 Matrix zu füllen)
    • texm3x3spec tDest, tSrc0, tSrc1 (berechnet Specular Reflection und Environment Mapping)
    • texm3x3vspec tDest, tSrc0 ( berechnet Specular Reflection und Environment Mapping mit unkonstantem Betrachtungsvektor)
    • texm3x3tex tDest, tSrc0 (berechnet 3x3 Matrixmultiplikation, setzt tDest als aktuelle Texture)
  • math. Operationen
    • add dest, src1, src2 (dest=src1+src2)
    • sub dest, src1, src2 (dest=src1-src2)
    • lrp dest, factor, src1, src2 (dest=factor*src1 + (1-factor)*src2)
    • dp3 dest, src1, src2 (dest=(src1.x*src2.x+src1.y*src2.y+....) - nur 3 Komponenten RGB )
    • mul dest, src0, src1 (dest=src0*src1)
    • mad dest, src0, src1, src2 (dest=src0*src1+src2)
    • mov dest, src (dest=src)
    • cnd dest, r0.a, src1, src2 (if r0.a>0.5 then dest=src1 else dest=src2)
    • Modifikatoren
      • r0.a (Alpha kopieren auf R,G,B)
      • 1-r0 (invertieren)
      • -r0 (negieren)
      • r0_bias (verschiebt Wert nach unten, y=x-0,5)
      • r0_bx2 ( verschiebt Wert nach unten und skaliert ihn um 2, y=2*(x-0,5) )
      • _x2 (verdoppelt Wert)
      • _x4 (vervierfacht Wert)
      • _d2 (halbiert Wert)
      • _sat (beschränkt den Wertebereich <0 auf 0 und >1 auf 1)

PS 1.0 - kein Hardwaresupport bekannt
  • bis zu 4 Anweisungen
  • Texture Register sind nur lesbar
  • EMBM benötigt zwei Texture Adressierungs Slots

PS 1.1 - Geforce 3, Radeon 8500
  • bis zu 8 Anweisungen
  • Texture Register sin lese- und schreibbar
  • EMBM benötigt einen Texture Adressierungs Slot

PS 1.2 - Geforce 3, Radeon 8500
  • wie PS 1.1
  • 4 neue Befehle
    • texreg2rgb tDest, tSrc0 (holt Texturesample, welcher durch Rot / Grün / Blau Komponenten adressiert wird)
    • texdp3 tDest, tSrc0 (berechnet Skalarprodukt von Texture tSrc0 mit den U,V,W Koordinaten von tDest )
    • texdp3tex tDest, tSrc0 (berechnet Skalarprodukt von Texture tSrc0 mit den U,V,W Koordinaten von tDest, setzt dann tDest als aktuelle Texture)
    • texm3x3 tDest, tSrc0 (wie texm3x3tex , setzt aber keine neue Texture)
  • 1 neuer Modifikator
    • r0.b (Blau kopieren auf Alpha)
  • 2 neue math. Operationen
    • dp4 dest, src1, src2 (dest=(src1.x*src2.x+src1.y*src2.y+....) - alle 4 Komponenten RGBA)
    • cmp dest, src0, src1, src2 ( dest= if (s0 >= 0.0) then s1 else s2, für jede Komponente RGBA )

PS 1.3 - Geforce 3, Radeon 8500
  • wie PS 1.2
  • 1 neuer Befehle
    • texm3x2depth tDest, tSrc0 ( berechnet Skalarprodukt von tn mit U,V,W von n+1, um Z zu bekommen, ebenfalls das Skalarprodukt mit U,V,W von n+2 um W zu bekommen, die Tiefe des aktuellen Pixels wird auf Z/W gesetzt)

PS 1.4 - Radeon 8500
  • RISC artigerer Versuch des Pixel Shaders
  • Pixel Shader arbeitet in 2 Phasen (jede Phase darf max. 6 Texture-Anweisungen gefolgt von 8 math. Anweisungen haben!)
  • stark geänderter Befehlssatz(neue Befehle sind kursiv)!!!
  • Gültige Befehle
    • texcrd rDest tSrc (kopiert Textureparameter in Temp. Register )
    • texld rDest, sSrc (holt Texturesamples bei Dest, mit den Koordinaten von s, s kann t# oder r# sein)
    • texkill
    • texdepth sDest (aktualisiert den Tiefenpuffer mit s.r/s.g)
  • Gültige math. Befehle
    • add, sub, mul, mad, lrp, cnd, cmp, dp3, dp4
    • bem dest, src0, src1 ( (n = Dest Register #)
      d.r = s0.r + D3DTSS_BUMPENVMAT00(stage n) * s1.r + D3DTSS_BUMPENVMAT10(stage n) * s1.g
      d.g = s0.g + D3DTSS_BUMPENVMAT01(stage n) * s1.r + D3DTSS_BUMPENVMAT11(stage n) * s1.g )
  • sonstige Befehle
    • nop, def
    • phase (markiert Punkt zwischen Phase 1 und 2)
  • mehr Register, mehr Textureeinheiten
  • bis zu 6 Texture-Anweisungen
  • bis zu 8 math. Anweisungen
Name (# index)
I/O Berechtigung
min. Anzahl
Quelle
c# nur lesen
8
API Aufruf
r# lesen / schreiben
6
Programm
t#
lesen / schreiben
6
Texture
v#
nur lesen
2
Vertex Farbe

Die Unterschiede zwischen den Pixel Shader Versionen sind doch recht groß, da freut man sich schon auf DirectX 9.
Mir persönlich sind es jedenfalls zu viele Versionen - wozu legt man Standarts fest? Es sollte doch alles etwas einfacher für die Softwarehersteller werden - eine Pixel Shader Version pro DirectX hätte doch sicher genügt.
Die Geforce 3 unterstützt PS 1.0 -1.3, diese erlauben maximal 4 Texturen pro Pixel. ATi's neue Radeon 8500 erfüllt bereits PS 1.4, welche bis zu 6 Texturen pro Pixel erlaubt. Also müssen alle PS Programme, die nicht der Version 1.4 entsprechen durch den Treiber konvertiert werden, was wiederum Performanceverluste, für die Radeon 8500, bedeuten könnte.
Bei der Geforce 3 wiederum lassen sich 6 Texturen pro Pixel nur mit mehreren Durchläufen erzeugen. Das kostet ebenfalls Performance.
Diese ganze Angelegenheit erschwert natürlich wieder das Benchmarken, da hier wieder ästhetische Gesichtspunkte mit in Betracht gezogen werden müssen, ähnlich wie bei FSAA.


Pixel Shader, Vertex Shader - gibts die bei OpenGL auch?


OpenGL Pipeline

Wie man sieht, sind die DX8 Vertex Shader hier als "per-vertex programs" und die DX8 Pixel Shader als "per-pixel shading" gekennzeichnet.
Die Vertex Programme benutzt man bei NVIDIA GPU's mit der NV_vertex_program Extension und bei ATI mit ATI_vertex_shader Jedoch ist bei ATI der Befehlssatz noch nicht veröffentlicht. Die Programmiersprache ist bei NVIDIA genau die gleiche, wie in DirectX 8.1. Somit sind keine Konvertierungen nötig. Bleibt zu hoffen, dass die anderen Hersteller (ST Micro, BitBoys) ähnlich verfahren.

Die Pixel Shader hingegen werden unter OpenGL ähnlich ihrer realen Beschaffenheit nach angesprochen. Das diese Einheit noch weit von freier Programmierungsmöglichkeit entfernt ist,

Geforce3 PS
 
hat die OpenGL-Lösung keinerlei Nachteile.

Hier unterscheidet man ganz klar zwischen NV_texture_shader, welcher für die Adressierungen der Texturen veranwortlich ist und dem NV_register_combiners der für die math. Operationen (Texture Überblendungen) verantwortlich ist. Bei ATI kommt die ATI_fragment_shader Extension zum Einsatz, bei der jew. 32 Mehrzweckregister und 32 Temp. Register zur Verfügung stehen. Deutlich mehr also, als in DirectX 8.1 vorgesehen sind.
Hier sehen wir einmal einen Vergleich (NVIDIA), kein besonders guter, da die DirectX Version nur aus einem Aufruf besteht:

OpenGL_DX8

Bleibt abzuwarten, was andere Hersteller hier für Möglichkeiten bieten.



Die haupt Vorteile / Nachteile der jeweiligen Schnittstelle



OpenGL
DirectX
n utzt die Hardware optimal aus,
durch spez. Anpassungen
ja
nein, an DirectX Funktionsset gebunden
läuft auf unterschiedlichen Plattformen ja
nein, nur Windows
läuft sofort auf den meisten 3D-Chips mit fast allen 3D Features,
ohne spez. Anpassungen

nein
ja
läuft auf verteilten Systemen
(mehrere Rechner erledigen unterschiedliche Teilaufgaben)
ja, da Clint-Server Architektur
nein
Performance
(Unreal Tournament mit den letzten D3D/OpenGL beta dll's)
Duron 1000/133 - 512 MB PC133 (2-2-2) - Geforce 2 Pro - 640x480x32
P.S. Unreal Engine original für Glide entwickelt, sind die Jungs von
Epic unfähig, oder ist es schwerer, für die DirectX Schnittstelle
gute Performance zu erzielen!?!
UTBench(23,8 / 71,2 / 42,4)
UTBench(18,5 / 41,4 / 26,5)



Was bringt die Zukunft?


Wie es mit Verbesserungen bei DirectX 9 aussieht, ist noch nicht ganz klar. Die entgültigen Spezifikationen stehen noch nicht fest. Die Renderfarbtiefe wird von 8 auf 10 oder 16 Bit angehoben und die Pixel + Vertex Shader können mehr Befehle ausführen.
Momentan laufen aber auch recht interessante Diskussionen über OpenGL 2.0. Hierbei ist das Ziel einen Hochsprache für die Pixel + Vertex Shader zu entwickeln, welche hardwareunabhängig ist. Das würde eine Vereinfachung der Programmierung bedeuten, denn assemblerähnliche Sprachen sind nicht jedermanns Sache. Für Programme wie Lightwave, 3D Studio oder Maya wäre es einfacher, die Shader zu integrieren.
Die Hardwarehersteller (nicht Microsoft ;) ) hätten endlich eine gemeinsame Basis für zukünftige Entwicklungen. Es gäbe die Möglichkeit, die Shader flexibler zu machen, oder Teile davon in Software auszulagern, um z.B. bei Multiprozessorsystemen eine optimale Lastenverteilung zu erreichen.
Natürlich liegt es nicht im Interesse der Hardwarefirmen, welche Ihren Marktanteil erhöhen wollen, besonders bereitwillig mit anderen Herstellern zusammenzuarbeiten.
Microsoft hat sicher auch andere Pläne, und wird versuchen OpenGL aus dem Consumer-Markt fernzuhalten. Eine weitere Möglichkeit wäre allerdings, eine gemeinsame Pixel + Vertex Shader Sprache zu entwickeln, welche in OpenGL & DirectX eingesetzt werden würde. Für die Softwareentwickler würde damit sicher ein Traum in Erfüllung gehen.
Die Möglichkeiten die sich zur Zeit bieten sind wirklich riesig, denn die Zukunft liegt in den programmierbaren Shadern. Wenn wir nicht zu vergangenen Zeiten zurückkehren wollen, wo es für jede Karte eine eigene Schnittstelle
(3dfx Glide, Rendition Redline, S3 Metal, ....) gab, dann ist jetzt der Zeitpunkt gekommen wo die Industrie handeln muss.

Hier noch ein aktueller Link zum Thema, von id Softwares John Carmack.