PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Arbeitsweise des NV30 Pixelprozessors (Ergänzungstext für den CineFX Artikel)


Demirug
2003-09-02, 19:31:33
Da es nun doch zu einigen Klagen bezüglich der Verständlichkeit des CineFX Artikels gekommen ist hier nun der Versuch die Arbeitsweise etwas mehr Praxisorientiert zu beleuchten. Getreu dem Motto „Man hat nie Zeit es richtig zu machen aber immer genug Zeit es noch einmal zu machen“ kann ich natürlich nicht versprechen das dies hier nun verständlicher wird als die ursprüngliche Version für den Artikel. Das ganze nun im Technologieforum weil sich dann Leo nicht mit meinem Geschreibsel abplagen muss und ich hier die besseren Möglichkeiten habe einzelne Teile bei Bedarf nachträglich genauer auszuführen

Lösen wir uns erst einmal völlig von den Zeichnungen von nVidia mit den vielen Einzelnen Einheiten und beginnen mit einem Vereinfachten Model des ganzen. Jeder NV3X Pixelprozessor teilt sich in 3 große Blöcke auf.

- Arbeiten vor dem Texturelookup
- Texturelookup
- Arbeiten nach dem Texturelookup

Verbunden sind diese 3 Einheiten mit Datenpfaden nach dem Prinzip einer Pipeline mit Loopback. Jede Einheit kann Daten zur nächsten übertragen und die letzte Einheit kann bei Bedarf wiederum die erste versorgen. Die Möglichkeiten der Übertragung sind dabei nicht unbedingt als sehr groszügig zu bezeichnen. Von der ersten zur zweiten Einheit lassen sich nun maximal 10 Fliesspunktwerte (32 Bit) übertragen. Diese sind aufgeteilt in drei Gruppen. Zwei Gruppen mit jeweils 3 Werten enthalten die Texturkoordinaten welche in der zweiten Einheit zum auslesen der Textur benötigt werden. Die restlichen 4 Werte bilden die Letzte Gruppe welche als zusammenhängender Block einfach durch die zweite Einheit unverändert durchgeschoben werden. Vom Texturelookup zur letzten Einheit können nun zwei Sampleergebnisse so wie die vier unveränderten Werte aus dem ersten Block übertragen werden. Zu guter letzt bleibt uns noch der Loopback Pfad. nVidia macht hierzu keine direkte Aussage gibt aber an das es im ersten Block 3 Loopback Register mit jeweils 4 32 Bit Fliesspunktwerten gibt. Aus diesem Grund ist davon auszugehen das über den Loopbackpfad auch 12 Werte übertragen werden können.

Bei CineFX I (NV30, NV31, NV34) besteht nun nur im ersten Block die möglichkeit PS >= 2.0 Operationen auszuführen. Nur dort ist ein dafür notwendiges vollständiges Fliesspunkt Rechenwerk vorhanden. Es gibt zwar auch im letzten Block Teileinheiten die mit Fliesspunkt Genauigkeit arbeiten aber diese sind nicht in der Lage die für eine Pixelshader FPU notwendigen Arbeiten zu übernehmen. Den Internen Aufbau des ersten Blocks lassen wir im Moment einmal unberücksichtig und klassifizieren wir in nur über das was er zu leisten vermag. Dem EVA (Eingabe Verarbeitung Ausgabe) Prinzip folgend schauen wir zuerst einmal auf die möglichen Eingangswerte. Dem Block stehen auf der einen Seite die 32 Werte aus den 8 Texturkoordinaten zur Verfügung. Zudem noch der Tiefenwert Z sowie der 1/W Wert. Damit wären wir bei 34 Werten. Hier gibt es nun aber einen kleinen Harken. All diese Werte müssen nun pro Pixel interpoliert werden und der NV3X Pixelprozessor erledigt diese arbeit „Just in Time“. Dabei steht im aber nur genügend Rechenkapazität für 6 aus diesen 34 Werten zur Verfügung. Im Normalfall ist das durchaus ausreichend möchte man aber direkt zwei Texturkoordinaten Registern verrechnen so ist das in einem Durchlauf nicht zu machen weil von den benötigen 8 Werte nur 6 interpoliert werden können. Neben den aus Vertexdaten interpolierten Eingangswerten stehen nun auch noch 3*4 Register zur Verfügung. Diese werden als Loopback-Register bezeichnet und haben die Aufgabe Zwischen-Ergebnisse zu speichern. Zudem gibt es noch ein „Scratch“ Register mit 4 Werten. Allerdings ist nicht eindeutig feststellbar ob es sich dabei um ein eigenes Register handelt oder für diesen Zweg eines der 3 Loopback-Register benutzt wird. Auf die Bedeutung dieses „Scratch“ Registers kommen wir dann noch bei der Aussage zu sprechen.

