HLSL
HLSL 은 그래픽 카드에서 도는 프로그램을 적는 언어입니다. C 를 닮은 문법으로 셰이더를 씁니다. 컴파일해서 그래픽 파이프라인의 정해진 자리에 꽂습니다. DirectX 9 와 함께 나왔습니다.
상세
Microsoft 의 Win32 문서는 HLSL(High Level Shader Language, 고수준 셰이더 언어)을 DirectX 의 프로그래머블 셰이더에 쓰는 C 를 닮은 고수준 셰이더 언어라고 적습니다. 정점 셰이더나 픽셀 셰이더를 HLSL 로 써서 Direct3D 애플리케이션 렌더러 구현에 쓸 수 있습니다. 물리 시뮬레이션 같은 것을 구현하려고 컴퓨트 셰이더를 쓸 수도 있습니다. 같은 문서는 HLSL 이 프로그래머블 3D 파이프라인을 세우려고 DirectX 9 부터 만들어졌다고 적습니다. 파이프라인 전체를 HLSL 명령으로 프로그램할 수 있다고도 적습니다.
셰이더 단계
데이터는 프리미티브의 스트림으로 그래픽 파이프라인에 들어옵니다. 그것을 처리하는 쪽이 셰이더 단계입니다. 실제 셰이더 단계는 Direct3D 판에 따라 다릅니다. 다만 정점 단계와 픽셀 단계, 지오메트리 단계는 확실히 포함된다고 프로그래밍 가이드가 적습니다. 테셀레이션용 헐 셰이더와 도메인 셰이더, 그리고 컴퓨트 셰이더도 단계에 들어갑니다. 이 단계들은 HLSL 로 완전히 프로그래밍할 수 있습니다.
HLSL 셰이더는 저작 시점에 컴파일할 수 있습니다. 실행 시점에 컴파일할 수도 있습니다. 컴파일된 셰이더는 실행 시점에 알맞은 파이프라인 단계로 설정됩니다.
flowchart TD
A["HLSL 소스"] --> B["컴파일 · 저작 시점 또는 실행 시점"]
B --> C["셰이더 바이너리"]
C --> D["실행 시점에 파이프라인 단계로 설정"]
셰이더 모델과 프로파일
DirectX 용 고수준 셰이딩 언어는 일련의 셰이더 모델을 구현합니다. 각 셰이더 모델은 앞선 모델의 능력 위에 쌓입니다. 제약은 줄이면서 기능은 더 구현합니다. 그래서 셰이더 모델 번호가 HLSL 로 무엇을 쓸 수 있는지를 가릅니다.
셰이더 프로파일은 셰이더를 컴파일하는 대상입니다. 셰이더 모델마다 지원하는 프로파일 목록이 따로 정해져 있습니다.
| 셰이더 모델 | 프로파일 |
|---|---|
| 셰이더 모델 1 | vs_1_1 |
| 셰이더 모델 2 | ps_2_0 · ps_2_x · vs_2_0 · vs_2_x · ps_4_0_level_9_0 · ps_4_0_level_9_1 · ps_4_0_level_9_3 · vs_4_0_level_9_0 · vs_4_0_level_9_1 · vs_4_0_level_9_3 · lib_4_0_level_9_1 · lib_4_0_level_9_3 |
| 셰이더 모델 3 | ps_3_0 · vs_3_0 |
| 셰이더 모델 4 | cs_4_0 · gs_4_0 · ps_4_0 · vs_4_0 · cs_4_1 · gs_4_1 · ps_4_1 · vs_4_1 · lib_4_0 · lib_4_1 |
| 셰이더 모델 5 | cs_5_0 · ds_5_0 · gs_5_0 · hs_5_0 · ps_5_0 · vs_5_0 · lib_5_0 |
| 셰이더 모델 6 | cs_6_0 · ds_6_0 · gs_6_0 · hs_6_0 · ps_6_0 · vs_6_0 · lib_6_0 |
어느 셰이더 모델로 셰이더를 설계할 수 있는지는 Direct3D 판이 정합니다.
| Direct3D | 설계할 수 있는 셰이더 모델 |
|---|---|
| Direct3D 9 | 셰이더 모델 1 · 2 · 3 |
| Direct3D 10 | 셰이더 모델 4 |
| Direct3D 11 | 셰이더 모델 5 |
| Direct3D 11.3 · Direct3D 12 | 셰이더 모델 5.1 |
| Direct3D 12 | 셰이더 모델 6 |
포기한 것
인라인으로 고정된 함수
HLSL 의 함수 선언에는 storageclass 수식자가 붙습니다. 지금 이 수식자에 넣을 수 있는 값은
inline 하나뿐입니다. 게다가 그 값이 기본값입니다. inline 을 적든 안 적든 함수는
인라인입니다. 레퍼런스는 HLSL 의 모든 함수가 인라인이라고 못 박습니다.
인라인 함수는 컴파일할 때 호출마다 함수 본문의 사본을 하나씩 만들어 냅니다. 문서가 그 이유로 드는 것은 함수 호출의 오버헤드를 줄이는 것입니다. 얻은 것이 그것이라면, 내준 것은 선택지입니다. 함수 하나를 한 벌만 두고 여러 자리에서 부르는 형태를 고를 수 없습니다.
셰이더 모델이 그어 놓은 선
셰이더 모델은 판마다 쓸 수 있는 것이 다릅니다. 뒤 모델일수록 제약이 줄고 기능이 늡니다. 뒤집으면 앞 모델에는 그만큼 못 하는 자리가 있다는 뜻입니다.
Windows Vista 부터 들어온 셰이더 모델 4 는 완전한 재설계였습니다. 명령과 상수의 개수 제한이 사라졌습니다. 다만 그 무제한은 기계의 하드웨어 제약 안에서입니다. 그리고 셰이더 모델 4 는 Windows Driver Model 을 요구합니다. 그 드라이버 모델은 Windows Vista 이상 운영체제에서만 쓸 수 있습니다. 기능을 연 값으로 운영체제 하한선을 받은 셈입니다.
고르는 폭도 좁습니다. Direct3D 10 셰이더는 셰이더 모델 4 로만 설계할 수 있습니다. 판과 모델이 이렇게 묶여 있어서 쓰는 쪽이 셰이더 모델을 자유롭게 고르지 못합니다.
DirectX Shader Compiler 저장소는 dxc.exe 를 셰이더 모델 6.0 이상의 HLSL 프로그램을
컴파일하는 명령줄 도구라고 적습니다.
Direct3D 를 겨냥한 출력
HLSL 은 프로그래머블 3D 파이프라인을 세우려고 만들어졌습니다. 컴파일 결과가 향하는 곳도 그쪽이 먼저입니다. DirectX Shader Compiler 는 HLSL 프로그램을 DirectX 용 DXIL(DirectX Intermediate Language, 다이렉트X 중간 언어)로 컴파일합니다. Vulkan 용 SPIR-V(Standard Portable Intermediate Representation, 표준 이식 중간 표현)도 낼 수 있습니다.
두 갈래가 저장소 문서에 소개되는 자리는 다릅니다. 저장소는 SPIR-V 를 겨냥하는 기능을
커뮤니티 기여의 사례로 소개합니다. 프로젝트 위키는 SPIR-V CodeGen 이 이제 어지간히 여물었다고 적습니다.
못 박은 말이 아니라 mature-ish 라는 표현입니다. Direct3D 밖으로 나가는 길은 언어가 아니라
컴파일러의 백엔드가 냅니다.
이 컴파일러 자체는 LLVM 과 Clang 프로젝트를 포크한 것에서 출발했습니다. 고친 자리는 둘입니다. 하나는 HLSL 을 받아들이는 것입니다. 다른 하나는 GPU(Graphics Processing Unit, 그래픽 처리 장치) 드라이버가 소비할 수 있는 검증된 셰이더 바이너리를 내는 것입니다.
예시
시맨틱이 붙은 셰이더 함수
레퍼런스가 BasicHLSL10 샘플의 BasicHLSL10.fx 에서 가져온 예제입니다.
struct VS_OUTPUT
{
float4 Position : SV_POSITION;
float4 Diffuse : COLOR0;
float2 TextureUV : TEXCOORD0;
};
VS_OUTPUT RenderSceneVS( float4 vPos : POSITION,
float3 vNormal : NORMAL,
float2 vTexCoord0 : TEXCOORD,
uniform int nNumLights,
uniform bool bTexture,
uniform bool bAnimate )
{
VS_OUTPUT Output;
...
return Output;
}
구조체 멤버 셋에는 콜론 뒤에 이름이 하나씩 붙어 있습니다. 함수 인자는 여섯 개 가운데 셋에만
붙었습니다. uniform 이 앞에 선 나머지 셋에는 콜론이 없습니다. SV_POSITION · COLOR0 ·
TEXCOORD0 · POSITION · NORMAL · TEXCOORD 가 붙은 이름입니다. 반환 타입에도 같은 표기를
붙일 수 있습니다. AdvancedParticles 샘플에서 가져온 아래 예제가 반환 타입에 시맨틱을 쓴
경우입니다.
// PS for particles
float4 PSPointSprite(PSSceneIn input) : SV_Target
{
return g_txDiffuse.Sample( g_samLinear, input.tex ) * input.color;
}
이쪽 인자 input 에는 콜론이 없습니다. 시맨틱이 붙은 자리는 반환 타입의 SV_Target 하나입니다.
dxc 명령 한 줄
DirectX Shader Compiler 위키가 적어 둔 호출입니다.
dxc -E main -T ps_6_0 -Fo myshader.bin -Zi -Fd myshader.pdb -D MYDEFINE=1 myshader.hlsl
마지막 인자 myshader.hlsl 이 입력 소스 파일입니다. -T 뒤에 붙은 ps_6_0 은 셰이더 모델 6
의 프로파일 목록에 들어 있는 이름입니다. 프로파일은 셰이더를 컴파일하는 대상이라고 레퍼런스가
적습니다. 같은 소스라도 이 한 자리를 바꾸면 다른 셰이더 모델을 겨냥하게 됩니다.
사용처
Direct3D 12 애플리케이션. Direct3D 11.3 과 Direct3D 12 셰이더는 셰이더 모델 5.1 로 설계할 수 있습니다. Direct3D 12 는 셰이더 모델 6 으로도 설계할 수 있습니다. 프로그래머블 3D 파이프라인을 HLSL 명령으로 프로그램하는 자리가 여기입니다. 파이프라인 전체를 HLSL 명령으로 프로그램할 수 있다고 Win32 문서가 적습니다. 그것이 이 자리에서 HLSL 을 쓰는 이유입니다.
Unity 의 ShaderLab 셰이더. Unity 공식 문서는 커스텀 ShaderLab 셰이더의 Pass 블록 안에 HLSL
정점 셰이더 프로그램과 프래그먼트 셰이더 프로그램을 적으라고 안내합니다. Pass 에 셰이더
프로그램을 더하는 자리에는 HLSLPROGRAM 지시자를 씁니다. 셰이더 프로그램을 적을 언어로 Unity
가 안내하는 것이 HLSL 입니다.
Vulkan 을 쓰는 애플리케이션. DirectX Shader Compiler 가 HLSL 을 SPIR-V 로 내립니다. DirectX 나 Vulkan 을 그래픽·게임·연산에 쓰는 애플리케이션이 이 도구로 셰이더 프로그램 바이너리를 만들 수 있다고 저장소 README 가 적습니다. Vulkan 쪽이 HLSL 을 고를 수 있는 것은 이 출력 때문입니다.
관련 항목
HLSL로 프로그래밍하는 셰이더 단계
정점 셰이더 · 픽셀 셰이더 · 프래그먼트 셰이더 · 지오메트리 셰이더 · 헐 셰이더 · 도메인 셰이더 · 컴퓨트 셰이더
그래픽 파이프라인을 이루는 부품
파이프라인 · 셰이더 단계 · 셰이더 · 프리미티브 · 테셀레이션 · 정점
HLSL의 기능을 가르는 버전·환경 조건
셰이더 모델 · 셰이더 프로파일 · DirectX · Direct3D · Windows Driver Model · 운영체제
HLSL을 컴파일하는 도구
DirectX Shader Compiler · dxc · fxc · dxv · 컴파일러
이 컴파일러를 이루는 구성 요소
LLVM · Clang · 어셈블러 · 디스어셈블러 · 검증기 · 백엔드
컴파일해서 내는 산출물
DXIL · SPIR-V · 셰이더 바이너리
이 산출물을 소비하는 대상
HLSL을 실제로 채택한 사례
Unity · ShaderLab
HLSL이 정하는 표기 규칙
시맨틱
HLSL을 정의하는 문서와 주체
Win32 · Microsoft
다른 이름: High Level Shader Language · High-Level Shading Language