Inside nVidia NV40
14. April 2004 / von aths / Seite 3 von 6
Warum Quad-basiertes Rendering?
Ein Pixel-Block von 2x2 Pixeln wird oft "Quad" genannt. Quad-basiertes Rendering geschieht vor allem aus zwei Gründen: Erstens, um etwas Logik und damit Transistoren zu sparen. Man spiele Quake3 in geringer Auflösung mit aktivierten MIP-Map-Colors. Dann sieht man leicht, dass das LOD (Level of Detail) für die Texturen pro Quad, nicht pro Pixel berechnet wird. Der zweite Grund ist, dass bestimmte LOD-Berechnungen (vor allem in Verbindung mit Enviromental Bumpmapping) darauf angewiesen sind, anstelle des einzelnen Pixels das gesamte Quad zu haben.
Klingt so weit ganz gut, aber warum kümmert uns das? Wegen der Effizienz! Auch an den Rändern von Dreiecken wird mit ganzen Quads gearbeitet, selbst wenn nur ein einziges Pixel Teil des Dreiecks ist. Bei diesem Beispiel sind drei Pipes arbeitslos. Early-Z occlusion (eine Technik, die schon im Vorhinein verhindern soll, dass unsichtbare Pixel berechnet werden) kann lediglich ganze Quads verwerfen. Early-Z wirft aber nicht jedes unsichtbare Quad raus, es besteht immer die Möglichkeit, dass trotzdem alle vier Pixel eines gegebenen Quads noch übermalt werden. Diese Füllratenverschwendung ist ein generelles Problem mit herkömmlichen "immediate render"-Architekturen. Die Early-Z occlusion vom NV40 kann bis zu 16 Quads pro Takt verwerfen, das sind bis zu 64 Pixel. Spiele-Engines, die einen Z-first Render-Pass nutzen, könnten durch das verbesserte Early-Z im NV40 deutlich beschleunigt werden.
Der Pixelshader 3.0 wirft aber noch größere Herausforderungen betreffs der Effizenz auf, sofern der Shader Sprunganweisungen benutzt. Es könnte sein, dass die Berechnungen für jedes einzelne Pixel im Quad unterschiedlich sind. Dann muss das Quad auch vier mal durch die Pipeline geloopt werden. Die Problematik mit dem Pixelshader 3.0 behandeln wir im Artikel noch ausführlicher.
Der NV40 hat 16 ROPs. Das klingt wie eine ROP pro Pipe. Aber nVidia baut eine "Fragment Crossbar" ein. Diese sichert nun, dass die ROPs dort eingesetzt werden wo man sie am nötigsten braucht. Mit den verbesserten ROPs können bis zu 32 "Zixel" pro Takt gerendert werden. Aber das darf man natürlich nicht als Pipeline zählen, dieses würde aus dem NV40 ein 32-Pipe-Design machen (was natürlich Unsinn wäre.) Bei 4x Antialiasing gibt es bis zu 64 Subpixel pro Takt, wodurch die ROPs zum Loop gewungen werden.
Memory Controlling
Der Memory Controller ist das Rückgrat der Leistung. Das wird oft unterschätzt. Wir haben jetzt noch nicht die Detail-Informationen, aber es sieht so aus als hätte nVidia die "Lightspeed memory architecture" wieder einmal verbessert. Zum Beispiel wurde an der Color-Compression gefeilt: NV40 kann Framebuffer-Kacheln auch dann komprimieren, wenn kein Antialiasing aktiv ist. Es sieht auch so aus, als wäre der Cache aufgebohrt. Solcher Aufwand ist wichtig, um die Performance zu maximieren und dabei gleichzeitig mit einem bezahlbaren Speicher-Interface zu arbeiten. Übrigens kann der NV40 bis zu 2 Gigabyte RAM adressieren.
Im nVidias Hauptquartier: Keith Setho, vor dem Performance Testing Lab (links).
Ist die Bandbreiten-Limitierung beim NV40 bedenklich?
Auf den ersten Blick ist der NV40 extrem Bandbreiten-limitiert. Betrachtet man die Sache näher, hängt es wirklich von der Situation ab. Alte Spiele leiden unter der geringen Bandbreite (gering ist sie verglichen mit der Füllrate), aber alte Spiele laufen eh schnell genug. Warum sollte man sich dann um Bandbreiten-Limitierung einen Kopf machen? Man kann ja alles aktivieren, 4x Antialiasing, 16x Anisotropie, und mit der höchsten Auflösung spielen, die der Monitor noch hergibt: Der NV40 bringt in alten Titeln extrem hohe Frameraten.
Lange Pixelshader, die heftige arithmetische Rechnungen vornehmen, sind dann wieder Shader-limitiert. Angesichts, dass der NV40 für zukünftige Spiele gebaut wurde, meinen wir, dass es keinen Grund gibt, sich heute am Bandbreiten-Problem des NV40 zu stören.
Textur-Filterung mit Floating Point
Der NV40 führt Floating Point Texturfilter ein. Bisherige GeForce-Karten nutzen intern 10-Bit-Fixpoint Präzision und ein 8 Bit Fixpoint Output (mit dem Vorzeichenbit hat der Output-Wert dann 9 Bit Länge.) NV40 beschert uns nun echte 16 Bit FP-Filterung mit FP16-Output! Dieser kann natürlich auch zu FX12 oder FP32 konvertiert werden.
Bei einem schnellen Blick auf FP16 erscheint das Format als große Verschwendung: 50% aller darstellbaren Werte sind dunkler als schwarz, ungefähr 25% heller als weiß. Nur die restlichen 25% aller darstellbaren Werte scheinen "anwendbar". Betrachten wir das erst mal als Vergeudung (obwohl es in Wahrheit keine ist), weil wir scheinbar zwei Bit "verlieren". Die verbleibenden 14 Bit für "echte Nutzung" sind noch immer viel mehr als 8.
FP-Formate arbeiten nun ganz anders als Fixpunkt-Darstellungen. FP16 heißt: 11 Bit Präzision, diese aber über einen großen Bereich. Vergleichen mit dem alten 8 Bit Output sind wir mindestens 3 Bit besser, und haben damit 2^3 = 8-fach bessere Auflösung.
Nehmen wir an, 8 Bit Fixpoint würde genutzt, und nur das letzte Bit wäre gesetzt. Dies entspricht einem Wert von etwa 0,004. Wir haben hier extrem niedrige Auflösung - das Bit kann an- oder ausgeknipst sein. (Somit können wir entweder 0,004 oder 0,0 darstellen, aber nichts dazwischen.) Mit FP16 hat man noch die volle 11-Bit-Auflösung selbst bei solch kleinen Werten! Man kann sogar noch weit darunter gehen und behält volle Auflösung. Mit Werten kleiner als 0,00006 verliert man dann nach und nach an Präzision. (Das gilt für FP16 mit "Denorm-Support." NV40 unterstützt Denorms bei FP16. Ohne dieses Feature würden Werte kleiner als 0,00006 sofort auf Null abgeschnitten. Denorm-Support wird von der API-Spezifikation nicht gefordert, und benötigt eine Menge Transistoren. Wir sind ziemlich froh, dass nVidia hier die Specs nicht nur erfüllt, sondern darüber hinaus denkt.)
Das Schöne bei Floating Point ist, dass die feine Auflösung in jenen Bereichen ist, wo man sie braucht. Verallgemeinert gesagt sind alle unsere menschlichen Sinne "logarithmisch", somit können wir einen sehr großen Bereich von Energie-Leveln wahrnehmen. Bei kleiner Musik-Lautstärke ist leises Rauschen leicht zu hören, während volle Phonstärke solch leises Rauschen "rausmaskiert". Den gleiche Effekt gibt's auch bei unterschiedlichen Lichtbedingungen: In dunkler Umgebung sehen wir noch sehr schwache Unterschiede, während in einer hellen Umgebung nur größere Helligkeits-Differenzen noch wahrnehmbar sind.
FP16 stellt seine Auflösung nicht nur kleinen Werten zur Verfügung. Reden wir kurz über Overbright Lighting. Quake3 nutzt 1 Bit für diese Technik. (Das Erlaubt einen Wertebereich bishin zur 2,0.) Da wir nur 8 Bit Präzision haben, und ein Bit für die Overbright-Darstellung genutzt wird, verbleiben 7 Bit Auflösung. FP bringt seine volle Bitbreiten-Auflösung natürlich in jeden darstellbaren Bereich.
Ab Zahlenwerten größer als 1024 kann FP16 keine Nachkommastellen mehr speichern, weil die Präzision voll für den Vorkommabereich gebraucht wird, und bei Werten größer 2048 sind keine ungeraden Zahlen mehr darstellbar. Da 2^11 = 2048, haben wir aber wirklich 11 Bit Auflösung. Mit FP16 kann man Zahlen bishin zu etwa 65000 darstellen und behält die 11 Bit! (Obwohl man in diesen Bereichen nicht mehr jede beliebige Ganzzahl speichern kann, hat man dennoch 11 Bit Auflösung. Wer mehr über Floating Point lesen will, dem sei ein kompletter Artikel zum Thema empfohlen.) Letzlich ist "heller als weiß" und "dunkler als schwarz" also doch keine Verschwendung.
Alle diese Vorteile von FP16 stehen nun in den Texture Mapping Units (TMUs) zur Verfügung. Wir halten das für einen wirklichen Sprung nach vorne. Das macht FP16-Texturen richtig brauchbar, weil FP16-Texturen durch mehr Präzision und höhere Dynamik glänzen, und die NV40-TMUs bilinear, trilinear und anisotrop mit FP16 filtern! Für Textur-Lookups, die von mathematischen Funktionen genutzt werden, bringt FP16 schöne gesteigerte Auflösung. Sowohl Material-Shader als auch insbesondere Texturen mit Licht-Informationen sind besser dran, wenn sie FP16-Input anstatt FX8-Werte nutzen. Image-based Lighting profitiert von der hohen Dynamik, die FP16 liefert.
Der NV40 hat ein Two-Level-Cache System. Der L2-Cache kann von jeder Quad-Pipeline genutzt werden. Wir schätzen die Größe des L2-Caches auf 8 kib. Jede Quad-Pipeline hat noch seinen eigenen L1-Cache. Der L2-Cache kann noch komprimierte Texturen speichern, diese werden bei der Übertragung in den L1-Cache dekomprimiert. Der ingesamt recht großen Cache erhöht natürlich die Transistor-Zahl, aber hilft den Einfluss der Speicherbandbreiten-Limitierung zu minimieren.
Mit der Übernahme des 3dfx-Kernbereiches konnte nVidia auch einige wertvolle Patente ergattern.