Variablensyntax

Verwenden Sie die folgenden Syntaxregeln, um HLSL-Variablen zu deklarieren.

[Storage_Class] [Type_Modifier] Typname[Index] [: Semantik] [: Packoffset] [: Register]; [Anmerkungen] [= Initial_Value]

Parameter

Storage_Class

Optionale Speicherklassenmodifizierer, die dem Compiler Hinweise zum Variablenbereich und zur Variablenlebensdauer geben; Die Modifizierer können in beliebiger Reihenfolge angegeben werden.

Wert BESCHREIBUNG
extern Markieren Sie eine globale Variable als externe Eingabe für den Shader. Dies ist die Standardmarkierung für alle globalen Variablen. Kann nicht mit statisch kombiniert werden.
nointerpolation Interpolieren Sie die Ausgaben eines Vertex-Shaders nicht, bevor Sie sie an einen Pixel-Shader übergeben.
Präzise Die genaue Schlüsselwort (keyword), wenn sie auf eine Variable angewendet wird, schränkt alle Berechnungen ein, die verwendet werden, um den dieser Variablen zugewiesenen Wert auf folgende Weise zu erzeugen:
  • Separate Vorgänge werden getrennt gehalten. Wenn beispielsweise ein Mul- und Add-Vorgang zu einem verrückten Vorgang verschmolzen wurde, zwingt präzise die Vorgänge, getrennt zu bleiben. Stattdessen müssen Sie explizit die verrückte intrinsische Funktion verwenden.
  • Die Reihenfolge der Vorgänge wird beibehalten. Wenn die Reihenfolge der Anweisungen zur Verbesserung der Leistung möglicherweise gemischt wurde, stellt präzise sicher, dass der Compiler die Reihenfolge wie geschrieben behält.
  • UNSICHERE IEEE-Vorgänge sind eingeschränkt. Wenn der Compiler möglicherweise schnelle mathematische Vorgänge verwendet hat, die keine NaN-Werte (nicht eine Zahl) und INF -Werte (unendlich) berücksichtigen, müssen die IEEE-Anforderungen in Bezug auf NaN- und INF-Werte genau beachtet werden. Ohne präzise sind diese Optimierungen und mathematischen Vorgänge nicht IEEE-sicher.
  • Das Qualifizieren einer Variablen präzise führt keine Vorgänge durch, die die Variable verwenden. Da eine präzise Weitergabe nur auf Vorgänge erfolgt, die zu den Werten beitragen, die der präzisen Variablen zugewiesen sind , kann es schwierig sein, die gewünschten Berechnungen korrekt zu machen. Daher empfiehlt es sich, die Shaderausgaben direkt dort zu markieren, wo Sie sie deklarieren, unabhängig davon, ob es sich um ein Strukturfeld oder einen Ausgabeparameter oder den Rückgabetyp der Eingabefunktion handelt. Die Möglichkeit, Optimierungen auf diese Weise zu steuern, behält die Ergebnisinvarianz für die geänderte Ausgabevarianz bei, indem Optimierungen deaktiviert werden, die sich aufgrund von Unterschieden in der akkumulierten Genauigkeit auf die Endergebnisse auswirken können. Dies ist nützlich, wenn Shader für tessellation wasserdichte Patchnähte beibehalten oder Tiefenwerte über mehrere Durchläufe abgleichen sollen. Beispielcode:
    HLSLmatrix g_mWorldViewProjection;
    void Standard(in float3 InPos : Position, out precise float4 OutPos : SV_Position)
    {
    Der Vorgang ist präzise, da er zum präzisen Parameter OutPos beiträgt
    OutPos = mul( float4( InPos, 1.0 ), g_mWorldViewProjection );
    }
