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.