Festlegen von Stammsignaturen in HLSL

Das Angeben von Stammsignaturen im HLSL-Shadermodell 5.1 ist eine Alternative zur Angabe in C++-Code.

Beispiel für HLSL-Stammsignatur

Eine Stammsignatur kann in HLSL als Zeichenfolge angegeben werden. Die Zeichenfolge enthält eine Auflistung von durch Trennzeichen getrennten Klauseln, die Komponenten der Stammsignatur beschreiben. Die Stammsignatur sollte für jedes Pipelinezustandsobjekt (PSO) shaderübergreifend identisch sein. Beispiel:

Stammsignaturversion 1.0

#define MyRS1 "RootFlags( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | " \
                         "DENY_VERTEX_SHADER_ROOT_ACCESS), " \
              "CBV(b0, space = 1), " \
              "SRV(t0), " \
              "UAV(u0, visibility = SHADER_VISIBILITY_GEOMETRY), " \
              "DescriptorTable( CBV(b0), " \
                               "UAV(u1, numDescriptors = 2), " \
                               "SRV(t1, numDescriptors = unbounded)), " \
              "DescriptorTable(Sampler(s0, numDescriptors = 2)), " \
              "RootConstants(num32BitConstants=1, b9), " \
              "DescriptorTable( UAV(u3), " \
                               "UAV(u4), " \
                               "UAV(u5, offset=1)), " \

              "StaticSampler(s2)," \
              "StaticSampler(s3, " \
                             "addressU = TEXTURE_ADDRESS_CLAMP, " \
                             "filter = FILTER_MIN_MAG_MIP_LINEAR )"

Diese Definition würde die folgende Stammsignatur aufweisen und beachten:

  • Die Verwendung von Standardparametern.
  • b0 und (b0, leerzeichen=1) nicht in Konflikt
  • u0 ist nur für den Geometrie-Shader sichtbar
  • u4 und u5 werden als Alias für denselben Deskriptor in einem Heap verwendet.

Eine Stammsignatur, die mithilfe der allgemeinen Shadersprache angegeben wird

Stammsignatur, Version 1.1

Root Signature Version 1.1 ermöglicht Treiberoptimierungen für Stammsignaturdeskriptoren und -daten.

#define MyRS1 "RootFlags( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | " \
                         "DENY_VERTEX_SHADER_ROOT_ACCESS), " \
              "CBV(b0, space = 1, flags = DATA_STATIC), " \
              "SRV(t0), " \
              "UAV(u0), " \
              "DescriptorTable( CBV(b1), " \
                               "SRV(t1, numDescriptors = 8, " \
                               "        flags = DESCRIPTORS_VOLATILE), " \
                               "UAV(u1, numDescriptors = unbounded, " \
                               "        flags = DESCRIPTORS_VOLATILE)), " \
              "DescriptorTable(Sampler(s0, space=1, numDescriptors = 4)), " \
              "RootConstants(num32BitConstants=3, b10), " \
              "StaticSampler(s1)," \
              "StaticSampler(s2, " \
                             "addressU = TEXTURE_ADDRESS_CLAMP, " \
                             "filter = FILTER_MIN_MAG_MIP_LINEAR )"

Die HLSL-Stammsignatursprache entspricht eng den C++-Stammsignatur-APIs und verfügt über eine entsprechende Ausdruckskraft. Die Stammsignatur wird als Sequenz von Klauseln angegeben, die durch Kommas getrennt sind. Die Reihenfolge der Klauseln ist wichtig, da die Reihenfolge der Analyse die Slotposition in der Stammsignatur bestimmt. Jede Klausel akzeptiert einen oder mehrere benannte Parameter. Die Reihenfolge der Parameter ist jedoch nicht wichtig.

RootFlags

Die optionale RootFlags-Klausel akzeptiert entweder 0 (der Standardwert, um keine Flags anzugeben) oder einen oder mehrere vordefinierte Stammflagswerte, die über den OR-Operator '|' verbunden sind. Die zulässigen Stammflagswerte werden durch D3D12_ROOT_SIGNATURE_FLAGS definiert.

Beispiel:

RootFlags(0) // default value – no flags
RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT)
RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | DENY_VERTEX_SHADER_ROOT_ACCESS)

Stammkonstanten

Die RootConstants-Klausel gibt Stammkonstanten in der Stammsignatur an. Zwei obligatorische Parameter sind : num32BitConstants und bReg (das Register, das BaseShaderRegister in C++-APIs entspricht) des cbuffer. Die Parameter space (RegisterSpace in C++-APIs) und visibility (ShaderVisibility in C++) sind optional, und die Standardwerte sind:

