Specifica delle firme radice in HLSL

La specifica delle firme radice nel modello HLSL Shader 5.1 è un'alternativa a specificarli nel codice C++.

Un esempio di firma radice HLSL

Una firma radice può essere specificata in HLSL come stringa. La stringa contiene una raccolta di clausole delimitate da virgole che descrivono i componenti costitutivi della firma radice. La firma radice deve essere identica tra shader per qualsiasi oggetto stato della pipeline (PSO). Esempio:

Firma radice versione 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 )"

Questa definizione darà la firma radice seguente, notando:

  • Uso dei parametri predefiniti.
  • b0 e (b0, space=1) non sono in conflitto
  • u0 è visibile solo al geometry shader
  • u4 e u5 vengono aliasati allo stesso descrittore in un heap

una firma radice specificata usando il linguaggio di shader di alto livello

Firma radice versione 1.1

La versione radice della firma 1.1 abilita le ottimizzazioni dei driver nei descrittori e nei dati della firma radice.

#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 )"

Il linguaggio di firma radice HLSL corrisponde strettamente alle API della firma radice C++ e ha una potenza espressiva equivalente. La firma radice viene specificata come sequenza di clausole, separate da virgole. L'ordine delle clausole è importante, poiché l'ordine di analisi determina la posizione dello slot nella firma radice. Ogni clausola accetta uno o più parametri denominati. L'ordine dei parametri non è tuttavia importante.

RootFlags

La clausola RootFlags facoltativa accetta 0 (il valore predefinito per indicare nessun flag) o uno o più dei valori dei flag radice predefiniti, connessi tramite l'operatore OR '|'. I valori del flag radice consentiti sono definiti da D3D12_ROOT_SIGNATURE_FLAGS.

Ad esempio:

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

Costanti radice

La clausola RootConstants specifica le costanti radice nella firma radice. Due parametri obbligatori sono: num32BitConstants e bReg (il registro corrispondente a BaseShaderRegister nelle API C++) del cbuffer. Lo spazio (RegisterSpace nelle API C++) e la visibilità (shaderVisibility in C++) sono facoltativi e i valori predefiniti sono:

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

Ad esempio:

RootConstants(num32BitConstants=3, b3)

Visibilità

La visibilità è un parametro facoltativo che può avere uno dei valori di D3D12_SHADER_VISIBILITY.

SHADER_VISIBILITY_ALL trasmette gli argomenti radice a tutti gli shader. In alcuni hardware questo non ha costi, ma in altri hardware è previsto un costo per fork dei dati in tutte le fasi dello shader. L'impostazione di una delle opzioni, ad esempio SHADER_VISIBILITY_VERTEX, limita l'argomento radice a una singola fase dello shader.

L'impostazione degli argomenti radice su fasi di single shader consente di usare lo stesso nome di associazione in fasi diverse. Ad esempio, un'associazione SRV di t0,SHADER_VISIBILITY_VERTEX e un'associazione SRV di t0,SHADER_VISIBILITY_PIXEL sarebbe valida. Tuttavia, se l'impostazione di visibilità era t0,SHADER_VISIBILITY_ALL per una delle associazioni, la firma radice non sarebbe valida.

CBV a livello radice

La CBV clausola (visualizzazione buffer costante) specifica una voce b-register Reg del buffer a livello radice. Si noti che si tratta di una voce scalare; non è possibile specificare un intervallo per il livello radice.

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 a livello radice

La SRV clausola (visualizzazione risorse shader) specifica una voce SRV t-register Reg a livello radice. Si noti che si tratta di una voce scalare; non è possibile specificare un intervallo per il livello radice.

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 a livello radice

La UAV clausola (visualizzazione accesso non ordinata) specifica una voce UAV a livello radice di registrazione u-register Reg. Si noti che si tratta di una voce scalare; non è possibile specificare un intervallo per il livello radice.

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 ])

Ad esempio:

UAV(u3)

Tabella descrittore

La DescriptorTable clausola è un elenco di clausole di tabella delimitate da virgole, nonché un parametro di visibilità facoltativo. Le clausole DescriptorTable includono CBV, SRV, UAV e Sampler. Si noti che i relativi parametri differiscono da quelli delle clausole a livello radice.

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

La tabella CBV descrittore ha la sintassi seguente:

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 ])

Ad esempio:

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

Il parametro obbligatorio bReg specifica l'inizio reg dell'intervallo cbuffer. Il parametro numDescriptors specifica il numero di descrittori nell'intervallo cbuffer contiguo; il valore predefinito 1. La voce dichiara un intervallo [Reg, Reg + numDescriptors - 1] cbuffer, quando numDescriptors è un numero. Se numDescriptors è uguale a "non collegato", l'intervallo è [Reg, UINT_MAX], il che significa che l'app deve assicurarsi che non faccia riferimento a un'area non vincolata. Il campo offset rappresenta il parametro OffsetInDescriptorsFromTableStart nelle API C++, ovvero l'offset (in descrittori) dall'inizio della tabella. Se l'offset è impostato su DESCRIPTOR_RANGE_OFFSET_APPEND (impostazione predefinita), significa che l'intervallo è direttamente dopo l'intervallo precedente. Tuttavia, l'immissione di offset specifici consente agli intervalli di sovrapporsi tra loro, consentendo di registrare l'aliasing.

La tabella SRV descrittore ha la sintassi seguente:

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 ])

Questa operazione è simile alla voce della tabella CBV descrittore, ad eccezione dell'intervallo specificato per le visualizzazioni delle risorse shader.

La tabella UAV descrittore ha la sintassi seguente:

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 ])

Questa operazione è simile alla voce della tabella CBV descrittore, ad eccezione dell'intervallo specificato per le visualizzazioni di accesso non ordinate.

