상수 변수에 대한 압축 규칙
압축 규칙은 데이터를 저장할 때 얼마나 긴밀하게 정렬할 수 있는지를 결정합니다. HLSL은 VS 출력 데이터, GS 입력 및 출력 데이터, PS 입력 및 출력 데이터에 대한 압축 규칙을 구현합니다. (IA 단계에서는 데이터 압축을 풀 수 없으므로 VS 입력에 대해 데이터가 압축되지 않습니다.)
HLSL 패킹 규칙은 데이터를 4 바이트 경계로 압축하는 Visual Studio에서 #pragma 팩 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;
더 촘촘한 배열은 주소 계산을 위한 추가 셰이더 명령의 필요성과의 균형입니다.