변수 구문
다음 구문 규칙을 사용하여 HLSL 변수를 선언합니다.
[Storage_Class] [Type_Modifier] Type Name[Index] [: Semantic] [: Packoffset] [: Register]; [Annotations] [= Initial_Value]
매개 변수
-
Storage_Class
-
변수 범위 및 수명에 대한 컴파일러 힌트를 제공하는 선택적 스토리지 클래스 한정자. 한정자는 임의의 순서로 지정할 수 있습니다.
값 설명 extern 셰이더에 대한 외부 입력으로 전역 변수를 표시합니다. 이는 모든 전역 변수에 대한 기본 표시입니다. static과 결합할 수 없습니다. nointerpolation 꼭짓점 셰이더의 출력을 픽셀 셰이더에 전달하기 전에 보간하지 마세요. precise 변수에 적용할 때 정확한 키워드는 다음과 같은 방법으로 해당 변수에 할당된 값을 생성하는 데 사용되는 계산을 제한합니다. - 별도의 작업은 별도로 유지됩니다. 예를 들어, mul 및 add 작업이 mad 작업으로 융합되었을 수 있는 경우 precise는 작업을 분리된 상태로 유지합니다. 대신 미친 내장 함수를 명시적으로 사용해야 합니다.
- 작업 순서가 유지됩니다. 성능 향상을 위해 명령 순서가 순서를 섞었을 수 있는 경우 컴파일러가 작성된 순서를 유지하도록 정확하게 확인합니다.
- IEEE 안전하지 않은 작업이 제한됩니다. 컴파일러가 NaN(숫자가 아님) 및 INF(무한) 값을 고려하지 않는 빠른 수학 연산을 사용했을 수 있는 경우 precise는 NaN 및 INF 값과 관련된 IEEE 요구 사항을 준수하도록 강제합니다. 정확하지 않으면 이러한 최적화 및 수학 연산은 IEEE로부터 안전하지 않습니다.
- 변수를 정밀하게 한정해도 변수를 정확하게 사용하는 작업은 수행되지 않습니다. 정밀한 값이 정확한 정규화된 변수에 할당된 값에만 전파되기 때문에 원하는 계산을 정확하게 만드는 것은 까다로울 수 있으므로 셰이더 출력을 구조 필드 또는 출력 매개 변수 또는 항목 함수의 반환 형식에 관계없이 선언하는 위치에 직접 정확하게 표시하는 것이 좋습니다. 이러한 방식으로 최적화를 제어하는 기능은 누적된 정밀도 차이로 인해 최종 결과에 영향을 줄 수 있는 최적화를 사용하지 않도록 설정하여 수정된 출력 변수에 대한 결과 차이를 유지합니다. 테셀레이션을 위한 셰이더가 수밀 패치 이음새를 유지하거나 여러 패스에 대한 깊이 값을 일치시킬 때 유용합니다. 샘플 코드:
HLSLmatrix g_mWorldViewProjection;
void main(in float3 InPos : Position, out precise float4 OutPos : SV_Position)
{
작업은 정확한 매개 변수 OutPos에 기여하기 때문에 정확합니다.
OutPos = mul( float4( InPos, 1.0 ), g_mWorldViewProjection );
}
shared 효과 간에 공유할 변수를 표시합니다. 이는 컴파일러에 대한 힌트입니다. groupshared 컴퓨팅 셰이더의 스레드 그룹 공유 메모리에 대한 변수를 표시합니다. D3D10에서 그룹 공유 스토리지 클래스가 있는 모든 변수의 최대 총 크기는 16kb이고 D3D11에서 최대 크기는 32kb입니다. 예를 참조하세요. static 한 번 초기화되고 함수 호출 간에 지속되도록 지역 변수를 표시합니다. 선언에 이니셜라이저가 포함되어 있지 않으면 값이 0으로 설정됩니다. static으로 표시된 전역 변수는 애플리케이션에 표시되지 않습니다. uniform 셰이더 실행 내내 데이터가 일정한 변수(예: 꼭짓점 셰이더의 재료 색)를 표시합니다. 전역 변수는 기본적으로 균일한 것으로 간주됩니다. volatile 자주 변경되는 변수를 표시합니다. 이는 컴파일러에 대한 힌트입니다. 이 스토리지 클래스 한정자는 지역 변수에만 적용됩니다.
참고: HLSL 컴파일러는 현재 이 스토리지 클래스 한정자를 무시합니다. -
Type_Modifier
-
선택적 변수 유형 한정자입니다.
값 설명 const 셰이더에서 변경할 수 없는 변수를 표시하므로 변수 선언에서 초기화해야 합니다. 전역 변수는 기본적으로 const로 간주됩니다(컴파일러에 /Gec 플래그를 제공하여 이 동작을 억제함). row_major 단일 상수 레지스터에 저장할 수 있도록 단일 행에 4개의 성분을 저장하는 변수를 표시합니다. column_major 행렬 수학을 최적화하기 위해 단일 열에 4개의 성분을 저장하는 변수를 표시합니다. 참고 항목
형식 한정자 값을 지정하지 않으면 컴파일러는 column_major 기본값으로 사용합니다.
-
Type
-
데이터 형식(DirectX HLSL)에 나열된 모든 HLSL 형식입니다.
-
Name[Index]
-
셰이더 변수를 고유하게 식별하는 ASCII 문자열입니다. 선택적 배열을 정의하려면 양의 정수 = 1인 배열 크기에 대해 index를 사용합니다.
-
Semantic
-
셰이더 입력과 출력을 연결하기 위해 컴파일러에서 사용하는 선택적 매개 변수 사용 정보입니다. 꼭짓점 셰이더 및 픽셀 셰이더에 대해 여러 미리 정의된 의미 체계가 있습니다. 컴파일러는 전역 변수 또는 셰이더에 전달된 매개 변수에 대해 선언되지 않은 의미 체계를 무시합니다.
-
Packoffset
-
셰이더 상수를 수동으로 압축하기 위한 선택적 키워드입니다. packoffset(DirectX HLSL)를 참조하세요.
-
Register
-
셰이더 변수를 특정 레지스터에 수동으로 할당하기 위한 선택적 키워드입니다. register(DirectX HLSL)를 참조하세요.
-
Annotation(s)
-
전역 변수에 연결된 문자열 형식의 선택적 메타데이터입니다. 주석은 효과 프레임워크에서 사용되며 HLSL에서는 무시됩니다. 자세한 구문을 보려면 주석 구문을 참조하세요.
-
Initial_Value
-
선택적 초기값 값의 수는 형식의 성분 수와 일치해야 합니다. extern으로 표시된 각 전역 변수는 리터럴 값으로 초기화되어야 합니다. static으로 표시된 각 변수는 상수로 초기화해야 합니다.
static 또는 extern으로 표시되지 않은 전역 변수는 셰이더로 컴파일되지 않습니다. 컴파일러는 전역 변수의 기본값을 자동으로 설정하지 않으며 최적화에 사용할 수 없습니다. 이 형식의 전역 변수를 초기화하려면 리플렉션을 사용하여 해당 값을 가져온 다음 값을 상수 버퍼에 복사합니다. 예를 들어, ID3D11ShaderReflection::GetVariableByName 메서드를 사용하여 변수를 가져오고 ID3D11ShaderReflectionVariable::GetDesc 메서드를 사용하여 셰이더 변수 설명을 가져오고, D3D11_SHADER_VARIABLE_DESC 구조체의 DefaultValue 멤버에서 초기 값을 가져옵니다. 상수 버퍼에 값을 복사하려면 버퍼가 CPU 쓰기 권한(D3D11_CPU_ACCESS_WRITE)으로 만들어졌는지 확인해야 합니다. 상수 버퍼를 만드는 방법에 대한 자세한 내용은 방법: 상수 버퍼 만들기를 참조하세요.
또한 효과 프레임워크를 사용하여 초기값 반영 및 설정을 자동으로 처리할 수 있습니다. 예를 들어, ID3DX11EffectPass::Apply 메서드를 사용할 수 있습니다.
Important
이 기능에 대한 지원은 기본 이니셜라이저를 반영하는 기능을 포함하여 Direct3D 12에서 제거되었습니다.
예제
다음은 셰이더 변수 선언의 몇 가지 예입니다.
float fVar;
float4 color;
int iVar[3];
uniform float4 position : SV_POSITION;
//Default initializers; supported up to Direct3D 11.
float fVar = 3.1f;
int iVar[3] = {1,2,3};
const float4 lightDirection = {0,0,1};
그룹 공유
HLSL을 사용하면 컴퓨팅 셰이더의 스레드가 공유 메모리를 통해 값을 교환할 수 있습니다. HLSL은 GroupMemoryBarrierWithGroupSync 등과 같은 장벽 기본 형식을 제공하여 셰이더의 공유 메모리에 대한 올바른 읽기 및 쓰기 순서를 보장하고 데이터 경합을 방지합니다.
참고
하드웨어는 그룹(워프 또는 웨이브 프런트)에서 스레드를 실행하며, 동일한 그룹에 속하는 스레드 동기화만 올바른 경우 성능 향상을 위해 경우에 따라 장벽 동기화를 생략할 수 있습니다. 그러나 다음과 같은 이유로 이러한 누락을 권장하지 않습니다.
- 이 누락으로 인해 일부 하드웨어에서 작동하지 않을 수 있고 일반적으로 더 작은 그룹에서 스레드를 실행하는 소프트웨어 래스터라이저에서 작동하지 않는 이식 불가능한 코드가 생성됩니다.
- 이 생략으로 달성할 수 있는 성능 개선은 모든 스레드 장벽을 사용하는 것과 비교할 때 미미합니다.
Direct3D 10에서는 그룹 공유에 쓸 때 스레드 동기화가 없으므로 각 스레드는 쓰기를 위해 배열의 단일 위치로 제한됩니다. 두 개의 스레드가 충돌하지 않도록 작성 시 SV_GroupIndex 시스템 값을 사용하여 이 배열에 인덱스를 생성합니다. 읽기 측면에서 모든 스레드는 읽기를 위해 전체 배열에 액세스할 수 있습니다.
struct GSData
{
float4 Color;
float Factor;
}
groupshared GSData data[5*5*1];
[numthreads(5,5,1)]
void main( uint index : SV_GroupIndex )
{
data[index].Color = (float4)0;
data[index].Factor = 2.0f;
GroupMemoryBarrierWithGroupSync();
...
}
패킹
레지스터 경계를 넘지 않도록 크기가 충분히 큰 벡터 및 스칼라의 하위 성분을 압축합니다. 예를 들어, 다음은 모두 유효합니다.
cbuffer MyBuffer
{
float4 Element1 : packoffset(c0);
float1 Element2 : packoffset(c1);
float1 Element3 : packoffset(c1.y);
}
패킹 유형을 혼합할 수 없습니다.
register 키워드와 마찬가지로 packoffset은 특정 대상일 수 있습니다. 하위 성분 압축은 register 키워드가 아닌 packoffset 키워드로만 사용할 수 있습니다. cbuffer 선언 내에서 register 키워드는 플랫폼 간 호환성을 위한 것으로 간주되므로 Direct3D 10 대상에 대해 무시됩니다.
압축된 요소가 겹칠 수 있으며 컴파일러에서 오류나 경고를 표시하지 않습니다. 이 예에서 Element2 및 Element3은 Element1.x 및 Element1.y와 겹칩니다.
cbuffer MyBuffer
{
float4 Element1 : packoffset(c0);
float1 Element2 : packoffset(c0);
float1 Element3 : packoffset(c0.y);
}
packoffset을 사용하는 샘플은 HLSLWithoutFX10 샘플입니다.