Shadermodell 3 (HLSL-Referenz)

Vertexshader und Pixelshader sind gegenüber früheren Shaderversionen erheblich vereinfacht. Wenn Sie Shader in Hardware implementieren, dürfen Sie vs_3_0 oder ps_3_0 nicht mit anderen Shaderversionen verwenden, und Sie dürfen keinen Shadertyp mit der Pipeline für feste Funktionen verwenden. Diese Änderungen ermöglichen es, Treiber und die Laufzeit zu vereinfachen. Die einzige Ausnahme besteht darin, dass nur softwarebasierte vs_3_0 Shader mit jeder Pixelshaderversion verwendet werden können. Wenn Sie einen reinen Software-vs_3_0-Shader mit einer früheren Pixelshaderversion verwenden, kann der Vertex-Shader außerdem nur Ausgabesemantik verwenden, die mit FVF-Codes (Flexible Vertex Format) kompatibel ist.

Die für Vertexshaderausgaben verwendete Semantik muss für Pixelshadereingaben verwendet werden. Die Semantik wird verwendet, um die Vertexshaderausgaben den Pixelshadereingaben zuzuordnen, ähnlich wie die Vertexdeklaration den Vertexshader-Eingaberegistern und früheren Shadermodellen zugeordnet wird. Weitere Informationen finden Sie unter Match Semantics on vs 3.0 and ps 3.0 shaders.

Zusätzliche Renderzustände im Umbruchmodus wurden hinzugefügt, um die Möglichkeit zusätzlicher Texturkoordinaten in diesem neuen Schema abzudecken. Attribute mit D3DDECLUSAGE_TEXCOORD und Nutzungsindex von 0 bis 15 werden im Umbruchmodus interpoliert, wenn die entsprechende D3DRS_WRAP* festgelegt ist.

Features des Vertexshadermodells 3

Die Ausgaberegistertypen des Vertexshaders wurden in zwölf Register reduziert (siehe Ausgaberegister). Jedes verwendete Register muss mithilfe der dcl-Anweisung und einer Semantik (z. B. dcl_color0 o0.xyzw) deklariert werden.

Das Vertexshadermodell 3_0 (vs_3_0) erweitert die Features von vs_2_0 durch eine leistungsfähigere Registerindizierung, eine Reihe vereinfachter Ausgaberegister, die Möglichkeit, eine Textur in einem Vertexshader zu erfassen, und die Möglichkeit, die Rate zu steuern, mit der Shadereingaben initialisiert werden.

Indiziere ein beliebiges Register

Alle Register( Eingabe- und Ausgaberegister) können mithilfe des Schleifenzählerregisters indiziert werden (in früheren Versionen konnten nur Konstantenregister indiziert werden.)

Sie müssen Eingabe- und Ausgaberegister deklarieren, bevor Sie sie indizieren. Sie dürfen jedoch kein Ausgaberegister indizieren, das mit einer Positions- oder Punktgrößensemantik deklariert wurde. Wenn die Indizierung verwendet wird, müssen die Positions- und psize-Semantik in den o0- bzw. o1-Registern deklariert werden.

Sie dürfen nur einen fortlaufenden Bereich von Registern indizieren. Das heißt, Sie können nicht über Register hinweg indiziert werden, die nicht deklariert wurden. Diese Einschränkung kann zwar unbequem sein, ermöglicht aber die Hardwareoptimierung. Der Versuch, nicht zusammenhängende Register zu indizieren, führt zu nicht definierten Ergebnissen. Die Shaderüberprüfung erzwingt diese Einschränkung nicht.

Vereinfachen von Ausgaberegistern

Alle verschiedenen Arten von Ausgaberegistern wurden in zwölf Ausgaberegister reduziert: 1 für Position, 2 für Farbe, 8 für Textur und 1 für Nebel oder Punktgröße. Diese Register interpolieren alle Daten, die sie für den Pixelshader enthalten. Ausgaberegisterdeklarationen sind erforderlich, und jedem Register wird Semantik zugewiesen.

Die Register können wie folgt unterteilt werden:

  • Mindestens ein Register muss als Positionsregister mit vier Komponenten deklariert werden. Dies ist das einzige Erforderliche Vertex-Shaderregister.
  • Die ersten zehn Register, die von einem Shader genutzt werden, können maximal vier Komponenten (xyzw) verwenden.
  • Das letzte (oder zwölfte) Register darf nur einen Skalar (z. B. Punktgröße) enthalten.