Zur eigentliche Verarbeitung lässt sich ohne ins Detail zu gehen nicht viel sagen. Es werden auf die ausgewählten Eingangswerte eine Reihe von Rechenoperationen ausgeführt welche dann zusammengenommen eine Pixelshader Operationen (bzw. einen Teil davon) ergeben.

Auf der Ausgabeseite stehen nun die bereist erwähnten 3 Wertgruppen zur Verfügung. 2 davon enthalten die Samplepositionen für den Texturelookup. Die letzten 4 Werte bilden nun ein Register welches zur nächsten Einheit durchgereicht wird oder für das „Scratch“ Register für einen weiteren Durchlauf übernommen wird.

Zum Texturelookup braucht man wohl hier nicht viel zu sagen da es sich um das übliche Verfahren handelt. Als Besonderheit könnte man noch die zusätzliche Möglichkeit sehen 4 32 Bit Fliesspunktwerte syncron zum Sample weiter zu schieben. Dies wird aber von einer Teileinheit erledigt die nicht direkt zum Textursystem gehört und eine solche Einheit war auch schon im Textureshader des NV20/NV25 vorhanden.

Der dritte und letzte Block des Pixelprozessors enthält unter anderem die für PS >= 2.0 nicht benutzbaren Int12 Einheiten sowie den Speicher für die Temp-Register. Der Rest der sich auch noch dort befindet wollen wir erst einmal bei Seite lassen weil er im Moment nicht so wichtig ist. Der kritische Faktor hier ist die Anzahl der Register (jeweils 4 Werte) welche aus dem Registerspeicher pro Takt gelesen und geschrieben werden können (Read und Write Ports). Leider gibt es dazu keinerlei Aussagen in dem Dokument. Gehen wir einmal davon aus das jeweils 3 Ports verfügbar sind was das logisch sinnvolle Minimum sein müsste.


--->IIIIIIIIIIIIIII<---
|-->I 1. Einheit I |
||->IIIIIIIIIIIIIII>---
||| | | |
||| | | |
||| IIIIIIIIIIIIIII
||| I 2. Einheit I
||| IIIIIIIIIIIIIII
||| | | |
||| | | |
||| IIIIIIIIIIIIIII<-3-IIIIIIIIIIIIIIIII
||| I 3. Einheit I I Temp Speicher I
||| IIIIIIIIIIIIIII>-3-IIIIIIIIIIIIIIIII
||| | | |
||--<-- | |
|---<----- |
----<--------


Wie führt man nun damit einen Pixelshader aus? Die Lösung die sicherlich am einfachsten zu realisieren ist wäre für jeden einzelnen Befehl die komplette Runde zu drehen:

1: Einheit 1 führt die zum Befehl gehörigen Berechnungen durch und gibt des Resultat auf den entsprechenden Ausgängen aus. Der Registerausgang wird dabei für Arithmetikbefehle genutzt. Die beiden Koordinaten Ausgänge entsprechend für Texturebefehle.

2: Einheit 2 erzeugt falls erforderlich die nötigen Texturesamples und schiebt den Inhalt des Registereingangs zum Ausgang durch so das die Samples und der Registerwert den Ausgang im gleichen Takt erreichen.

