定数変数のパッキング 規則
パッキング ルールは、格納時にデータをどの程度厳密に配置できるかを決定します。 HLSL は、VS 出力データ、GS 入出力データ、および PS 入出力データのパッキング規則を実装します。 (IA ステージではデータをアンパックできないため、データは VS 入力用にパックされません)。
HLSL パッキング規則は、データを 4 バイト境界にパックする Visual Studio で #pragma パック 4 を実行するのと似ています。 さらに、HLSL は 16 バイト境界を越えないようにデータをパックします。 変数は、変数が 4 ベクトル境界にまたがるまで、指定された 4 成分ベクトルにパックされます。次の変数は、次の 4 成分ベクトルにバウンスされます。
各構造体は、次の 4 成分ベクトルで次の変数を強制的に開始します。 これにより、構造体の配列のパディングが生成されることがあります。 結果として得られる構造体のサイズは、常に sizeof(4 成分ベクトル) によって均等に割り切れます。
配列は、既定では HLSL にパックされません。 オフセット計算でシェーダーが ALU オーバーヘッドを引き受けるのを避けるために、配列内のすべての要素が 4 要素ベクトルに格納されます。 キャストを使用すると、配列のパッキング (およびアドレス指定計算が発生します) を実現できることに注意してください。
構造体とそれに対応するパックされたサイズの例を次に示します (指定すると、float1 は 4 バイトを占有します)。
// 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;
};
より積極的な梱包
配列をより積極的にパックできます。例を次に示します。 定数バッファーから次のような配列にアクセスするとします。
// Original array: not efficiently packed.
float2 myArray[32];
定数バッファーでは、上記の宣言は 32 個の 4 要素ベクトルを使用します。 これは、各配列要素がこれらのベクトルの先頭に配置されるためです。 ここで、これらの値を定数バッファーに (スペースなしで) 密にパックし、シェーダー内の配列に float2[32]
配列としてアクセスする場合は、代わりに次のように記述できます。
float4 packedArrayInCBuffer[16];
// shader uses myArray here:
static const float2 myArray[32] = (float2[32])packedArrayInCBuffer;
より厳密なパッキングは、アドレス計算のための追加のシェーダー命令の必要性に対するトレードオフです。