Sintaxis de variables

Use las siguientes reglas de sintaxis para declarar variables HLSL.

[Storage_Class] [Type_Modifier] Type Name[Index] [: Semantic] [: Packoffset] [: Register]; [Anotaciones] [= Initial_Value]

Parámetros

Storage_Class

Modificadores opcionales de clase de almacenamiento que proporcionan sugerencias del compilador sobre el ámbito y la duración de las variables; los modificadores se pueden especificar en cualquier orden.

Valor Descripción
extern Marcar una variable global como entrada externa para el sombreador; este es el marcado predeterminado para todas las variables globales. No se puede combinar con static.
nointerpolation No interpole las salidas de un sombreador de vértices antes de pasarlas a un sombreador de píxeles.
Precisa La palabra clave precisa cuando se aplica a una variable restringirá los cálculos usados para generar el valor asignado a esa variable de las maneras siguientes:
  • Las operaciones independientes se mantienen separadas. Por ejemplo, cuando una operación de suma y mul podría haberse fusionado en una operación loca, las operaciones precisas obligan a que las operaciones permanezcan separadas. En su lugar, debe usar explícitamente la función intrínseca loca.
  • Se mantiene el orden de las operaciones. Cuando el orden de las instrucciones se haya ordenado aleatoriamente para mejorar el rendimiento, garantiza con precisión que el compilador conserva el orden tal como se escribe.
  • Las operaciones no seguras de IEEE están restringidas. Cuando el compilador podría haber usado operaciones matemáticas rápidas que no tienen en cuenta los valores NaN (no un número) y INF (infinito), obliga a respetar los requisitos de IEEE relativos a los valores NaN e INF. Sin precisión, estas optimizaciones y operaciones matemáticas no son seguras para IEEE.
  • Calificar una variable precisa no realiza operaciones que usan la variable precisa. Dado que precisa se propaga solo a las operaciones que contribuyen a los valores asignados a la variable precisa, hacer correctamente los cálculos deseados precisos puede ser complicado, por lo que se recomienda marcar las salidas del sombreador exactamente donde se declaran, ya sea en un campo de estructura, en un parámetro de salida o en el tipo de valor devuelto de la función de entrada. La capacidad de controlar las optimizaciones de esta manera mantiene la invariable de resultados para la variable de salida modificada deshabilitando las optimizaciones que podrían afectar a los resultados finales debido a las diferencias de precisión acumuladas. Resulta útil cuando se quieren sombreadores para la teselación mantener costuras de parches apretados o coincidir los valores de profundidad en varios pasos. Código de ejemplo:
    HLSLmatrix g_mWorldViewProjection;
    void main(in float3 InPos : Position, out precise float4 OutPos : SV_Position)
    {
    la operación es precisa porque contribuye al parámetro preciso OutPos
    OutPos = mul( float4( InPos, 1.0 ), g_mWorldViewProjection );
    }
shared Marcar una variable para compartir entre efectos; se trata de una sugerencia para el compilador.
groupshared Marque una variable para la memoria compartida de grupo de subprocesos para los sombreadores de proceso. En D3D10, el tamaño total máximo de todas las variables con la clase de almacenamiento compartido de grupo es de 16 kb, en D3D11 el tamaño máximo es de 32 kb. Vea ejemplos.
static Marque una variable local para que se inicialice una vez y persista entre las llamadas de función. Si la declaración no incluye un inicializador, el valor se establece en cero. Una variable global marcada como estática no es visible para una aplicación.
Uniforme Marcar una variable cuyos datos son constantes durante la ejecución de un sombreador (como un color de material en un sombreador de vértices); Las variables globales se consideran uniformes de forma predeterminada.
volatile Marcar una variable que cambia con frecuencia; se trata de una sugerencia para el compilador. Este modificador de clase de almacenamiento solo se aplica a una variable local.
Nota: Actualmente, el compilador HLSL omite este modificador de clase de almacenamiento.

Type_Modifier

Modificador de tipo variable opcional.

Valor Descripción
const Marque una variable que no puede cambiar un sombreador, por lo tanto, debe inicializarse en la declaración de variable. Las variables globales se consideran const de forma predeterminada (suprimen este comportamiento proporcionando la marca /Gec al compilador).
row_major Marque una variable que almacena cuatro componentes en una sola fila para que se puedan almacenar en un único registro de constantes.
column_major Marque una variable que almacena 4 componentes en una sola columna para optimizar las matemáticas de matriz.

Nota

Si no especifica un valor modificador de tipo, el compilador usa column_major como valor predeterminado.

Tipo

Cualquier tipo HLSL que aparezca en Tipos de datos (DirectX HLSL) .