RootConstants(num32BitConstants=N, bReg [, space=0, 
              visibility=SHADER_VISIBILITY_ALL ])

Beispiel:

RootConstants(num32BitConstants=3, b3)

Sichtbarkeit

Sichtbarkeit ist ein optionaler Parameter, der einen der Werte aus D3D12_SHADER_VISIBILITY enthalten kann.

SHADER_VISIBILITY_ALL überträgt die Stammargumente an alle Shader. Auf mancher Hardware fallen keine Kosten an, aber bei anderer Hardware fallen Kosten für das Forken der Daten in alle Shaderphasen an. Durch Festlegen einer der Optionen, z. B. SHADER_VISIBILITY_VERTEX, wird das Stammargument auf eine einzelne Shaderstufe beschränkt.

Das Festlegen von Stammargumenten auf einzelne Shaderphasen ermöglicht die Verwendung desselben Bindungsnamens in verschiedenen Phasen. Beispielsweise wäre eine SRV-Bindung von und die t0,SHADER_VISIBILITY_VERTEX SRV-Bindung von t0,SHADER_VISIBILITY_PIXEL gültig. Wenn die Sichtbarkeitseinstellung t0,SHADER_VISIBILITY_ALL jedoch für eine der Bindungen gilt, wäre die Stammsignatur ungültig.

CBV auf Stammebene

Die CBV (Konstantenpufferansicht)-Klausel gibt einen Stammebenenkonstantenpuffer b-register Reg-Eintrag an. Beachten Sie, dass dies ein Skalareintrag ist. Es ist nicht möglich, einen Bereich für die Stammebene anzugeben.

CBV(bReg [, space=0, visibility=SHADER_VISIBILITY_ALL ])    //   Version 1.0
CBV(bReg [, space=0, visibility=SHADER_VISIBILITY_ALL,      // Version 1.1
            flags=DATA_STATIC_WHILE_SET_AT_EXECUTE ])

SRV auf Stammebene

Die SRV (Shaderressourcenansicht)-Klausel gibt einen SRV t-register-Reg-Eintrag auf Stammebene an. Beachten Sie, dass dies ein Skalareintrag ist. Es ist nicht möglich, einen Bereich für die Stammebene anzugeben.

SRV(tReg [, space=0, visibility=SHADER_VISIBILITY_ALL ])    //   Version 1.0
SRV(tReg [, space=0, visibility=SHADER_VISIBILITY_ALL,      // Version 1.1
            flags=DATA_STATIC_WHILE_SET_AT_EXECUTE ])

UAV auf Stammebene

Die UAV (ungeordnete Zugriffsansicht) -Klausel gibt einen UAV-Registrierungseintrag auf Stammebene an. Beachten Sie, dass dies ein Skalareintrag ist. Es ist nicht möglich, einen Bereich für die Stammebene anzugeben.

UAV(uReg [, space=0, visibility=SHADER_VISIBILITY_ALL ])    //   Version 1.0
UAV(uReg [, space=0, visibility=SHADER_VISIBILITY_ALL,      // Version 1.1
            flags=DATA_VOLATILE ])

Beispiel:

UAV(u3)

Deskriptortabelle

Die DescriptorTable -Klausel selbst ist eine Liste von durch Trennzeichen getrennten Deskriptortabellenklauseln sowie ein optionaler Sichtbarkeitsparameter. Die DescriptorTable-Klauseln umfassen CBV, SRV, UAV und Sampler. Beachten Sie, dass sich ihre Parameter von denen der Stammebenenklauseln unterscheiden.

DescriptorTable( DTClause1, [ DTClause2, … DTClauseN,
                 visibility=SHADER_VISIBILITY_ALL ] )

Die Deskriptortabelle CBV weist die folgende Syntax auf:

CBV(bReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND ])   // Version 1.0
CBV(bReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND      // Version 1.1
          , flags=DATA_STATIC_WHILE_SET_AT_EXECUTE ])

Beispiel:

DescriptorTable(CBV(b0),SRV(t3, numDescriptors=unbounded))