3: Die dritte Einheit nimmt die von Einheit 2 gelieferten Werte entgegen und speichert sie an den entsprechenden Stellen im Temp-Speicher ab. Gleichzeitig werden die für den nächsten Befehl erforderlichen Werte aus den Temp-Register geladen und an den Loopback ausgängen zur Verfügung gestellt. Ist man beim letzten Befehl angekommen wird das Endergebniss an die dem Pixelprozessor nachgestellten ROPs (Raster Operatoren übergeben)

Dieses 3 Schritt Verfahren ist supersimple aber dafür hochgradig zuverlässig umsetzbar. Zudem ist es auch das einzige Verfahren von dem man mit 100% Sicherheit sagen kann das es auf jeden Fall mit einer Cine FX Pipeline funktioniert. Bevor wir nun einen Blick auf unter Umständen möglichen komplexere Verfahren zur Umsetzung von Shadercode auf den Pixelprozessor anschauen wollen wir uns zuerst einmal betrachten woher die starke Abhänigkeit der Shaderleistung im Bezug auf die Anzahl der Temp-Register innerhalb des Shadercodes herrührt.

Wie bereits an andere Stelle erwähnt wird der Pixelprozessor durch ein Tor vom Rasterisierer getrennt. Sobald ein Shaderprogramm geladen wird welches die Loopback Funktion benutzt wird das Tor von einem Wächter beschützt welcher dafür Sorge trägt das nicht mehr Pixelquads in die Pipeline eingelassen werden als diese mit dem entsprechenden Shader verarbeiten kann. Die maximale Anzahl der möglichen Quads bestimmt sich primär über die Anzahl der benutzten Temp-Register. Der Temp-Speicher ist dabei die begrenzende Resource. Da der Pixelprozessor intern nach wie vor als Pipeline aufgebaut ist benötigt ein Quad vom Anfang bis zum Ende mehrere Takte. Da uns dazu keine genauen Angaben vorliegen gehen wir für das folgenden Beispiel einfach einmal von 10 Takten aus. In der Realität sind es eher mehr aber mit nur 10 Takten werden die Beispiele etwas übersichtlicher.

Das folgende Diagramm zeigt nun wie Quads durch die Pipeline wandern. Die Richtung ist dabei von Links nach Rechts und von Oben nach unten sehen wir die einzelnen Takte.

Genügend Speicher für 16 Quads:

Takt R G 01 02 03 04 05 06 07 08 09 10
1 1 | XX XX XX XX XX XX XX XX XX XX
2 2 | 1 XX XX XX XX XX XX XX XX XX
3 3 | 2 1 XX XX XX XX XX XX XX XX
4 4 | 3 2 1 XX XX XX XX XX XX XX
5 5 | 4 3 2 1 XX XX XX XX XX XX
6 6 | 5 4 3 2 1 XX XX XX XX XX
7 7 | 6 5 4 3 2 1 XX XX XX XX
8 8 | 7 6 5 4 3 2 1 XX XX XX
9 9 | 8 7 6 5 4 3 2 1 XX XX
10 10 | 9 8 7 6 5 4 3 2 1 XX
11 11 | 10 9 8 7 6 5 4 3 2 1
12 11 | 1 10 9 8 7 6 5 4 3 2
13 11 | 2 1 10 9 8 7 6 5 4 3
...

Nachdem die Pipeline einmal gefüllt ist läuft sie mit voller Geschwindigekeit. Erhöhen wir nun die Temp-Register so das wir nun noch Platz für 8 Quad haben.


Takt R G 01 02 03 04 05 06 07 08 09 10
1 1 | XX XX XX XX XX XX XX XX XX XX
2 2 | 1 XX XX XX XX XX XX XX XX XX
3 3 | 2 1 XX XX XX XX XX XX XX XX
4 4 | 3 2 1 XX XX XX XX XX XX XX
5 5 | 4 3 2 1 XX XX XX XX XX XX
6 6 | 5 4 3 2 1 XX XX XX XX XX
7 7 | 6 5 4 3 2 1 XX XX XX XX
8 8 | 7 6 5 4 3 2 1 XX XX XX
9 9 | 8 7 6 5 4 3 2 1 XX XX
10 9 | XX 8 7 6 5 4 3 2 1 XX
11 9 | XX XX 8 7 6 5 4 3 2 1
12 9 | 1 XX XX 8 7 6 5 4 3 2
13 9 | 2 1 XX XX 8 7 6 5 4 3
14 9 | 3 2 1 XX XX 8 7 6 5 4
...