Eine Liste der Register finden Sie unter Register – vs_3_0.

Texturbeispiel in einem Vertex-Shader

Vertex-Shader 3_0 unterstützt die Textursuche im Vertex-Shader mithilfe von texldl – vs.

Features des Pixelshadermodells 3

Die Farb- und Texturregister des Pixelshaders wurden in zehn Eingaberegister reduziert (siehe Eingaberegistertypen). Das Gesichtserkennungsregister ist ein Gleitkomma-Skalarregister. Nur das Zeichen dieses Registers ist gültig. Wenn das Vorzeichen negativ ist, ist der Grundtyp eine Rückseite. Dies kann in einem Pixelshader verwendet werden, um für instance eine beidseitige Beleuchtung zu erzielen. Das Positionsregister verweist auf die aktuellen (x,y) Pixel.

Die Shaderkonstantenregister können wie folgt festgelegt werden:

Abgleichen der Semantik auf vs_3_0 und ps_3_0 Shadern

Es gibt einige Einschränkungen bei der semantischen Verwendung mit vs_3_0 und ps_3_0. Im Allgemeinen müssen Sie vorsichtig sein, wenn Sie eine Semantik für eine Shadereingabe verwenden, die mit einer Semantik übereinstimmt, die in einer Shaderausgabe verwendet wird.

Für instance packt dieser Pixelshader mehrere Namen in einem Register:

ps_3_0 
dcl_texcoord0 v0.x 
dcl_texcoord1 v0.yz // Valid to pack multiple names into one register 
dcl_texcoord2_centroid v1.w
...

Jedes Register weist eine andere Semantik auf. Beachten Sie, dass Sie aufgrund der Verwendung der Schreibmaske auch v0.x und v0.yz mit unterschiedlicher (mehrfacher) Semantik benennen können.

Angesichts des Pixelshaders kann der folgende vs_3_0 Shader nicht mit ihm gekoppelt werden:

vs_3_0 
... 
dcl_texcoord0 o5.x 
dcl_texcoord1 o6.yzw 
...

Diese beiden Shader sind in Konflikt mit der Verwendung der D3DDECLUSAGE_TEXCOORD0 und D3DDECLUSAGE_TEXCOORD1 Semantik.

Schreiben Sie den Vertex-Shader wie folgt um, um die semantische Kollision zu vermeiden:

vs_3_0 
... 
dcl_texcoord2 o3 
dcl_texcoord3 o9 
...

Ebenso kann ein semantischer Name, der in verschiedenen Eingaberegistern im Pixelshader deklariert ist (v0 und v1 im Pixelshader), nicht in einem einzelnen Ausgaberegister in diesem Vertexshader verwendet werden. Für instance kann dieser Vertex-Shader nicht mit dem Pixelshader gekoppelt werden, da D3DDECLUSAGE_TEXCOORD1 sowohl für Pixelshader-Eingaberegister (v0, v1) als auch für das Vertex-Shaderausgaberegister o3 verwendet wird.

vs_3_0 
... 
dcl_texcoord0 o3.x 
dcl_texcoord1 o3.yz 

dcl_texcoord2 o3.w // BAD! Would be valid if this were not o3 
dcl_texcoord3 o9 ... 

Andererseits kann dieser Vertexshader nicht mit dem Pixelshader gekoppelt werden, da das Ausgabeformat für einen Parameter mit einer bestimmten Semantik nicht die vom Pixelshader angeforderten Daten bereitstellt:

vs_3_0 
... 
dcl_texcoord0 o5.x 
dcl_texcoord1 o5.yzw 
dcl_texcoord2 o7.yz // BAD! Would be valid if w were included 
dcl_texcoord3 o9 
... 

Dieser Vertex-Shader stellt keine Ausgabe mit einem der vom Pixelshader angeforderten semantischen Namen bereit, sodass die Shaderpaarung ungültig ist:

vs_3_0 
... 
dcl_texcoord0 o5.x 
dcl_texcoord1 o5.yzw 
dcl_texcoord3 o9 
// The pixel shader wants texcoord2, with a w component, 
// but it isn't output by this vertex shader at all! 
... 

