Regras de empacotamento para variáveis constantes

As regras de empacotamento ditam quão firmemente os dados podem ser organizados quando são armazenados. A HLSL implementa regras de empacotamento para dados de saída do VS, dados de entrada e saída do GS e dados de entrada e saída do PS. (Os dados não são empacotados para entradas do VS porque o estágio de IA não pode desempacotar os dados.)

As regras de empacotamento da HLSL são semelhantes à execução de um #pragma pack 4 com o Visual Studio, que empacota os dados com limites de 4 bytes. Além disso, a HLSL empacota os dados para que não ultrapassem o limite de 16 bytes. As variáveis são empacotadas em um determinado vetor de quatro componentes até que a variável tenha um limite de 4 vetores; as próximas variáveis serão transferidas para o próximo vetor de quatro componentes.

Cada estrutura força a próxima variável a iniciar no próximo vetor de quatro componentes. Às vezes, isso gera preenchimento de matrizes de estruturas. O tamanho resultante de qualquer estrutura será sempre divisível por sizeof(vetor de quatro componentes).

As matrizes não são empacotadas em HLSL por padrão. Para evitar forçar o sombreador a assumir a sobrecarga da ALU para cálculos de deslocamento, cada elemento em uma matriz é armazenado em um vetor de quatro componentes. Observe que você pode obter empacotamento de matrizes (e incorrer em cálculos de endereçamento) usando a conversão.

A seguir estão exemplos de estruturas e seus tamanhos empacotados correspondentes (dados: um 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; 
};

Empacotamento mais agressivo

Você pode empacotar uma matriz de forma mais agressiva; aqui está um exemplo. Digamos que você queira acessar uma matriz como esta a partir do buffer constante:

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

No buffer constante, a declaração acima consumirá 32 vetores de 4 elementos. Isso ocorre porque cada elemento de matriz será colocado no início de um desses vetores. Agora, se você quiser que esses valores sejam bem empacotados (sem espaços) no buffer constante e ainda queira acessar uma matriz no sombreador como uma matriz float2[32], você pode escrever isto:

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

O empacotamento mais compacto é uma compensação em relação a necessidade de instruções adicionais do sombreador para computação de endereço.