Reglas de empaquetado para variables constantes

Las reglas de empaquetado dictan cómo se pueden organizar los datos estrictamente cuando se almacenan. HLSL implementa reglas de empaquetado para los datos de salida de VS, los datos de entrada y salida de GS, y los datos de entrada y salida de PS. (Los datos no están empaquetados para las entradas de VS porque la fase de IA no puede desempaquetar datos).

Las reglas de empaquetado de HLSL son similares a realizar un paquete de #pragma 4 con Visual Studio, que empaqueta los datos en límites de 4 bytes. Además, HLSL empaqueta los datos para que no cruce un límite de 16 bytes. Las variables se empaquetan en un vector de cuatro componentes determinado hasta que la variable se sitúe en un límite de 4 vectores; Las siguientes variables se devolverán al siguiente vector de cuatro componentes.

Cada estructura obliga a la siguiente variable a iniciarse en el siguiente vector de cuatro componentes. Esto a veces genera relleno para matrices de estructuras. El tamaño resultante de cualquier estructura siempre será divisible por sizeof(vector de cuatro componentes).

Las matrices no se empaquetan en HLSL de manera predeterminada. Para evitar forzar el sombreador a asumir la sobrecarga de ALU para los cálculos de desplazamiento, cada elemento de una matriz se almacena en un vector de cuatro componentes. Tenga en cuenta que puede lograr el empaquetado de matrices (y incurrir en los cálculos de direccionamiento) mediante la conversión.

A continuación se muestran ejemplos de estructuras y sus tamaños empaquetados correspondientes (dados: un float1 ocupa 4 bytes):

//  2 x 16byte elements
cbuffer IE
{
    float4 Val1;
    float2 Val2;  // starts a new vector
    float2 Val3;
};

//  3 x 16byte elements
cbuffer IE
{
    float2 Val1;
    float4 Val2;  // starts a new vector
    float2 Val3;  // starts a new vector
};

//  1 x 16byte elements
cbuffer IE
{
    float1 Val1;
    float1 Val2;
    float2 Val3;
};

//  1 x 16byte elements
cbuffer IE
{
    float1 Val1;
    float2 Val2;
    float1 Val3;
};

//  2 x 16byte elements
cbuffer IE
{
    float1 Val1;
    float1 Val1;
    float1 Val1;
    float2 Val2;    // starts a new vector
};


//  1 x 16byte elements
cbuffer IE
{
    float3 Val1;
    float1 Val2;
};

//  1 x 16byte elements
cbuffer IE
{
    float1 Val1;
    float3 Val2;
};

//  2 x 16byte elements
cbuffer IE
{
    float1 Val1;
    float1 Val1;
    float3 Val2;        // starts a new vector
};


// 3 x 16byte elements
cbuffer IE
{
    float1 Val1;

    struct     {
        float4 SVal1;    // starts a new vector
        float1 SVal2;    // starts a new vector
    } Val2;
};

// 3 x 16byte elements
cbuffer IE
{
    float1 Val1;  
    struct     {
        float1 SVal1;     // starts a new vector
        float4 SVal2;     // starts a new vector
    } Val2;
};

// 3 x 16byte elements
cbuffer IE
{
    struct     {
        float4 SVal1;
        float1 SVal2;    // starts a new vector
    } Val1;

    float1 Val2; 
};

Empaquetado más agresivo

Puede empaquetar una matriz de forma más agresiva; este es un ejemplo. Supongamos que desea acceder a una matriz como esta desde el búfer de constantes:

// Original array: not efficiently packed.
float2 myArray[32];

En el búfer de constantes, la declaración anterior consumirá 32 vectores de 4 elementos. Esto se debe a que cada elemento de matriz se colocará al principio de uno de estos vectores. Ahora, si desea que estos valores se empaquetan estrechamente (sin espacios) en el búfer de constantes y quiera acceder a la matriz en el sombreador como una matrizfloat2[32], puede escribir esto en su lugar:

float4 packedArrayInCBuffer[16];
// shader uses myArray here:
static const float2 myArray[32] = (float2[32])packedArrayInCBuffer;

El empaquetado más ajustado es un equilibrio frente a la necesidad de instrucciones adicionales del sombreador para el cálculo de direcciones.