Règles d’empaquetage de variables constantes

Les règles d’empaquetage déterminent la façon dont les données peuvent être étroitement organisées lorsqu’elles sont stockées. HLSL implémente des règles d’empaquetage pour les données de sortie VS, les données d’entrée et de sortie GS, ainsi que les données d’entrée et de sortie PS. (Les données des entrées VS ne sont pas empaquetées, car la phase IA ne peut pas les dépaqueter.)

Les règles d’empaquetage HLSL sont similaires à l’exécution d’une #pragma pack 4 avec Visual Studio, qui empaquette les données dans des limites de 4 octets. En outre, HLSL empaquette les données sans dépasser une limite de 16 octets. Les variables sont empaquetées dans un vecteur à quatre composants donné jusqu’à ce que la variable chevauche une délimitation à 4 vecteurs. Les variables suivantes sont renvoyées au vecteur à quatre composants suivant.

Chaque structure force la variable suivante à démarrer sur le vecteur à quatre composants suivant. Cela génère parfois un remplissage des tableaux de structures. La taille résultante de la structure sera toujours divisible en parts égales par sizeof(vecteur à quatre composants).

Par défaut, les tableaux ne sont pas empaquetés dans HLSL. Pour éviter de forcer le nuanceur à assumer la surcharge ALU des calculs de décalage, chaque élément d’un tableau est stocké dans un vecteur à quatre composants. Notez que vous pouvez effectuer un empaquetage des tableaux (et entraîner les calculs d’adressage) à l’aide d’un cast.

Voici des exemples de structures et leurs tailles empaquetées correspondantes (sachant qu’un float1 occupe 4 octets) :

//  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; 
};

Empaquetage plus agressif

Vous pouvez empaqueter un tableau de façon plus agressive. En voici un exemple. Supposons que vous souhaitez accéder à un tableau comme celui-ci à partir de la mémoire tampon constante :

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

Dans la mémoire tampon constante, la déclaration ci-dessus utilise 32 vecteurs à 4 éléments. Chaque élément du tableau est placé au début de l’un de ces vecteurs. Maintenant, si vous souhaitez que ces valeurs soient étroitement empaquetées (sans espaces) dans la mémoire tampon constante, et si vous souhaitez accéder au tableau dans le nuanceur en tant que tableau float2[32], vous pouvez écrire ceci à la place :

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

L’empaquetage plus étroit est un compromis par rapport à la nécessité d’instructions de nuanceur supplémentaires pour le calcul de l’adresse.