Share via


封裝常數變數的規則

封裝規則會決定儲存數據時可以排列得有多緊。 HLSL 會實作 VS 輸出資料的封裝規則、GS 輸入和輸出數據,以及 PS 輸入和輸出數據。 (因為 IA 階段無法解除封裝數據,所以不會封裝 VS 輸入的數據。

HLSL 封裝規則類似於使用 Visual Studio 執行 #pragma 套件 4 ,以將數據封裝成 4 位元組界限。 此外,HLSL 會封裝數據,使其不會跨越16位元組界限。 變數會封裝成指定的四個元件向量,直到變數跨越4向量界限為止:下一個變數將會反彈至下一個四元件向量。

每個結構都會強制下一個變數在下一個四元件向量上啟動。 這有時會產生結構的陣列填補。 任何結構的產生大小一律會依 sizeof四個元件向量)平均地分割。

數位預設不會封裝在 HLSL 中。 為了避免強制著色器對位移計算產生 ALU 額外負荷,陣列中的每個元素都會儲存在四個元件向量中。 請注意,您可以使用轉換來達成數位的封裝(併產生尋址計算)。

以下是結構及其對應封裝大小的範例(給定: 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;

更緊密的封裝是取捨與地址計算的其他著色器指示的需求。