Jetzt schieben wir 2 Blasen durch die Prozessorpipeline. Für 8 Operationen brauchen wir 10 Takte was die Effizienz gerade auf 80% gesenkt hat. Aber verdoppel wir noch einmal die Registerzahl was uns nur noch Platz für 4 Quads lässt.


Takt R G 01 02 03 04 05 06 07 08 09 10
1 1 | XX XX XX XX XX XX XX XX XX XX
2 2 | 1 XX XX XX XX XX XX XX XX XX
3 3 | 2 1 XX XX XX XX XX XX XX XX
4 4 | 3 2 1 XX XX XX XX XX XX XX
5 5 | 4 3 2 1 XX XX XX XX XX XX
6 5 | XX 4 3 2 1 XX XX XX XX XX
7 5 | XX XX 4 3 2 1 XX XX XX XX
8 5 | XX XX XX 4 3 2 1 XX XX XX
9 5 | XX XX XX XX 4 3 2 1 XX XX
10 5 | XX XX XX XX XX 4 3 2 1 XX
11 5 | XX XX XX XX XX XX 4 3 2 1
12 5 | 1 XX XX XX XX XX XX 4 3 2
13 5 | 2 1 XX XX XX XX XX XX 4 3
14 5 | 3 2 1 XX XX XX XX XX XX 4
...


Da waren es schon 6 Blasen und in 10 Takten kommen wir nur noch auf 4 Anweisungen was nur noch 40% nutzung der Rohleistung entspeicht. Um nun dieses Trauerspiel noch zu ende zu bringen verdoppeln wir noch einmal die Registeranzahl:


Takt R G 01 02 03 04 05 06 07 08 09 10
1 1 | XX XX XX XX XX XX XX XX XX XX
2 2 | 1 XX XX XX XX XX XX XX XX XX
3 3 | 2 1 XX XX XX XX XX XX XX XX
4 3 | XX 2 1 XX XX XX XX XX XX XX
5 3 | XX XX 2 1 XX XX XX XX XX XX
6 3 | XX XX XX 2 1 XX XX XX XX XX
7 3 | XX XX XX XX 2 1 XX XX XX XX
8 3 | XX XX XX XX XX 2 1 XX XX XX
9 3 | XX XX XX XX XX XX 2 1 XX XX
10 3 | XX XX XX XX XX XX XX 2 1 XX
11 3 | XX XX XX XX XX XX XX XX 2 1
12 3 | 1 XX XX XX XX XX XX XX XX 2
13 3 | 2 1 XX XX XX XX XX XX XX XX
14 3 | XX 2 1 XX XX XX XX XX XX XX
...


Traurig bei den 8 Blasen in der Pipeline und nur 2 Operationen in 10 Takten arbeitet sie gerade noch mit 20% Effektivität.

Zum Thema mit den alternativen Operationsmodies kommen wir dann später.

Gast
2003-09-03, 10:52:20
Ich will ja nicht mossern, aber der große Artikel war einfacher zu verstehen und übersichtlicher. :)

Trotzdem mal eine Frage : für wieviele Quads hat den nun die FX Speicher? Wirklich nur für 4 Quads (= 4Temp-Register); oder doch mehr solange man kein Loopback macht ???

