Sintassi delle variabili
Usare le regole di sintassi seguenti per dichiarare le variabili HLSL.
[Storage_Class] [Type_Modifier] Type Name[Index] [: Semantic] [: Packoffset] [: Register]; [Annotazioni] [= Initial_Value]
Parametri
-
Storage_Class
-
Modificatori facoltativi della classe di archiviazione che forniscono agli hint del compilatore sull'ambito e sulla durata delle variabili; I modificatori possono essere specificati in qualsiasi ordine.
valore Descrizione extern Contrassegnare una variabile globale come input esterno allo shader; si tratta del contrassegno predefinito per tutte le variabili globali. Non può essere combinato con statico. nointerpolation Non interpolare gli output di un vertex shader prima di passarli a un pixel shader. preciso La parola chiave precisa quando applicata a una variabile limita tutti i calcoli usati per produrre il valore assegnato a tale variabile nei modi seguenti: - Le operazioni separate vengono mantenute separate. Ad esempio, dove un mul e un'operazione di aggiunta potrebbero essere stati fusi in un'operazione folle, precise forza le operazioni a rimanere separate. È invece necessario usare in modo esplicito la funzione intrinseca mad.
- L'ordine delle operazioni viene mantenuto. Se l'ordine delle istruzioni potrebbe essere stato casuale per migliorare le prestazioni, garantisce che il compilatore mantenga l'ordine come scritto.
- Le operazioni IEEE unsafe sono limitate. Se il compilatore potrebbe aver usato operazioni matematiche veloci che non considerano i valori NaN (non un numero) e INF (infinito), forza il rispetto dei requisiti IEEE relativi ai valori NaN e INF. Senza precisione, queste ottimizzazioni e operazioni matematiche non sono sicure da IEEE.
- La qualificazione di una variabile precisa non esegue operazioni che usano la variabile precisa. Poiché propaga in modo preciso solo le operazioni che contribuiscono ai valori assegnati alla variabile precisa, la corretta esecuzione dei calcoli desiderati può essere complessa, pertanto è consigliabile contrassegnare gli output dello shader in modo preciso in cui vengono dichiarati, indipendentemente dal fatto che si tratti di un campo di struttura o di un parametro di output o del tipo restituito della funzione di immissione. La possibilità di controllare le ottimizzazioni in questo modo mantiene l'invarianza per la variabile di output modificata disabilitando le ottimizzazioni che potrebbero influire sui risultati finali a causa delle differenze di precisione accumulate. È utile quando si desidera che gli shader per la tassellatura mantengano le cuciture patch strette dall'acqua o corrispondano ai valori di profondità su più passaggi. Codice di esempio:
HLSLmatrix g_mWorldViewProjection;
void main(in float3 InPos : Position, out precise float4 OutPos : SV_Position)
{
l'operazione è precisa perché contribuisce al parametro preciso OutPos
OutPos = mul( float4( InPos, 1.0 ), g_mWorldViewProjection );
}
condiviso Contrassegnare una variabile per la condivisione tra effetti; si tratta di un suggerimento per il compilatore. groupshared Contrassegnare una variabile per la memoria condivisa del gruppo di thread per gli shader di calcolo. In D3D10 la dimensione totale massima di tutte le variabili con la classe di archiviazione grouphared è di 16 kb, in D3D11 la dimensione massima è di 32 kb. Vedere esempi. static Contrassegnare una variabile locale in modo che venga inizializzata una volta e venga mantenuta tra le chiamate di funzione. Se la dichiarazione non include un inizializzatore, il valore viene impostato su zero. Una variabile globale contrassegnata come statica non è visibile a un'applicazione. uniform Contrassegnare una variabile i cui dati sono costanti durante l'esecuzione di uno shader (ad esempio un colore materiale in un vertex shader); le variabili globali sono considerate uniformi per impostazione predefinita. volatile Contrassegnare una variabile che cambia frequentemente; si tratta di un suggerimento per il compilatore. Questo modificatore della classe di archiviazione si applica solo a una variabile locale.
Nota: il compilatore HLSL attualmente ignora questo modificatore della classe di archiviazione. -
Type_Modifier
-
Modificatore facoltativo di tipo variabile.
valore Descrizione const Contrassegnare una variabile che non può essere modificata da uno shader, pertanto deve essere inizializzata nella dichiarazione di variabile. Le variabili globali sono considerate const per impostazione predefinita (eliminare questo comportamento fornendo il flag /Gec al compilatore). row_major Contrassegnare una variabile che archivia quattro componenti in una singola riga in modo che possano essere archiviati in un unico registro costante. column_major Contrassegnare una variabile che archivia 4 componenti in una singola colonna per ottimizzare la matematica della matrice. Nota
Se non si specifica un valore modificatore di tipo, il compilatore usa column_major come valore predefinito.
-
Type
-
Qualsiasi tipo HLSL elencato in Tipi di dati (DirectX HLSL).
-
Name[Index]
-
Stringa ASCII che identifica in modo univoco una variabile shader. Per definire una matrice facoltativa, usare l'indice per le dimensioni della matrice, ovvero un numero intero positivo = 1.
-
Semantico
-
Informazioni facoltative sull'utilizzo dei parametri, usate dal compilatore per collegare input e output dello shader. Esistono diverse semantiche predefinite per vertex shader e pixel shader. Il compilatore ignora la semantica a meno che non vengano dichiarati in una variabile globale o un parametro passato in uno shader.
-
Packoffset
-
Parola chiave facoltativa per la compressione manuale delle costanti shader. Vedere packoffset (DirectX HLSL).
-
Registra
-
Parola chiave facoltativa per l'assegnazione manuale di una variabile shader a un particolare registro. Vedere Register (DirectX HLSL).
-
Annotazioni
-
Metadati facoltativi, sotto forma di stringa, collegati a una variabile globale. Un'annotazione viene usata dal framework dell'effetto e ignorata da HLSL; per visualizzare una sintassi più dettagliata, vedere sintassi delle annotazioni.
-
Initial_Value
-
Valori iniziali facoltativi; Il numero di valori deve corrispondere al numero di componenti in Type. Ogni variabile globale contrassegnata con extern deve essere inizializzata con un valore letterale. Ogni variabile contrassegnata come statica deve essere inizializzata con una costante.
Le variabili globali non contrassegnate come statiche o extern non vengono compilate nello shader. Il compilatore non imposta automaticamente i valori predefiniti per le variabili globali e non può usarli nelle ottimizzazioni. Per inizializzare questo tipo di variabile globale, usare reflection per ottenere il relativo valore e quindi copiare il valore in un buffer costante. Ad esempio, è possibile usare il metodo ID3D11ShaderReflection::GetVariableByName per ottenere la variabile, usare il metodo ID3D11ShaderReflectionVariable::GetDesc per ottenere la descrizione della variabile shader e ottenere il valore iniziale dal membro DefaultValue della struttura D3D11_SHADER_VARIABLE_DESC. Per copiare il valore nel buffer costante, è necessario assicurarsi che il buffer sia stato creato con l'accesso in scrittura della CPU (D3D11_CPU_ACCESS_WRITE). Per altre informazioni su come creare un buffer costante, vedere Procedura: Creare un buffer costante.
È anche possibile usare il framework degli effetti per elaborare automaticamente la reflection e l'impostazione del valore iniziale. Ad esempio, è possibile usare il metodo ID3DX11EffectPass::Apply.
Importante
Il supporto per questa funzionalità è stato rimosso in Direct3D 12, inclusa la possibilità di riflettere gli inizializzatori predefiniti.
Esempi
Ecco alcuni esempi di dichiarazioni di variabili shader.
float fVar;
float4 color;
int iVar[3];
uniform float4 position : SV_POSITION;
//Default initializers; supported up to Direct3D 11.
float fVar = 3.1f;
int iVar[3] = {1,2,3};
const float4 lightDirection = {0,0,1};
Gruppo condiviso
HLSL consente ai thread di un compute shader di scambiare valori tramite memoria condivisa. HLSL fornisce primitive di barriera come GroupMemoryBarrierWithGroupSync e così via per garantire l'ordinamento corretto di letture e scritture nella memoria condivisa nello shader e per evitare race dei dati.
Nota
L'hardware esegue thread in gruppi (distorsioni o fronti d'onda) e la sincronizzazione delle barriere può talvolta essere omessa per migliorare le prestazioni quando solo la sincronizzazione dei thread appartenenti allo stesso gruppo è corretta. Ma sconsigliamo vivamente questa omissione per questi motivi:
- Questa omissione comporta codice non portabile, che potrebbe non funzionare su alcuni hardware e non funziona su rasterizzatori software che in genere eseguono thread in gruppi più piccoli.
- I miglioramenti delle prestazioni che è possibile ottenere con questa omissione saranno minori rispetto all'uso della barriera all-thread.
In Direct3D 10 non è presente alcuna sincronizzazione dei thread durante la scrittura in groupshared, quindi ciò significa che ogni thread è limitato a una singola posizione in una matrice per la scrittura. Usare il valore di sistema SV_GroupIndex per indicizzare in questa matrice durante la scrittura per assicurarsi che nessun thread possa entrare in conflitto. In termini di lettura, tutti i thread hanno accesso all'intera matrice per la lettura.
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();
...
}
Imballaggio
Comprimere sottocomponenti di vettori e scalari le cui dimensioni sono sufficienti per impedire l'attraversamento dei limiti del registro. Ad esempio, questi sono tutti validi:
cbuffer MyBuffer
{
float4 Element1 : packoffset(c0);
float1 Element2 : packoffset(c1);
float1 Element3 : packoffset(c1.y);
}
Non è possibile combinare tipi di imballaggio.
Come la parola chiave register, un packoffset può essere specifico. La compressione del sottocomponente è disponibile solo con la parola chiave packoffset, non la parola chiave register. All'interno di una dichiarazione cbuffer, la parola chiave register viene ignorata per le destinazioni Direct3D 10 perché si presuppone che sia per la compatibilità multipiattaforma.
Gli elementi compressi possono sovrapporsi e il compilatore non restituirà alcun errore o avviso. In questo esempio Element2 ed Element3 si sovrappongono con Element1.x ed Element1.y.
cbuffer MyBuffer
{
float4 Element1 : packoffset(c0);
float1 Element2 : packoffset(c0);
float1 Element3 : packoffset(c0.y);
}
Un esempio che usa packoffset è: esempio HLSLWithoutFX10.