定数変数のパッキング規則

パッキング規則は、格納時にデータをどの程度緊密に配置できるかを指定します。 HLSL は、VS の出力データ、GS の入出力データ、PS の入出力データに関するパッキング規則を実装します。 (IA ステージではデータをアンパックできないため、データは VS 入力についてはパックされません。)

HLSL パッキング規則は、データを 4 バイト境界にパックする Visual Studio での #pragma pack 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;

より緊密にパックすると、それと引き換えに、アドレス計算のための追加のシェーダー命令が必要になります。