Wenn das Ding wirklich nur 4 Quads durchlässt, dann heist das ja, das alle etwas komplizierteren PS2.0 Sachen die Performance gleich auf 40% runterrasseln lassen. Ich kann mir eigentlich nicht vorstellen, das Nvidia so einen Schrott designt bei dem bis zu 60% der Rechenleistung brach liegt. Da das eine Hardware-Sache ist, würden dann selbst die besten Treiber nix helfen und eine FX5900-Ultra käme nie über ~70% der im Artikel genannten Leistung hinaus ( 1:1 Mischung aus Loopback und nicht). Nur bei einfachsten Shadern auf DX8.1-Niveau wäre es dann doch möglich die Recheneinheiten richtig auszulasten, oder?

Demirug
2003-09-03, 11:28:46
Original geschrieben von Gast
Ich will ja nicht mossern, aber der große Artikel war einfacher zu verstehen und übersichtlicher. :)

Ich habe ja auch keine Versprechungen gemacht.

Trotzdem mal eine Frage : für wieviele Quads hat den nun die FX Speicher? Wirklich nur für 4 Quads (= 4Temp-Register); oder doch mehr solange man kein Loopback macht ???

Die Anzahl der Quads hängt von der Anzahl der benutzten Temp-Register ab. Im Patent ist speicher für 8*64*64Bit vorgesehen. 64 Bit entsprechen dabei einem FP16 Tempregister. Bei einem Shader mit 4 fp32 Register (brauchen dementsprechend zwei Zellen) wäre also Platz für 8*64/(4*2) = 32 Quads. Hat die Pipeline mehr als 32 Stufen reicht das schon nicht mehr aus.

Wenn das Ding wirklich nur 4 Quads durchlässt, dann heist das ja, das alle etwas komplizierteren PS2.0 Sachen die Performance gleich auf 40% runterrasseln lassen. Ich kann mir eigentlich nicht vorstellen, das Nvidia so einen Schrott designt bei dem bis zu 60% der Rechenleistung brach liegt. Da das eine Hardware-Sache ist, würden dann selbst die besten Treiber nix helfen und eine FX5900-Ultra käme nie über ~70% der im Artikel genannten Leistung hinaus ( 1:1 Mischung aus Loopback und nicht). Nur bei einfachsten Shadern auf DX8.1-Niveau wäre es dann doch möglich die Recheneinheiten richtig auszulasten, oder?

Die 10 Stufen sind nur ein Beispiel (wie oben erwähnt) in Wirklichkeit werden es wohl viel mehr sein. Aber es ist ja auch mehr Speicher vorhanden. Hält man die Anzahl der Temps entsprechend gering sollte die Pipeline voll auslastbar sein. Aber an diesem Punkt hat das Design wirklich ein Problem was von der sehr langen Pipeline herrührt.

Gast
2003-09-03, 11:43:56
Danke für die schnelle Antwort.

Da hab ich mich wohl etwas in die Irre führen lassen.

Apropos Stages.

Kann man das nicht ausmessen indem man ein Vertex durchschickt und ausmisst wann es wieder zum Vorschein kommt?

Man bräuchte zwei Shader/Befehle. einer, der vom Chip ohne Verzögerung ausgeführt wird ( und ein neues frame startet) und einen Shader der die ganze Pipeline durchläuft. Dann schaut man wie viele Quads inzwischen durchgelaufen sind und zählt ab.

So würde ich mir das jedenfalls als Laie vorstellen.

Demirug
2003-09-03, 11:49:21
Original geschrieben von Gast
Danke für die schnelle Antwort.

Da hab ich mich wohl etwas in die Irre führen lassen.

Apropos Stages.

Kann man das nicht ausmessen indem man ein Vertex durchschickt und ausmisst wann es wieder zum Vorschein kommt?

Man bräuchte zwei Shader/Befehle. einer, der vom Chip ohne Verzögerung ausgeführt wird ( und ein neues frame startet) und einen Shader der die ganze Pipeline durchläuft. Dann schaut man wie viele Quads inzwischen durchgelaufen sind und zählt ab.

So würde ich mir das jedenfalls als Laie vorstellen.

Leider nicht weil die Pipeline ja immer komplett durchlaufen wird und man auf dem Chip direkt keine möglichkeit hat zu messen wie lange der durchlauf nun dauert. Ich bin zwar am überlegen wie man doch noch herausbekommt wie lange die Pipeline ist und wie viel Register-Speicher verfügbar ist aber bisher ist da noch nichts wirklich verwertbares herausgekommen.

