Share via


Packregeln für Konstantenvariablen

Die Packregeln geben vor, wie eng die Daten beim Speichern angeordnet werden können. HLSL implementiert Packregeln für VS-Ausgabedaten, GS-Eingabe- und Ausgabedaten sowie PS-Eingabe- und Ausgabedaten. (Daten werden für VS-Eingaben nicht gepackt, da die IA-Stufe die Daten nicht entpacken kann.)

HLSL-Packregeln ähneln dem Ausführen eines #pragma Pack 4 mit Visual Studio, das Daten in 4-Byte-Begrenzungen packt. Außerdem packt HLSL die Daten so, dass sie eine 16-Byte-Grenze nicht überschreiten. Variablen werden in einen bestimmten Vektor mit vier Komponenten gepackt, bis die Variable eine 4-Vektor-Grenze überspannt. Die nächsten Variablen werden zum nächsten Vektor mit vier Komponenten zurückgesprungen.

Jede Struktur erzwingt die nächste Variable für den nächsten Vektor mit vier Komponenten. Dies generiert manchmal Abstände für Arrays von Strukturen. Die resultierende Größe jeder Struktur wird immer gleichmäßig durch sizeof(Vier-Komponenten-Vektor) teilbar sein.

Arrays werden in HLSL standardmäßig nicht gepackt. Um zu vermeiden, dass der Shader den ALU-Aufwand für Offset-Berechnungen übernimmt, wird jedes Element in einem Array in einem Vektor mit vier Komponenten gespeichert. Beachten Sie, dass Sie das Packen von Arrays (und die damit verbundenen Adressierungsberechnungen) durch Umwandlung erreichen können.

Im Folgenden finden Sie Beispiele für Strukturen und ihre entsprechenden gepackten Größen (angegeben: ein float1 belegt 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; 
};

Aggressiveres Packen

Sie können ein Array aggressiver packen. Hier ist ein Beispiel. Nehmen wir an, Sie möchten vom konstanten Puffer aus auf ein Array wie dieses zugreifen:

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

Im Konstantenpuffer verbraucht die obige Deklaration 32 4-Elementvektoren. Das liegt daran, dass jedes Arrayelement am Anfang eines dieser Vektoren platziert wird. Wenn Sie diese Werte eng gepackt (ohne Leerzeichen) im Konstantenpuffer haben wollen und trotzdem auf das Array im Shader als float2[32]-Array zugreifen wollen, können Sie stattdessen Folgendes schreiben:

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

Die engere Packung ist ein Kompromiss gegenüber dem Bedarf an zusätzlichen Shader-Anweisungen für die Adressberechnung.