HLSL

4. 함수

Awesome Red Tomato 2021. 12. 24. 14:38

1. 사용자 정의 함수

HLSL 함수의 특징이다.

1. 익숙한 C++의 함수 구문을 사용한다.

2. 매개변수는 항상 값으로 전달된다.

3. 재귀를 지원하지 않는다.

4. 항상 인라인화된다.

// in: 입력용 변수 out: 출력용 변수 inout: 입출력용 변수
bool foo(in const bool b, out int r1, inout float r2)
{
	if(b)
	{
		r1 = 5; // r1을 통해 하나의 값을 출력한다.
	}
	else
	{
		r1 = 1; // r1을 통해 하나의 값을 출력한다.
	}

	// r2는 inout이므로 입력 값이 될 수도 출력 값이 될 수도 있다.
	r2 = r2 * r2 * r2;

	return true;
}

 

 

2. 내장 함수

https://docs.microsoft.com/ko-kr/windows/win32/direct3dhlsl/dx-graphics-hlsl-intrinsic-functions

 

내장 함수 - Win32 apps

다음 표에서는 HLSL에서 사용할 수 있는 내재 함수를 나열합니다. 각 함수에는 간단한 설명과 입력 인수 및 반환 형식에 대한 자세한 내용이 있는 참조 페이지에 대한 링크가 있습니다.

docs.microsoft.com

 

 

3.  상수 버퍼의 압축 및 채움

HLSL에서 상수 버퍼의 요소들을 4차원 벡터 단위로 저장하는데, 이 때 HLSL은 하나의 요소가 두 4차원 벡터에 걸쳐서 저장되어서는 안된다는 규칙을 강제한다.

// HLSL
cbuffer cb : register(b0)
{
	float3 Pos;
	float3 Dir;
};

 

이 자료를 순서대로 4차원 벡터 단위로 저장한다면 다음과 같은 형태가 될 것이다.

벡터 1: (Pos.x, Pos.y, Pos.z, Dir.x)

벡터 2: (Dir.y, Dir.z, 빈칸, 빈칸)

 

이렇게 하면 dir요소가 두 4차원 벡터에 걸치게 되는데, 이는 한 요소가 두 벡터에 걸쳐지면 안된다는 HLSL의 규칙을 위반하는 것이다. 이를 방지하기 위해, HLSL은 셰이더 메모리 안에서 다음과 같이 빈칸들을 채워 넣는다.

벡터 1: (Pos.x, Pos.y, Pos.z, 빈칸)

벡터 2: (Dir.x, Dir.y, Dir.z, 빈칸)

 

 

만약 이 상수 버퍼에 대응되는 C++ 구조체가 다음과 같이 정의되어 있다고 하자.

// C++
struct Data
{
	XMFLOAT3 Pos;
	XMFLOAT3 Dir;
};

 

만약 앞의 규칙을 간과하고 무작정 memcpy를 해버리면 셰이더가 잘못된 상수 값을 사용하게 되어버린다. 제대로 HLSL 상수 버퍼에 복사되게 하려면 C++ 구조체를 다시 정의해야 한다. 우선, 채움 필드들의 존재를 명시적으로 해준다.

cbuffer cb : register(b0)
{
	float3 Pos;
	float __pad0;
	float3 Dir;
	float __pad1;
};

 

C++ 구조체도 동일하게 해준다.

// C++
struct Data
{
	XMFLOAT3 Pos;
	float __pad0;
	XMFLOAT3 Dir;
	float __pad1;
};

 

이제 memcpy를 수행하면 제대로 복사된다.