Widowmaka
2003-09-03, 15:52:40
Erstmal danke und grosses Lob, mir hat dieser Text die Erleuchtung gebracht :). Eine Frage habe ich aber trotzdem:

Takt R G 01 02 03 04 05 06 07 08 09 10
1 1 | XX XX XX XX XX XX XX XX XX XX
2 2 | 1 XX XX XX XX XX XX XX XX XX
3 3 | 2 1 XX XX XX XX XX XX XX XX
4 4 | 3 2 1 XX XX XX XX XX XX XX
5 5 | 4 3 2 1 XX XX XX XX XX XX
6 6 | 5 4 3 2 1 XX XX XX XX XX
7 7 | 6 5 4 3 2 1 XX XX XX XX
8 8 | 7 6 5 4 3 2 1 XX XX XX
9 9 | 8 7 6 5 4 3 2 1 XX XX
10 10 | 9 8 7 6 5 4 3 2 1 XX
11 11 | 9 8 7 6 5 4 3 2 1 XX
12 11 | 10 9 8 7 6 5 4 3 2 1
13 11 | 1 10 9 8 7 6 5 4 3 2
14 11 | 2 1 10 9 8 7 6 5 4 3
...
In diesem Bild sind bei Takt 10 und 11 in allen Pipelinestufen die gleichen Quads. Ist das ein tippfehler oder hat das einen bestimmten Grund? Wenn ja welchen?

Demirug
2003-09-03, 16:53:31
Original geschrieben von Widowmaka
Erstmal danke und grosses Lob, mir hat dieser Text die Erleuchtung gebracht :). Eine Frage habe ich aber trotzdem:

Takt R G 01 02 03 04 05 06 07 08 09 10
1 1 | XX XX XX XX XX XX XX XX XX XX
2 2 | 1 XX XX XX XX XX XX XX XX XX
3 3 | 2 1 XX XX XX XX XX XX XX XX
4 4 | 3 2 1 XX XX XX XX XX XX XX
5 5 | 4 3 2 1 XX XX XX XX XX XX
6 6 | 5 4 3 2 1 XX XX XX XX XX
7 7 | 6 5 4 3 2 1 XX XX XX XX
8 8 | 7 6 5 4 3 2 1 XX XX XX
9 9 | 8 7 6 5 4 3 2 1 XX XX
10 10 | 9 8 7 6 5 4 3 2 1 XX
11 11 | 9 8 7 6 5 4 3 2 1 XX
12 11 | 10 9 8 7 6 5 4 3 2 1
13 11 | 1 10 9 8 7 6 5 4 3 2
14 11 | 2 1 10 9 8 7 6 5 4 3
...
In diesem Bild sind bei Takt 10 und 11 in allen Pipelinestufen die gleichen Quads. Ist das ein tippfehler oder hat das einen bestimmten Grund? Wenn ja welchen?

Tippfehler. So stimmst.

Takt R G 01 02 03 04 05 06 07 08 09 10
1 1 | XX XX XX XX XX XX XX XX XX XX
2 2 | 1 XX XX XX XX XX XX XX XX XX
3 3 | 2 1 XX XX XX XX XX XX XX XX
4 4 | 3 2 1 XX XX XX XX XX XX XX
5 5 | 4 3 2 1 XX XX XX XX XX XX
6 6 | 5 4 3 2 1 XX XX XX XX XX
7 7 | 6 5 4 3 2 1 XX XX XX XX
8 8 | 7 6 5 4 3 2 1 XX XX XX
9 9 | 8 7 6 5 4 3 2 1 XX XX
10 10 | 9 8 7 6 5 4 3 2 1 XX
11 11 | 10 9 8 7 6 5 4 3 2 1
12 11 | 1 10 9 8 7 6 5 4 3 2
13 11 | 2 1 10 9 8 7 6 5 4 3
...