Änderungen im Nebel-, Tiefen- und Schattierungsmodus

Wenn D3DRS_SHADEMODE für flache Schattierung während der Beschneidung und Dreieckrasterung festgelegt ist, werden Attribute mit D3DDECLUSAGE_COLOR als flach schattiert interpoliert. Wenn Komponenten eines Registers mit einer Farbsemantik deklariert werden, andere Komponenten desselben Registers jedoch eine andere Semantik erhalten, wird die Interpolation für flache Schattierung (linear oder flach) für die Komponenten in diesem Register ohne Farbsemantik undefiniert.

Wenn Nebelrendering gewünscht ist, müssen vs_3_0 und ps_3_0 Shader Nebel implementieren. Außerhalb der Shader werden keine Nebelberechnungen durchgeführt. Es gibt kein Nebelregister in vs_3_0, und zusätzliche Semantik D3DDECLUSAGE_FOG (für nebelgemischten Faktor berechnet pro Scheitelpunkt) und D3DDECLUSAGE_DEPTH (für die Übergabe eines Tiefenwerts an den Pixelshader zum Berechnen des Nebelmischungsfaktors) wurden hinzugefügt.

Der Zustand der Texturphase D3DTSS_TEXCOORDINDEX wird bei Verwendung des Pixelshaders 3.0 ignoriert.

Die folgenden Werte wurden hinzugefügt, um diese Änderungen zu berücksichtigen:

// Fog and Depth usages
D3DDECLUSAGE_FOG 
D3DDECLUSAGE_DEPTH 

// Additional wrap states for vs_3_0 attributes with D3DDECLUSAGE_TEXCOORD 
D3DRS_WRAP8 
D3DRS_WRAP9 
D3DRS_WRAP10 
D3DRS_WRAP11 
D3DRS_WRAP12 
D3DRS_WRAP13 
D3DRS_WRAP14 
D3DRS_WRAP15

Gleitkomma- und Ganzzahlkonvertierungen

Gleitkommaberechnungen erfolgen in verschiedenen Teilen der Pipeline mit unterschiedlicher Genauigkeit und Bereichen (16 Bit, 24 Bit und 32 Bit). Ein Wert, der größer als der dynamische Bereich der Pipeline ist, der in diese Pipeline eingeht (z. B. wird eine 32-Bit-Floattexturzuordnung in einer 24-Bit-Float-Pipeline in ps_2_0 abgetastet), erstellt ein undefiniertes Ergebnis. Für ein vorhersagbares Verhalten sollten Sie einen solchen Wert auf den maximalen dynamischen Bereich klammern.

Die Konvertierung von einem Gleitkommawert in eine ganze Zahl erfolgt an mehreren Stellen, z. B.:

  • Beim Auftreten einer mova - vs .-Anweisung.
  • Während der Texturadressierung.
  • Beim Schreiben an ein Renderziel ohne Gleitkomma.

Angeben der vollständigen oder teilweisen Genauigkeit

Sowohl ps_3_0 als auch ps_2_x bieten Unterstützung für zwei Genauigkeitsstufen:

ps_3_0 ps_2_0 Precision Wert
x Vollständig fp32 oder höher
x Partielle Genauigkeit fp16=s10e5
x x Vollständig fp24=s16e7 oder höher
x x Partielle Genauigkeit fp16=s10e5

 

ps_3_0 unterstützt eine höhere Genauigkeit als ps_2_0. Standardmäßig werden alle Vorgänge auf der Ebene der vollständigen Genauigkeit ausgeführt.

Eine teilweise Genauigkeit (siehe Pixelshader-Registermodifizierer) wird durch Hinzufügen des _pp-Modifizierers zum Shadercode angefordert (sofern die zugrunde liegende Implementierung dies unterstützt). Implementierungen können den Modifizierer immer ignorieren und die betroffenen Vorgänge mit voller Genauigkeit ausführen.