Name[Index]

Cadena ASCII que identifica de forma única una variable de sombreador. Para definir una matriz opcional, use el índice para el tamaño de la matriz, que es un entero positivo = 1.

Semántica

Información opcional sobre el uso de parámetros, utilizada por el compilador para vincular las entradas y salidas del sombreador. Hay varias semánticas predefinidas para sombreadores de vértices y píxeles. El compilador omite la semántica a menos que se declaren en una variable global o un parámetro pasado a un sombreador.

Packoffset

Palabra clave opcional para empaquetar manualmente constantes de sombreador. Consulta packoffset (DirectX HLSL).

Registro

Palabra clave opcional para asignar manualmente una variable de sombreador a un registro determinado. Consulte register (DirectX HLSL) (Registro [HLSL]).

Anotaciones

Metadatos opcionales, en forma de cadena, adjuntados a una variable global. El marco de efecto utiliza una anotación y se omite por HLSL; para ver una sintaxis más detallada, consulte la sintaxis de anotación.

Initial_Value

Valores iniciales opcionales; el número de valores debe coincidir con el número de componentes de Type. Cada variable global marcada como extern debe inicializarse con un valor literal; cada variable marcada como estática debe inicializarse con una constante.

Las variables globales que no están marcadas como estáticas o extern no se compilan en el sombreador. El compilador no establece automáticamente valores predeterminados para variables globales y no los puede usar en optimizaciones. Para inicializar este tipo de variable global, use la reflexión para obtener su valor y, a continuación, copie el valor en un búfer de constantes. Por ejemplo, puede usar el método ID3D11ShaderReflection::GetVariableByName para obtener la variable, use el método ID3D11ShaderReflectionVariable::GetDesc para obtener la descripción de la variable de sombreador y obtener el valor inicial del miembro DefaultValue de la estructura D3D11_SHADER_VARIABLE_DESC . Para copiar el valor en el búfer de constantes, debe asegurarse de que el búfer se creó con acceso de escritura de CPU (D3D11_CPU_ACCESS_WRITE). Para obtener más información sobre cómo crear un búfer de constantes, vea Cómo: Crear un búfer de constantes.

También puede usar el marco de efectos para procesar automáticamente el reflejo y establecer el valor inicial. Por ejemplo, puede usar el método ID3DX11EffectPass::Apply .

Ejemplos

Estos son varios ejemplos de declaraciones de variable de sombreador.

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};
      

Grupo compartido

HLSL permite que los subprocesos de un sombreador de proceso intercambie valores a través de la memoria compartida. HLSL proporciona primitivos de barrera, como GroupMemoryBarrierWithGroupSync, etc. para garantizar el orden correcto de lecturas y escrituras en memoria compartida en el sombreador y para evitar razas de datos.

Nota

El hardware ejecuta subprocesos en grupos (warps o frentes de onda) y a veces se puede omitir la sincronización de barreras para aumentar el rendimiento cuando solo se sincronizan subprocesos que pertenecen al mismo grupo es correcto. Pero desaconsejamos esta omisión por estas razones:

  • Esta omisión produce código no portátil, que podría no funcionar en algún hardware y no funciona en rasterizadores de software que normalmente ejecutan subprocesos en grupos más pequeños.
  • Las mejoras de rendimiento que puede lograr con esta omisión serán menores en comparación con el uso de la barrera de todos los subprocesos.

En Direct3D 10 no hay sincronización de subprocesos al escribir en grupo compartido, por lo que esto significa que cada subproceso está limitado a una sola ubicación en una matriz para escribir. Use el valor del sistema SV_GroupIndex para indexar en esta matriz al escribir para asegurarse de que no pueden colisionar dos subprocesos. En términos de lectura, todos los subprocesos tienen acceso a toda la matriz para su lectura.

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();
    ...
}

Embalaje

Empaqueta los subcomponentes de vectores y escalares cuyo tamaño es lo suficientemente grande como para evitar cruzar los límites del registro. Por ejemplo, todos son válidos:

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

No se pueden mezclar tipos de empaquetado.

Al igual que la palabra clave register, un packoffset puede ser específico de destino. El empaquetado de subcomponentes solo está disponible con la palabra clave packoffset, no con la palabra clave register. Dentro de una declaración cbuffer, la palabra clave register se omite para destinos de Direct3D 10, ya que se supone que es para la compatibilidad multiplataforma.

Los elementos empaquetados se pueden superponer y el compilador no dará ningún error o advertencia. En este ejemplo, Element2 y Element3 se superponerán con Element1.x y Element1.y.

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

Un ejemplo que usa packoffset es: HLSLWithoutFX10 Sample.

Variables (DirectX HLSL)