La tabella Sampler descrittore ha la sintassi seguente:

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 ])

Questa operazione è simile alla voce della tabella CBV descrittore, ad eccezione dell'intervallo specificato per i sampler shader. Si noti che gli esempi non possono essere combinati con altri tipi di descrittori nella stessa tabella descrittore (poiché si trovano in un heap descrittore separato).

Sampler statico

L'esempio statico rappresenta la struttura D3D12_STATIC_SAMPLER_DESC . Il parametro obbligatorio per StaticSampler è un registro scalare, sampler s-register Reg. Altri parametri sono facoltativi con i valori predefiniti illustrati di seguito. La maggior parte dei campi accetta un set di enumerazioni predefinite.

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 ])

Ad esempio:

StaticSampler(s4, filter=FILTER_MIN_MAG_MIP_LINEAR)

Le opzioni dei parametri sono molto simili alle chiamate API C++, ad eccezione del borderColor, che è limitato a un'enumerazione in HLSL.

Il campo filtro può essere uno dei D3D12_FILTER.

I campi degli indirizzi possono essere uno dei D3D12_TEXTURE_ADDRESS_MODE.

La funzione di confronto può essere una delle D3D12_COMPARISON_FUNC.

Il campo colore bordo può essere uno dei D3D12_STATIC_BORDER_COLOR.

La visibilità può essere una delle D3D12_SHADER_VISIBILITY.

Compilazione di una firma radice HLSL

Esistono due meccanismi per compilare una firma radice HLSL. Prima di tutto, è possibile collegare una stringa di firma radice a un particolare shader tramite l'attributo RootSignature (nell'esempio seguente, usando il punto di ingresso MyRS1 ):

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

Il compilatore creerà e verificherà il BLOB della firma radice per lo shader e lo incorporare insieme al codice di byte shader nel BLOB shader. Il compilatore supporta la sintassi della firma radice per il modello shader 5.0 e versioni successive. Se una firma radice è incorporata in uno shader modello di shader 5.0 e tale shader viene inviato al runtime D3D11, anziché D3D12, la parte della firma radice verrà ignorata automaticamente da D3D11.

L'altro meccanismo consiste nel creare un BLOB di firma radice autonomo, forse per riutilizzarlo con un ampio set di shader, risparmiando spazio. Effect-Compiler Tool (FXC) supporta sia modelli rootsig_1_0che rootsig_1_1 shader. Il nome della stringa di definizione viene specificato tramite l'argomento /E consueto. Ad esempio:

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

Si noti che la stringa di firma radice definita può anche essere passata alla riga di comando, ad esempio /D MyRS1="...".

Modifica delle firme radice con il compilatore FXC

Il compilatore FXC crea il codice byte dello shader dai file di origine HLSL. Per questo compilatore sono disponibili molti parametri facoltativi, fare riferimento allo strumento Effect-Compiler.

Per la gestione delle firme radice create da HLSL, la tabella seguente fornisce alcuni esempi dell'uso di FXC.

A linee Riga di comando Descrizione
1 fxc /T ps_5_1 shaderWithRootSig.hlsl /Fo rs1.fxo Compila uno shader per la destinazione pixel shader 5.1, l'origine dello shader si trova nel file shaderWithRootSig.hlsl, che include una firma radice. Lo shader e la firma radice vengono compilati come BLOB separati nel file binario rs1.fxo.
2 fxc /dumpbin rs1.fxo /extractrootsignature /Fo rs1.rs.fxo Estrae la firma radice dal file creato dalla riga 1, quindi il file rs1.rs.fxo contiene solo una firma radice.
3 fxc /dumpbin rs1.fxo /Qstrip_rootsignature /Fo rs1.stripped.fxo Rimuove la firma radice dal file creato dalla riga 1, quindi il file rs1.stripped.fxo contiene uno shader senza firma radice.
4 fxc /dumpbin rs1.stripped.fxo /setrootsignature rs1.rs.fxo /Fo rs1.new.fxo Combina uno shader e una firma radice che si trovano in file separati in un file binario contenente entrambi i BLOB. In questo esempio rs1.new.fx0 sarebbe identico a rs1.fx0 nella riga 1.
5 fxc /T rootsig_1_0 rootSigAndMaybeShaderInHereToo.hlsl /E RS1 /Fo rs2.fxo Crea un file binario di firma radice autonomo da un'origine che può contenere più di una sola firma radice. Si noti la destinazione rootsig_1_0 e che RS1 è il nome della stringa di macro della firma radice (#define) nel file HLSL.

 

La funzionalità disponibile tramite FXC è disponibile anche a livello di codice usando la funzione D3DCompile . Questa chiamata compila uno shader con una firma radice o una firma radice autonoma (impostando la destinazione rootsig_1_0). D3DGetBlobPart e D3DSetBlobPart possono estrarre e collegare firme radice a un BLOB esistente.  D3D_BLOB_ROOT_SIGNATURE viene usato per specificare il tipo di parte del BLOB della firma radice. D3DStripShader rimuove la firma radice (usando il flag D3DCOMPILER_STRIP_ROOT_SIGNATURE) dal BLOB.

Note

Nota

Mentre la compilazione offline degli shader è fortemente consigliata, se gli shader devono essere compilati in fase di esecuzione, fare riferimento alle osservazioni per D3DCompile2.

 

Nota

Non è necessario modificare gli asset HLSL esistenti per gestire le firme radice da usare con essi.

 

Indicizzazione dinamica con HLSL 5.1

Funzionalità dello shader HLSL Model 5.1 per Direct3D 12

Associazione di risorse

Associazione di risorse in HLSL

Firme radice

Modello shader 5.1

Valore di riferimento dello stencil specificato dello shader

Caricamenti della visualizzazione accesso non ordinato tipizzato