다음을 통해 공유


상수 변수에 대한 압축 규칙

압축 규칙은 데이터가 저장될 때 얼마나 긴밀하게 정렬될 수 있는지를 나타냅니다. 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;

더 엄격한 압축은 주소 계산을 위한 추가 셰이더 지침의 필요성과 절충입니다.