Der obligatorische Parameter bReg gibt den Startreg des cbuffer-Bereichs an. Der NumDescriptors-Parameter gibt die Anzahl der Deskriptoren im zusammenhängenden cbuffer-Bereich an. Der Standardwert ist 1. Der Eintrag deklariert einen cbuffer-Bereich [Reg, Reg + numDescriptors - 1], wenn numDescriptors eine Zahl ist. Wenn numDescriptors gleich "unbounded" ist, lautet [Reg, UINT_MAX]der Bereich , was bedeutet, dass die App sicherstellen muss, dass sie nicht auf einen außerhalb der Grenzen stehenden Bereich verweist. Das Offsetfeld stellt den OffsetInDescriptorsFromTableStart-Parameter in den C++-APIs dar, d. h. den Offset (in Deskriptoren) vom Anfang der Tabelle. Wenn der Offset auf DESCRIPTOR_RANGE_OFFSET_APPEND (Standard) festgelegt ist, bedeutet dies, dass der Bereich direkt nach dem vorherigen Bereich liegt. Durch die Eingabe bestimmter Offsets können sich Bereiche jedoch überlappen, sodass Registeraliasing möglich ist.

Die Deskriptortabelle SRV weist die folgende Syntax auf:

SRV(tReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND ])    // Version 1.0
SRV(tReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND,      // Version 1.1
            flags=DATA_STATIC_WHILE_SET_AT_EXECUTE ])

Dies ähnelt dem Deskriptortabelleneintrag CBV , mit der Ausnahme, dass der angegebene Bereich für Shaderressourcenansichten gilt.

Die Deskriptortabelle UAV weist die folgende Syntax auf:

UAV(uReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND ])    // Version 1.0
UAV(uReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND,      // Version 1.1
            flags=DATA_VOLATILE ])

Dies ähnelt dem Deskriptortabelleneintrag CBV , mit der Ausnahme, dass der angegebene Bereich für ungeordnete Zugriffsansichten gilt.

Die Deskriptortabelle Sampler weist die folgende Syntax auf:

Sampler(sReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND ])  // Version 1.0
Sampler(sReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND,    // Version 1.1
                flags=0 ])

Dies ähnelt dem Deskriptortabelleneintrag CBV , mit der Ausnahme, dass der angegebene Bereich für Shader-Sampler gilt. Beachten Sie, dass Sampler nicht mit anderen Deskriptorentypen in derselben Deskriptortabelle gemischt werden können (da sie sich in einem separaten Deskriptorheap befinden).

Statischer Sampler

Der statische Sampler stellt die D3D12_STATIC_SAMPLER_DESC-Struktur dar. Der obligatorische Parameter für StaticSampler ist ein skalarer Sampler s-register Reg. Andere Parameter sind optional, wobei unten die Standardwerte angezeigt werden. Die meisten Felder akzeptieren einen Satz vordefinierter Enumerationen.

StaticSampler( sReg,
              [ filter = FILTER_ANISOTROPIC, 
                addressU = TEXTURE_ADDRESS_WRAP,
                addressV = TEXTURE_ADDRESS_WRAP,
                addressW = TEXTURE_ADDRESS_WRAP,
                mipLODBias = 0.f,
                maxAnisotropy = 16,
                comparisonFunc = COMPARISON_LESS_EQUAL,
                borderColor = STATIC_BORDER_COLOR_OPAQUE_WHITE,
                minLOD = 0.f,         
                maxLOD = 3.402823466e+38f,
                space = 0, 
                visibility = SHADER_VISIBILITY_ALL ])

Beispiel:

StaticSampler(s4, filter=FILTER_MIN_MAG_MIP_LINEAR)

Die Parameteroptionen ähneln den C++-API-Aufrufen sehr, mit Ausnahme von borderColor, das auf eine Enumeration in HLSL beschränkt ist.

Das Filterfeld kann eines der D3D12_FILTER sein.

Die Adressfelder können jeweils eines der D3D12_TEXTURE_ADDRESS_MODE sein.

Die Vergleichsfunktion kann eine der D3D12_COMPARISON_FUNC sein.

Das Rahmenfarbfeld kann eines der D3D12_STATIC_BORDER_COLOR sein.

Sichtbarkeit kann eine der D3D12_SHADER_VISIBILITY sein.

Kompilieren einer HLSL-Stammsignatur

Es gibt zwei Mechanismen zum Kompilieren einer HLSL-Stammsignatur. Zunächst ist es möglich, eine Stammsignaturzeichenfolge über das RootSignature-Attribut an einen bestimmten Shader anzufügen (im folgenden Beispiel unter Verwendung des Einstiegspunkts MyRS1 ):

[RootSignature(MyRS1)]
float4 main(float4 coord : COORD) : SV_Target
{
…
}

Der Compiler erstellt und überprüft das Stammsignaturblob für den Shader und bettet es zusammen mit dem Shaderbytecode in das Shaderblob ein. Der Compiler unterstützt die Stammsignatursyntax für Shadermodell 5.0 und höher. Wenn eine Stammsignatur in einen Shadermodell 5.0-Shader eingebettet ist und dieser Shader an die D3D11-Runtime im Gegensatz zu D3D12 gesendet wird, wird der Stammsignaturteil von D3D11 unbeaufsichtigt ignoriert.