geteilt Markieren Sie eine Variable für die Gemeinsame Nutzung zwischen Effekten; Dies ist ein Hinweis auf den Compiler.
groupshared Markieren Sie eine Variable für Threadgruppen-Shared Memory für Compute-Shader. In D3D10 beträgt die maximale Gesamtgröße aller Variablen mit der gruppenfreigaben Speicherklasse 16 KB, in D3D11 beträgt die maximale Größe 32 KB. Siehe Beispiele.
static Markieren Sie eine lokale Variable, sodass sie einmal initialisiert wird und zwischen Funktionsaufrufen beibehalten wird. Wenn die Deklaration keinen Initialisierer enthält, wird der Wert auf 0 festgelegt. Eine als statisch markierte globale Variable ist für eine Anwendung nicht sichtbar.
Einheitliche Markieren Sie eine Variable, deren Daten während der gesamten Ausführung eines Shaders konstant sind (z. B. eine Materialfarbe in einem Vertex-Shader); globale Variablen gelten standardmäßig als einheitlich .
volatile Markieren Sie eine Variable, die sich häufig ändert. Dies ist ein Hinweis auf den Compiler. Dieser Speicherklassenmodifizierer gilt nur für eine lokale Variable.
Hinweis: Der HLSL-Compiler ignoriert derzeit diesen Speicherklassenmodifizierer.

Type_Modifier

Optionaler Variablentypmodifizierer.

Wert BESCHREIBUNG
const Markieren Sie eine Variable, die nicht durch einen Shader geändert werden kann. Daher muss sie in der Variablendeklaration initialisiert werden. Globale Variablen gelten standardmäßig als const (unterdrücken Sie dieses Verhalten, indem Sie dem Compiler das Flag /Gec bereitstellen).
row_major Markieren Sie eine Variable, die vier Komponenten in einer einzelnen Zeile speichert, damit sie in einem einzelnen Konstantenregister gespeichert werden können.
column_major Markieren Sie eine Variable, die 4 Komponenten in einer einzelnen Spalte speichert, um die Matrixmathematik zu optimieren.

Hinweis

Wenn Sie keinen Typmodifiziererwert angeben, verwendet der Compiler column_major als Standardwert.

Type

Ein beliebiger HLSL-Typ, der unter Datentypen (DirectX HLSL) aufgeführt ist.

Name[Index]

ASCII-Zeichenfolge, die eine Shadervariable eindeutig identifiziert. Um ein optionales Array zu definieren, verwenden Sie den Index für die Arraygröße, die eine positive ganze Zahl = 1 ist.

Semantische

Optionale Parameterverwendungsinformationen, die vom Compiler zum Verknüpfen von Shadereingaben und -ausgaben verwendet werden. Es gibt mehrere vordefinierte Semantiken für Vertex- und Pixel-Shader. Der Compiler ignoriert die Semantik, es sei denn, sie werden für eine globale Variable deklariert oder ein Parameter, der an einen Shader übergeben wird.

Packoffset

Optional Schlüsselwort (keyword) zum manuellen Packen von Shaderkonstanten. Siehe packoffset (DirectX HLSL).

Registrieren

Optional Schlüsselwort (keyword) zum manuellen Zuweisen einer Shadervariablen zu einem bestimmten Register. Siehe registrieren (DirectX HLSL).

Anmerkungen

Optionale Metadaten in Form einer Zeichenfolge, die an eine globale Variable angefügt sind. Eine Anmerkung wird vom Effektframework verwendet und von HLSL ignoriert. Eine ausführlichere Syntax finden Sie unter Anmerkungssyntax.

Initial_Value

Optionale Anfangswerte; die Anzahl der Werte sollte mit der Anzahl der Komponenten in Type übereinstimmen. Jede globale Variable, die extern markiert ist, muss mit einem Literalwert initialisiert werden. Jede variable, die als statisch markiert ist, muss mit einer Konstanten initialisiert werden.

Globale Variablen, die nicht als statisch oder extern gekennzeichnet sind, werden nicht in den Shader kompiliert. Der Compiler legt nicht automatisch Standardwerte für globale Variablen fest und kann sie nicht in Optimierungen verwenden. Um diesen Typ von globalen Variablen zu initialisieren, verwenden Sie reflektion, um den Wert abzurufen, und kopieren Sie den Wert dann in einen konstanten Puffer. Sie können beispielsweise die ID3D11ShaderReflection::GetVariableByName-Methode verwenden, um die Variable abzurufen, die ID3D11ShaderReflectionVariable::GetDesc-Methode zum Abrufen der Shadervariablenbeschreibung und den Anfangswert aus dem DefaultValue-Member der D3D11_SHADER_VARIABLE_DESC-Struktur abzurufen. Um den Wert in den Konstantenpuffer zu kopieren, müssen Sie sicherstellen, dass der Puffer mit CPU-Schreibzugriff (D3D11_CPU_ACCESS_WRITE) erstellt wurde. Weitere Informationen zum Erstellen eines Konstantenpuffers finden Sie unter Vorgehensweise: Erstellen eines Konstantenpuffers.