Der _pp-Modifizierer kann in zwei Kontexten auftreten:

  • In einer Texturkoordinatendeklaration, um Texturkoordinaten mit teilweiser Genauigkeit an den Pixelshader zu übergeben. Dies kann verwendet werden, wenn Texturkoordinaten Farbdaten an den Pixelshader weiterleiten, was bei teilweiser Genauigkeit schneller ist als bei einigen Implementierungen mit voller Genauigkeit.
  • Bei jeder Anweisung, die Verwendung von teilgenauer Genauigkeit anzufordern, einschließlich Anweisungen zum Laden von Texturen. Dies gibt an, dass die Implementierung die Anweisung mit teilweiser Genauigkeit ausführen und ein Ergebnis mit teilweiser Genauigkeit speichern darf. Wenn kein expliziter Modifizierer vorhanden ist, muss die Anweisung mit voller Genauigkeit ausgeführt werden (unabhängig von der Genauigkeit der Eingabeopernden).

Eine Anwendung kann sich bewusst dafür entscheiden, präzision und leistung zu tauschen. Es gibt verschiedene Arten von Shadereingabedaten, die natürliche Kandidaten für die Verarbeitung teilweiser Genauigkeit sind:

  • Farbiteratoren werden durch Werte mit teilweiser Genauigkeit gut dargestellt.
  • Texturwerte aus den meisten Formaten können durch Werte mit teilweiser Genauigkeit genau dargestellt werden (Werte, die aus 32-Bit-Gleitkommaformattexturen entnommen werden, sind eine offensichtliche Ausnahme).
  • Konstanten können entsprechend dem Shader durch eine Darstellung mit teilweiser Genauigkeit dargestellt werden.

In all diesen Fällen kann der Entwickler die teilweise Genauigkeit für die Verarbeitung der Daten angeben, da er weiß, dass keine Genauigkeit der Eingabedaten verloren geht. In einigen Fällen kann es für einen Shader erforderlich sein, dass die internen Schritte einer Berechnung mit voller Genauigkeit ausgeführt werden, auch wenn Eingabe- und Endausgabewerte nicht mehr als eine teilgenaue Genauigkeit aufweisen.

Software-Vertex- und Pixel-Shader

Softwareimplementierungen (Laufzeit und Referenz für Vertexshader und Referenz für Pixelshader) von Shadern der Version 2_0 und höher haben eine gewisse Validierungslockerung. Dies ist für Debugging- und Prototyperstellungszwecke nützlich. Die Anwendung gibt der Laufzeit/dem Assembler an, dass sie einen Teil der Validierung mithilfe des flags _sw im Assembler (z. B. vs_2_sw) entspannt benötigt. Ein Softwareshader funktioniert nicht mit Hardware.

vs_2_sw ist eine Entspannung bis zu den maximalen Vs_2_x; ebenso ist ps_2_sw eine Entspannung bis zu den maximalen Obergrenzen von ps_2_x. Insbesondere werden die folgenden Validierungen gelockert:

Shadermodell Resource Begrenzung
vs_2_sw, vs_3_sw, ps_2_sw, ps_3_sw Anzahl der Anweisungen Unbegrenzt
vs_2_sw, vs_3_sw, ps_2_sw, ps_3_sw Float-Konstantenregister 8192
vs_2_sw, vs_3_sw, ps_2_sw, ps_3_sw Ganzzahlige Konstantenregister 2048
vs_2_sw, vs_3_sw, ps_2_sw, ps_3_sw Boolesche Konstantenregister 2048
ps_2_sw Abhängige Lesetiefe Unbegrenzt
vs_2_sw Anweisungen und Bezeichnungen für die Flusssteuerung Unbegrenzt
vs_2_sw, vs_3_sw, ps_2_sw, ps_3_sw Schleifenstart/Schritt/Anzahl Iterationsstart und Iterationsschrittgröße für Rep- und Schleifenanweisungen sind 32-Bit-Ganzzahlen mit Vorzeichen. Die Anzahl kann bis zu MAX_INT/64 sein.
vs_2_sw, vs_3_sw, ps_2_sw, ps_3_sw Portgrenzwerte Die Portgrenzwerte für alle Registerdateien werden gelockert.
vs_3_sw Anzahl der Interpolatoren 16 Ausgaberegister in vs_3_sw.
ps_3_sw Anzahl der Interpolatoren 14(16-2) Eingaberegister für ps_3_sw.

 

Shadermodell 3 (DirectX HLSL)