Syntaxe de variable
Utilisez les règles de syntaxe suivantes pour déclarer des variables HLSL.
[Storage_Class] [Type_Modifier] Type Name[Index] [: Semantic] [: Packoffset] [: Register]; [Annotations] [= Initial_Value]
Paramètres
-
Storage_Class
-
Modificateurs de classe de stockage facultatifs qui donnent au compilateur des indications sur l’étendue et la durée de vie des variables ; les modificateurs peuvent être spécifiés dans n’importe quel ordre.
Valeur Description extern Marque une variable globale comme entrée externe au nuanceur ; il s’agit du marquage par défaut pour toutes les variables globales. On ne peut pas le combiner avec static. nointerpolation N’interpole pas les sorties d’un nuanceur de vertex avant de les transmettre à un nuanceur de pixels. precise Le mot clé precise, lorsqu’il est appliqué à une variable, restreint tous les calculs utilisés pour générer la valeur assignée à cette variable des manières suivantes : - Les opérations distinctes sont conservées séparément. Par exemple, alors que des opérations mul et add auraient pu être fusionnées dans une opération mad, précise force les opérations à rester séparées. Au lieu de cela, vous devez utiliser explicitement la fonction intrinsèque mad.
- L’ordre des opérations est conservé. Lorsque l’ordre des instructions aurait pu être modifié pour améliorer les performances, precise garantit que le compilateur préserve l’ordre tel qu’il a été écrit.
- Les opérations non sécurisées IEEE sont restreintes. Là où le compilateur aurait pu utiliser des opérations mathématiques rapides qui ne tiennent pas compte des valeurs NaN (pas un nombre) et INF (infini), precise oblige à respecter les exigences IEEE concernant les valeurs NaN et INF. Sans precise, ces optimisations et opérations mathématiques ne sont pas sécurisées pour IEEE.
- Qualifier une variable precise n’effectuer pas d’opérations qui utilisent la variable precise. Étant donné que precise se propage uniquement aux opérations qui contribuent aux valeurs affectées à la variable qualifiée precise, il peut s’avérer difficile de faire en sorte que les calculs souhaités soient precise. Nous recommandons donc de marquer les sorties du nuanceur comme precise directement là où vous les déclarez, qu’il s’agisse d’un champ de structure ou d’un paramètre de sortie, ou du type de renvoi de la fonction d’entrée. La possibilité de contrôler les optimisations de cette manière permet de maintenir l’invariabilité des résultats pour la variable de sortie modifiée en désactivant les optimisations qui pourraient affecter les résultats finaux en raison des différences de précision accumulées. Cela s’avère utile lorsque vous souhaitez que les nuanceurs de pavage conservent des coutures de patch étanches ou correspondent aux valeurs de profondeur sur plusieurs passes. Exemple de code :
HLSLmatrix g_mWorldViewProjection;
void main(in float3 InPos : Position, out precise float4 OutPos : SV_Position)
{
// operation is precise because it contributes to the precise parameter OutPos
OutPos = mul( float4( InPos, 1.0 ), g_mWorldViewProjection );
}
shared Marque une variable pour la partager entre les effets. Il s’agit d’une indication pour le compilateur. groupshared Marque une variable pour la mémoire partagée par les groupes de threads pour les nuanceurs de calcul. Dans D3D10, la taille totale maximale de toutes les variables avec la classe de stockage groupshared est de 16 ko, dans D3D11, la taille maximale est de 32 Ko. Consultez les exemples. static Marque une variable locale de manière à ce qu’elle soit initialisée une seule fois et qu’elle persiste entre les appels de fonction. Si la déclaration n’inclut pas d’initialiseur, la valeur est définie sur zéro. Une variable globale marquée static n’est pas visible pour une application. uniforme Marque une variable dont les données sont constantes tout au long de l’exécution d’un nuanceur (par exemple, une couleur de matériau dans un nuanceur de vertex) ; les variables globales sont considérées comme uniformes par défaut. volatile Marque une variable qui change fréquemment ; il s’agit d’une indication pour le compilateur. Ce modificateur de classe de stockage s’applique uniquement à une variable locale.
Remarque : le compilateur HLSL ignore actuellement ce modificateur de classe de stockage. -
Type_Modifier
-
Modificateur de type variable facultatif.
Valeur Description const Marque une variable qui ne peut pas être modifiée par un nuanceur, par conséquent, elle doit être initialisée dans la déclaration de variable. Les variables globales sont considérées comme const par défaut (supprimez ce comportement en fournissant l’indication /Gec au compilateur). row_major Marquez une variable qui stocke quatre composants dans une seule ligne afin qu’ils puissent être stockés dans un seul registre de constante. column_major Marque une variable qui stocke 4 composants dans une seule colonne pour optimiser les mathématiques de matrices. Remarque
Si vous ne spécifiez pas de valeur de modificateur de type, le compilateur utilise column_major comme valeur par défaut.
-
Type
-
Tout type HLSL répertorié dans Types de données (DirectX HLSL).
-
Name[Index]
-
Chaîne ASCII qui identifie de façon unique une variable de nuanceur. Pour définir un tableau facultatif, utilisez index pour la taille du tableau, qui est un entier positif = 1.
-
Semantic
-
Informations facultatives sur l’utilisation des paramètres, utilisées par le compilateur pour lier les entrées et sorties du nuanceur. Il existe plusieurs sémantiques prédéfinies pour les nuanceurs de vertex et de pixels. Le compilateur ignore les sémantiques, sauf si elles sont déclarées sur une variable globale ou un paramètre transmis à un nuanceur.
-
Packoffset
-
Mot clé facultatif pour empaqueter manuellement les constantes du nuanceur. Consulter packoffset (DirectX HLSL).
-
S’inscrire
-
Mot clé facultatif pour affecter manuellement une variable de nuanceur à un registre particulier. Consulter register (DirectX HLSL).
-
Annotation(s)
-
Métadonnées facultatives, sous la forme d’une chaîne, attachées à une variable globale. Une annotation est utilisée par l’infrastructure d’effet et ignorée par HLSL ; pour afficher une syntaxe plus détaillée, consultez la syntaxe annotation.
-
Initial_Value
-
Valeur(s) initiale(s) facultative(s) ; le nombre de valeurs doit correspondre au nombre de composants dans Type. Chaque variable globale marquée extern doit être initialisée avec une valeur littérale ; chaque variable marquée static doit être initialisée avec une constante.
Les variables globales qui ne sont pas marquées static ou extern ne sont pas compilées dans le nuanceur. Le compilateur ne définit pas automatiquement les valeurs par défaut pour les variables globales et ne peut pas les utiliser dans les optimisations. Pour initialiser ce type de variable globale, utilisez la réflexion pour obtenir sa valeur, puis copiez cette dernière dans une mémoire tampon de constantes. Vous pouvez par exemple utiliser la méthode ID3D11ShaderReflection::GetVariableByName pour obtenir la variable, utiliser la méthode ID3D11ShaderReflectionVariable::GetDesc pour obtenir la description de la variable de nuanceur et obtenir la valeur initiale du membre DefaultValue de la structure D3D11_SHADER_VARIABLE_DESC. Pour copier la valeur dans la mémoire tampon de constantes, vous devez vous assurer que la mémoire tampon a été créée avec l’accès en écriture du processeur (D3D11_CPU_ACCESS_WRITE). Pour en savoir plus sur la création d’une mémoire tampon de constantes, consultez Guide pratique pour créer une mémoire tampon de constantes.
Vous pouvez également utiliser l’infrastructure d’effets pour traiter automatiquement la réflexion et définir la valeur initiale. Par exemple, vous pouvez utiliser la méthode ID3DX11EffectPass::Apply.
Important
La prise en charge de cette fonctionnalité a été supprimée dans Direct3D 12, y compris la possibilité de refléter les initialiseurs par défaut.
Exemples
Voici plusieurs exemples de déclarations de variable de nuanceur.
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};
Partagées en groupes
HLSL permet aux threads d’un nuanceur de calcul d’échanger des valeurs via la mémoire partagée. HLSL fournit des primitives de barrière telles que GroupMemoryBarrierWithGroupSync et ainsi de suite pour garantir l’ordre correct des lectures et des écritures dans la mémoire partagée dans le nuanceur et pour éviter les concurrences de données.
Remarque
Le matériel exécute des threads en groupes (warps ou fronts de vagues) et la synchronisation des barrières peut parfois être omise pour augmenter les performances lorsque seule la synchronisation des threads appartenant au même groupe est adéquate. Mais nous déconseillons fortement cette omission pour les raisons suivantes :
- Cette omission génère un code non portable, qui peut ne pas fonctionner sur du matériel et ne fonctionne pas sur des rastériseurs logiciels qui exécutent généralement des threads dans des groupes plus petits.
- Les améliorations de performances que vous pouvez obtenir avec cette omission seront mineures par rapport à l’utilisation de la barrière de tous les threads.
Dans Direct3D 10, il n’existe aucune synchronisation de threads lors de l’écriture dans groupshared, ce qui signifie que chaque thread est limité à un emplacement unique dans un tableau pour l’écriture. Utilisez la valeur système SV_GroupIndex pour indexer dans ce tableau lors de l’écriture pour vous assurer qu’aucun deux threads ne peuvent entrer en conflit. En termes de lecture, tous les threads ont accès à l’ensemble du tableau pour la lecture.
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();
...
}
Emballage
Empaquète des sous-composants de vecteurs et scalaires dont la taille est suffisamment grande pour empêcher le franchissement des limites du registre. Par exemple, les suivants sont tous valides :
cbuffer MyBuffer
{
float4 Element1 : packoffset(c0);
float1 Element2 : packoffset(c1);
float1 Element3 : packoffset(c1.y);
}
On ne peut pas mélanger des types d’empaquètement.
Comme le mot clé register, un packoffset peut être spécifique à la cible. L’empaquètement de sous-composant est disponible uniquement avec le mot clé packoffset, et pas avec le mot clé register. Dans une déclaration cbuffer, le mot clé register est ignoré pour les cibles Direct3D 10, car il est supposé être compatible entre plateformes.
Les éléments empaquetés peuvent se chevaucher et le compilateur ne génère aucune erreur ou avertissement. Dans cet exemple, Element2 et Element3 se chevauchent avec Element1.x et Element1.y.
cbuffer MyBuffer
{
float4 Element1 : packoffset(c0);
float1 Element2 : packoffset(c0);
float1 Element3 : packoffset(c0.y);
}
Un exemple qui utilise packoffset est : HLSLWithoutFX10 Sample.