Sie können auch das Effektframework verwenden, um das Reflektieren und Festlegen des Anfangswerts automatisch zu verarbeiten. Sie können beispielsweise die ID3DX11EffectPass::Apply-Methode verwenden.

Beispiele

Im Folgenden finden Sie mehrere Beispiele für Shadervariablendeklarationen.

float fVar;
float4 color;
float fVar = 3.1f;

int iVar[3];

int iVar[3] = {1,2,3};

uniform float4 position : SV_POSITION; 
const float4 lightDirection = {0,0,1};
      

Freigegebene Gruppe

HLSL ermöglicht Threads eines Compute-Shaders den Austausch von Werten über gemeinsam genutzten Arbeitsspeicher. HLSL stellt Barrieregrundtypen wie GroupMemoryBarrierWithGroupSync usw. bereit, um die richtige Reihenfolge von Lese- und Schreibvorgängen im gemeinsam genutzten Speicher im Shader sicherzustellen und Datenrassen zu vermeiden.

Hinweis

Hardware führt Threads in Gruppen (Warps oder Wellenfronten) aus, und die Synchronisierung von Barrieren kann manchmal weggelassen werden, um die Leistung zu erhöhen, wenn nur die Synchronisierung von Threads, die zu derselben Gruppe gehören, richtig ist. Wir raten jedoch dringend davon ab, diese Auslassung aus folgenden Gründen zu unterlassen:

  • Diese Auslassung führt zu nicht portierbarem Code, der auf einiger Hardware möglicherweise nicht funktioniert und bei Softwarerasterizern, die normalerweise Threads in kleineren Gruppen ausführen, nicht funktioniert.
  • Die Leistungsverbesserungen, die Sie mit dieser Auslassung erzielen können, sind im Vergleich zur Verwendung von All-Thread-Barrieren geringfügig.

In Direct3D 10 gibt es keine Synchronisierung von Threads beim Schreiben in groupshared. Dies bedeutet, dass jeder Thread auf einen einzelnen Speicherort in einem Array zum Schreiben beschränkt ist. Verwenden Sie den SV_GroupIndex Systemwert, um beim Schreiben in dieses Array zu indizieren, um sicherzustellen, dass keine zwei Threads kollidieren können. In Bezug auf das Lesen haben alle Threads Zugriff auf das gesamte Array zum Lesen.

struct GSData
{
    float4 Color;
    float Factor;
}

groupshared GSData data[5*5*1];

[numthreads(5,5,1)]
void main( uint index : SV_GroupIndex )
{
    data[index].Color = (float4)0;
    data[index].Factor = 2.0f;
    GroupMemoryBarrierWithGroupSync();
    ...
}

Verpackung

Packen Sie Unterkomponenten von Vektoren und Skalaren, deren Größe groß genug ist, um das Überschreiten von Registergrenzen zu verhindern. Dies sind z. B. alle gültig:

cbuffer MyBuffer
{
    float4 Element1 : packoffset(c0);
    float1 Element2 : packoffset(c1);
    float1 Element3 : packoffset(c1.y);
}
        

Packungstypen können nicht gemischt werden.

Wie das Register Schlüsselwort (keyword) kann ein Packoffset zielspezifisch sein. Die Unterkomponentenverpackung ist nur mit dem packoffset Schlüsselwort (keyword) und nicht mit dem Register Schlüsselwort (keyword) verfügbar. In einer cbuffer-Deklaration wird das Register Schlüsselwort (keyword) für Direct3D 10-Ziele ignoriert, da davon ausgegangen wird, dass es sich um plattformübergreifende Kompatibilität handelt.

Gepackte Elemente können sich überlappen, und der Compiler gibt keinen Fehler oder keine Warnung aus. In diesem Beispiel überlappen sich Element2 und Element3 mit Element1.x und Element1.y.

cbuffer MyBuffer
{
    float4 Element1 : packoffset(c0);
    float1 Element2 : packoffset(c0);
    float1 Element3 : packoffset(c0.y);
}
        

Ein Beispiel, das packoffset verwendet, ist : HLSLWithoutFX10-Beispiel.

Variablen (DirectX HLSL)