Der andere Mechanismus besteht darin, ein eigenständiges Stammsignaturblob zu erstellen, um es möglicherweise mit einer großen Gruppe von Shadern wiederzuverwenden, um Platz zu sparen. Das Effekt-Compiler-Tool (FXC) unterstützt sowohl rootsig_1_0 als auchrootsig_1_1 Shadermodelle. Der Name der define-Zeichenfolge wird über das übliche Argument /E angegeben. Beispiel:

fxc.exe /T rootsig_1_1 MyRS1.hlsl /E MyRS1 /Fo MyRS1.fxo

Beachten Sie, dass die Stammsignaturzeichenfolge define auch über die Befehlszeile übergeben werden kann, z. B. /D MyRS1="...".

Bearbeiten von Stammsignaturen mit dem FXC-Compiler

Der FXC-Compiler erstellt Shaderbytecode aus HLSL-Quelldateien. Es gibt viele optionale Parameter für diesen Compiler, siehe Effect-Compiler Tool.

Für die Verwaltung von HLSL-erstellten Stammsignaturen enthält die folgende Tabelle einige Beispiele für die Verwendung von FXC.

Linie Befehlszeile BESCHREIBUNG
1 fxc /T ps_5_1 shaderWithRootSig.hlsl /Fo rs1.fxo Kompiliert einen Shader für das Pixel-Shader 5.1-Ziel. Die Shaderquelle befindet sich in der Datei shaderWithRootSig.hlsl, die eine Stammsignatur enthält. Der Shader und die Stammsignatur werden als separate Blobs in der Binärdatei rs1.fxo kompiliert.
2 fxc /dumpbin rs1.fxo /extractrootsignature /Fo rs1.rs.fxo Extrahiert die Stammsignatur aus der von Zeile 1 erstellten Datei, sodass die Datei rs1.rs.fxo nur eine Stammsignatur enthält.
3 fxc /dumpbin rs1.fxo /Qstrip_rootsignature /Fo rs1.stripped.fxo Entfernt die Stammsignatur aus der Von Zeile 1 erstellten Datei, sodass die Datei rs1.stripped.fxo einen Shader ohne Stammsignatur enthält.
4 fxc /dumpbin rs1.stripped.fxo /setrootsignature rs1.rs.fxo /Fo rs1.new.fxo Kombiniert einen Shader und eine Stammsignatur, die sich in separaten Dateien befinden, in einer Binärdatei, die beide Blobs enthält. In diesem Beispiel wäre rs1.new.fx0 mit rs1.fx0 in Zeile 1 identisch.
5 fxc /T rootsig_1_0 rootSigAndMaybeShaderInHereToo.hlsl /E RS1 /Fo rs2.fxo Erstellt eine eigenständige Binärdatei der Stammsignatur aus einer Quelle, die möglicherweise mehr als nur eine Stammsignatur enthält. Beachten Sie das rootsig_1_0-Ziel, und dass RS1 der Name der Makrozeichenfolge der Stammsignatur (#define) in der HLSL-Datei ist.

 

Die über FXC verfügbare Funktionalität ist auch programmgesteuert mit der D3DCompile-Funktion verfügbar. Dieser Aufruf kompiliert einen Shader mit einer Stammsignatur oder einer eigenständigen Stammsignatur (festlegen des rootsig_1_0 Ziels). D3DGetBlobPart und D3DSetBlobPart können Stammsignaturen extrahieren und an ein vorhandenes Blob anfügen.  D3D_BLOB_ROOT_SIGNATURE wird verwendet, um den Typ des Stammsignaturblobparts anzugeben. D3DStripShader entfernt die Stammsignatur (unter Verwendung des D3DCOMPILER_STRIP_ROOT_SIGNATURE Flags) aus dem Blob.

Hinweise

Hinweis

Während die Offlinekompilierung von Shadern dringend empfohlen wird, lesen Sie die Hinweise zu D3DCompile2, wenn Shader zur Laufzeit kompiliert werden müssen.

 

Hinweis

Vorhandene HLSL-Ressourcen müssen nicht geändert werden, um Stammsignaturen zu verarbeiten, die mit ihnen verwendet werden sollen.

 

Dynamische Indizierung mit HLSL 5.1

HLSL Shader Model 5.1 Features für Direct3D 12

Ressourcenbindung

Ressourcenbindung in HLSL

Stammsignaturen

Shadermodell 5.1

Von Shader festgelegter Schablonenreferenzwert

Getippte, nicht sortierte Zugriffsansichten werden geladen