Stacky_
매일 쌓이는 기록
HLSL 기초 본문
개요
- HLSL은 GPU에서 실행되는 언어로, C/C++과 매우 닮았다.
- 정확히는 CPU에서 컴파일되어 바이너리 코드를 GPU로 넘겨주면, GPU에서 실행된다.
- 이때, 컴파일은 빌드 시에 한번 그리고 런타임 중에 동적으로 파일이 변경되면 그때마다 한 번씩 컴파일된다.
HLSL의 변수
- HLSL의 변수는 3가지의 종류로 나뉜다
- 스칼라 변수
- 벡터 변수
- 행렬 변수
- 스칼라 변수는 C/C++에서 보는 그런 변수들과 동일하다.
- HLSL에서는
bool
,int
,uint
,half
,float
를 사용할 수 있다. - 벡터 변수는 배열처럼 float이 1~4개로 이어져 있는 형태의 변수이다.
- 보통 스칼라 변수 키워드 바로 뒤에 숫자를 붙여 표현한다.
float4 color; // [r, g, b, a]
- 행렬 변수는 이차원 배열처럼 float이 1~16개로 이어져 있는 형태의 변수이다.
- 스칼라 변수 키워드 바로 뒤에 "숫자x숫자"를 붙여 표현한다.
float4x4 matrix;
/* [ a, b, c, d ]
* [ e, f, g, h ]
* [ i, j, k, l ]
* [ m, n, o, p ]
*/
의미론 / 의미체계(semantics)
- 의미론은 GPU가 데이터를 어떤 의미가 있는지 명시해 주는 것을 의미한다.
- 만일 아래와 같은 코드가 있다고 해보자.
struct VOut
{
float4 position;
float4 color;
};
VOut VShader(float4 position, float4 color)
{
VOut output;
output.position = position;
output.color = color;
return output;
}
- 이 코드에서, 우리가 보기에는 큰 문제가 없다.
- 위치값과 색상값을 가져와서 구조체에 집어넣는 형식이고, 이를 통해 GPU에 전달하는 것이다.
- 그런데 GPU의 입장에서는 동일한 벡터 변수 두 개가 전부인 데이터이다.
struct
{
float4, float4
};
- 결국 GPU는 위치값과 색상값을 가지고 처리해야 하는데, 무엇이 위치값이고 색상값인지 GPU로서는 알 길이 없다.
- 따라서, GPU에게 명시적으로 각 변수의 의미를 알려줄 필요가 있다.
struct VOut
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
VOut VShader(float4 position : POSITION, float4 color : COLOR)
{
VOut output;
output.position = position;
output.color = color;
return output;
}
의미체계의 종류
- 의미체계는 DirectX9 이상에서 사용되는 의미체계와 DirectX10 이상에서 사용되는 의미체계로 나뉜다.
struct VOut
{
float4 position : SV_POSITION; // DirectX10이상 의미체계
float4 color : COLOR; // DirectX9이상 의미체계
};
VOut VShader(float4 position : POSITION, float4 color : COLOR)
{
VOut output;
output.position = position;
output.color = color;
return output;
}
- 보통 DirectX10 이상에서 사용되는 의미체계는
SV_
라는 접두사가 붙고, 입력 레이아웃을 통해 등록할 필요가 없다. - 반면, DirectX9 이상에서 사용되는 의미체계는
SV_
접두사를 붙이지도 않고, A입력 레이아웃을 통해 반드시 등록해야 한다.
D3D11_INPUT_ELEMENT_DESC ied[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
};
- 이는 역사적인 이유로 인해 나누어졌다.
- DirectX9 이전에는 렌더링 파이프라인이 고정 기능 파이프라인(Fixed-Function Pipeline)이었다.
- 즉, 렌더링 파이프라인이 이미 만들어져 있는 기다란 파이프였고, 여기에 개발자가 만질 수 있는 것은 파이프에 있는 밸브들 몇 가지(실제로는 Vertex Shader와 Pixel Shader)였다.
- 그러나 DirectX10으로 넘어오면서, 더 이상 고정이 아닌 개발자들이 마음대로 이 파이프들을 다른 것으로 교체하는 것이 가능해졌다.
- 문제는 여기서 발생하는데, 바로 통일된 의미론이 없다는 것이다.
- 각 파이프 - 정확히는 셰이더들이 데이터를 해석할 때 제각각으로 해석할 여지가 커지고 이렇게 되면 데이터의 흐름자체가 꼬이게 되고, 처리가 제대로 이루어질 수 없다.
- 때문에, 기존에는 프로그래머가 마음대로 지정했던 의미론을 하나의 시스템 값으로 고정해서 사용하도록 한 것이다.
- 그래서 DirectX10 이상의 의미론에서는 접미사
SV_
가 붙는다.
DirectX9에서는 정말 프로그래머 마음대로 의미론을 바꿀 수 있었나?
- 결론부터 말하면, 그렇지 않지만 그렇다고
SV_
처럼 시스템 값에 등록되어 있지는 않았다.- DirectX9 보다 훨씬 이전에는 정말 프로그래머 마음대로 의미론을 지정했었다.
- 하지만, 시간이 지나면서 프로그래머 사이들에서
POSITION
이나COLOR
같은 값이 관습처럼 사용되었다.- 그러면서 GPU 드라이버 개발자들도 이에 맞춰서 개발하면서 어쩌다 보니 마치 시스템 값처럼 사용하게 된 것이다.
- 따라서 만일
POSITION
이나COLOR
대신 다른 것들을 등록하면 GPU 드라이버가 인식을 하지 못해 제대로 동작하지 않는다.
참고한 자료
'Game > Graphics' 카테고리의 다른 글
Visual Studio에서 DirectX Tool Kit 라이브러리 적용 (0) | 2025.06.10 |
---|---|
Input Assembler(IA) (0) | 2025.06.05 |