셰이더 상수(HLSL)
셰이더 모델 4에서 셰이더 상수는 메모리의 하나 이상의 버퍼 리소스에 저장됩니다. 상수 버퍼(cbuffers)와 텍스처 버퍼(tbuffers)의 두 가지 형식의 버퍼로 구성될 수 있습니다. 상수 버퍼는 액세스 대기 시간이 짧고 CPU에서 더 자주 업데이트되는 상수-변수 사용에 최적화되어 있습니다. 이러한 이유로 추가 크기, 레이아웃 및 액세스 제한이 이러한 리소스에 적용됩니다. 텍스처 버퍼는 텍스처처럼 액세스되며 임의로 인덱싱된 데이터에 대해 더 잘 수행됩니다. 사용하는 리소스 형식에 관계없이 애플리케이션에서 만들 수 있는 상수 버퍼 또는 텍스처 버퍼의 수에는 제한이 없습니다.
상수 버퍼 또는 텍스처 버퍼를 선언하는 것은 레지스터를 수동으로 할당하거나 데이터를 압축하기 위한 register 및 packoffset 키워드가 추가된 C의 구조체 선언과 매우 유사합니다.
BufferType 이름 [: register(b#)] { VariableDeclaration [: packoffset(c#.xyzw)]; ... };
매개 변수
-
BufferType
-
[in] 버퍼 형식입니다.
BufferType 설명 cbuffer 상수 버퍼 tbuffer 텍스처 버퍼 -
이름
-
[in] 고유한 버퍼 이름을 포함하는 ASCII 문자열입니다.
-
register(b#)
-
[in] 상수 데이터를 수동으로 압축하는 데 사용되는 선택적 키워드입니다. 상수는 시작 레지스터가 레지스터 번호(#)로 제공되는 상수 버퍼의 레지스터에만 압축될 수 있습니다.
-
VariableDeclaration
-
[in] 구조체 멤버 선언과 유사한 변수 선언입니다. 이는 모든 HLSL 형식 또는 효과 개체일 수 있습니다(텍스처 또는 샘플러 개체 제외).
-
packoffset(c#.xyzw)
-
[in] 상수 데이터를 수동으로 압축하는 데 사용되는 선택적 키워드입니다. 상수는 레지스터 번호가 (#)로 제공되는 모든 상수 버퍼에 압축될 수 있습니다. 하위 성분 압축(xyzw swizzling 사용)은 크기가 단일 레지스터 내에 맞는(레지스터 경계를 넘지 않음) 상수에 사용할 수 있습니다. 예를 들어, float4는 4-성분 레지스터에 맞지 않기 때문에 y 성분으로 시작하는 단일 레지스터에 압축할 수 없습니다.
설명
상수 버퍼는 각각의 셰이더 상수를 개별적으로 호출해 개별적으로 커밋하지 않고 그룹화하여 동시에 커밋할 수 있도록 함으로써 셰이더 상수 업데이트에 필요한 대역폭을 줄입니다.
상수 버퍼는 버퍼처럼 액세스되는 특수 버퍼 리소스입니다. 각 상수 버퍼는 최대 4096개의 벡터를 보유할 수 있습니다. 각 벡터에는 최대 4개의 32비트 값이 포함됩니다. 파이프라인 단계당 최대 14개의 상수 버퍼를 바인딩할 수 있습니다(2개의 추가 슬롯은 내부용으로 예약됨).
텍스처 버퍼는 텍스처처럼 액세스되는 특수 버퍼 리소스입니다. 텍스처 액세스(버퍼 액세스와 비교할 때)는 임의로 인덱싱된 데이터에 대해 더 나은 성능을 가질 수 있습니다. 파이프라인 단계당 최대 128개의 텍스처 버퍼를 바인딩할 수 있습니다.
버퍼 리소스는 셰이더 상수 설정의 오버헤드를 최소화하도록 설계되었습니다. 효과 프레임워크(ID3D10Effect 인터페이스 참조)는 업데이트 상수 및 텍스처 버퍼를 관리하거나 Direct3D API를 사용하여 버퍼를 업데이트할 수 있습니다(리소스 데이터 복사 및 액세스(Direct3D 참조) 10) 참조). 애플리케이션은 다른 버퍼(예: 렌더링 대상 또는 스트림 출력 대상)에서 상수 버퍼로 데이터를 복사할 수도 있습니다.
D3D10 애플리케이션에서 상수 버퍼 사용에 대한 자세한 내용은 리소스 종류(Direct3D 10) 및 버퍼 리소스 만들기(Direct3D 10)를 참조하세요.
D3D11 애플리케이션에서 상수 버퍼 사용에 대한 자세한 내용은 Direct3D 11의 버퍼 소개 및 방법: 상수 버퍼 만들기를 참조하세요.
상수 버퍼는 뷰가 파이프라인에 바인딩될 필요가 없습니다. 그러나 텍스처 버퍼에는 뷰가 필요하고 텍스처 슬롯에 바인딩되어야 합니다(또는 효과를 사용할 때 SetTextureBuffer로 바인딩되어야 함).
상수 데이터를 압축하는 방법에는 register(DirectX HLSL) 및 packoffset(DirectX HLSL) 키워드를 사용하는 두 가지 방법이 있습니다.
Direct3D 9와 Direct3D 10 및 11의 차이점:
- 압축을 수행하지 않고 각 변수를 float4 레지스터 집합에 할당하는 Direct3D 9의 상수 자동 할당과 달리 HLSL 상수 변수는 Direct3D 10 및 11의 압축 규칙을 따릅니다.
상수 버퍼 구성
상수 버퍼는 각각의 셰이더 상수를 개별적으로 호출해 개별적으로 커밋하지 않고 그룹화하여 동시에 커밋할 수 있도록 함으로써 셰이더 상수 업데이트에 필요한 대역폭을 줄입니다.
상수 버퍼를 효율적으로 사용하는 가장 좋은 방법은 해당 업데이트 빈도에 따라 상수 버퍼에 셰이더 변수를 구성하는 것입니다. 이를 통해 애플리케이션은 셰이더 상수를 업데이트하는 데 필요한 대역폭을 최소화할 수 있습니다. 예를 들어, 셰이더는 두 개의 상수 버퍼를 선언하고 업데이트 빈도에 따라 각각의 데이터를 구성할 수 있습니다. 개체별로 업데이트해야 하는 데이터(예: 월드 행렬)는 상수 버퍼로 그룹화되며 각 개체에 대해 업데이트됩니다. 이는 장면을 특징짓는 데이터와 별개이므로(장면이 변경될 때) 훨씬 덜 자주 업데이트될 가능성이 높습니다.
cbuffer myObject
{
float4x4 matWorld;
float3 vObjectPosition;
int arrayIndex;
}
cbuffer myScene
{
float3 vSunPosition;
float4x4 matView;
}
기본 상수 버퍼
$Global 및 $Param의 두 가지 기본 상수 버퍼를 사용할 수 있습니다. 전역 범위에 있는 변수는 cbuffer에 사용되는 것과 동일한 압축 방법을 사용하여 암시적으로 $Global cbuffer에 추가됩니다. 함수의 매개 변수 목록에 있는 Uniform 매개 변수는 효과 프레임워크 외부에서 셰이더를 컴파일할 때 $Param 상수 버퍼에 나타납니다. 효과 프레임워크 내에서 컴파일될 때 모든 uniform은 전역 범위에 정의된 변수로 해석되어야 합니다.
예시
다음은 행렬 배열로 구성된 텍스처 버퍼인 Skinning10 Sample의 예입니다.
tbuffer tbAnimMatrices
{
matrix g_mTexBoneWorld[MAX_BONE_MATRICES];
};
이 예 선언은 특정 레지스터에서 시작하도록 상수 버퍼를 수동으로 할당하고 하위 성분별로 특정 요소를 압축합니다.
cbuffer MyBuffer : register(b3)
{
float4 Element1 : packoffset(c0);
float1 Element2 : packoffset(c1);
float1 Element3 : packoffset(c1.y);
}