DirectX12 디버깅을 하다가 '비트 필드' 라는 개념을 몰라서 버그가 났던 것을 깨달아서 이 글을 쓴다.
c++는 c언어의 특성을 이어받는 언어라고 할 수 있다. 비트 필드또한 그렇다. 형태는 다음과 같다.
typedef struct D3D12_RAYTRACING_INSTANCE_DESC
{
FLOAT Transform[ 3 ][ 4 ];
UINT InstanceID : 24;
UINT InstanceMask : 8;
UINT InstanceContributionToHitGroupIndex : 24;
UINT Flags : 8;
D3D12_GPU_VIRTUAL_ADDRESS AccelerationStructure;
} D3D12_RAYTRACING_INSTANCE_DESC;
UINT(int의 typedef꼴)는 운영체제 별로 다르지만 보통 4byte(32bit)의 크기를 가지는 type이다. 하지만, 구조체 내에서 위 예와 같이 (: 24) 같이 비트 크기를 따로 할당하게 되면, 해당 item은 구조체 내에서 프로그래머가 지정한 만큼의 크기를 가진다. 구조체 비트 필드 문법을 통해서 구조체 크기의 최적화가 가능한 것이다.
나는 저 : 24라는 문법을 거짓말 안하고 코딩하면서 처음봤다.. 그리고 그 의미를
UINT InstanceContributionToHitGroupIndex : 24 //-->아 기본값이 24구나!
라고 해석하는 짓을 저질러 버렸다.. 그리고, 습관처럼 구조체의 모든 멤버를 초기화하며 24의 값을 줘버렸다.
그 결과 단 1개의 HitGroup을 가지는 내 DXR렌더러는 검은 삼각형만을 출력하는 결과가 나왔다. 이제 다시는 헷갈리지 않을 개념이다.
솔직히 정말 흔하지 않은 문법이다. DirectX12 API에서도 특히 D3D12_RAYTRACING_INSTANCE_DESC같은 녀석들만 비트 필드 문법을 사용한다.
왜 마소 개발자가 이런짓을 했을까 생각을 해봤는데, 이 구조체의 특징은 CPU의 구조체를 GPU메모리에 그대로 올리는 구조체라는 것이다. 즉, GPU메모리의 데이터 형식에 딱 맞게 memcopy연산을 하기 위해 이런 짓을 한것 아닐까? 라는 추측을 해본다..