포스트

DirecX12 | Lecture 8. Root Signature (인프런)

DirectX12 강의 8. Root Signature를 정리한 글입니다.

DirecX12 | Lecture 8. Root Signature (인프런)

강의 정보 🎓


1. Root Signature 구조 변경

  • 기존: InitAsConstantBufferView()
  • 변경: InitAsDescriptorTable()
1
2
3
std::array<CD3DX12_DESCRIPTOR_RANGE, 1> descriptorRanges = {
    CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, CBV_REGISTER_COUNT, 0)
};
  • 관련 enum 및 상수 정의:
1
2
3
4
enum class CBV_REGISTER_NUMBER {
    b0 = 0, b1, b2, b3, b4, END
};
constexpr UINT CBV_REGISTER_COUNT = static_cast<UINT>(CBV_REGISTER_NUMBER::END);

2. ConstantBuffer 리팩토링

  • CBV용 리소스를 생성하고 디스크립터 힙에 View를 생성한다.
  • 핵심 절차:
    1. D3D12_DESCRIPTOR_HEAP_DESC 설정
    2. 디바이스를 통해 디스크립터 힙 생성
    3. 시작 주소/인크리먼트 저장
    4. View를 다수 생성 (예: 256개 슬롯)
    5. CreateView()Init() 내부에서 호출

3. TableDescriptorHeap 클래스 도입

  • 목적: CBV/SRV/UAV를 테이블 단위로 묶어 관리
  • 주요 기능:
    • Init() : 디스크립터 힙 생성
    • Clear() : 그룹 인덱스 초기화
    • SetCBV() : CPU 핸들을 현재 테이블에 복사
    • CommitTable() : GPU에 테이블 바인딩

📐 디스크립터 힙 구조 예시:

1
2
3
4
5
6
Shader-visible Descriptor Heap
┌────────────────────────────────────┐
│ Group 0: [CBV0][CBV1][CBV2]...     │
│ Group 1: [CBV0][CBV1][CBV2]...     │
│ Group 2: [CBV0][CBV1][CBV2]...     │
└────────────────────────────────────┘

4. 엔진 구조 반영

  • EngineTableDescriptorHeap 추가한다.
  • CommandQueue::RenderBegin()에서:
    • Clear() 호출
    • SetDescriptorHeaps() 호출 (프레임당 1회 권장)
    • SetDescriptorHeaps() 은 1개의 CBV/SRV/UAV 힙 + 1개의 Sampler 힙만 바인딩 가능하다.

5. PushData 흐름 변경

  • PushData()는 이제 D3D12_CPU_DESCRIPTOR_HANDLE을 반환한다.
  • 불필요한SetGraphicsRootConstantBufferView() 를 제거한다.
1
2
3
4
5
6
7
// Mesh.cpp - Render()
D3D12_CPU_DESCRIPTOR_HANDLE handle = constantBuffer->PushData(...);

tableDescriptorHeap->SetCBV(handle, CbvRegisterNumber::b0);
...

tableDescriptorHeap->CommitTable();

이슈 및 트러블슈팅

  • ConstantBuffer::Init()에서 CreateView() 호출을 누락하였다. → 렌더링 오류 발생
  • 이후 Render 시점에 CBV 테이블 업데이트 누락에 주의하자.

참고

  • 디스크립터 테이블 전환 이유

    항목설명
    Root Descriptor속도 빠르지만 개수 제한 (최대 64 DWORD)
    Descriptor Table확장성과 유연성이 뛰어남 (CBV/SRV/UAV 묶음 사용)
    장점셰이더에 필요한 자원을 테이블로 묶어 GPU에 효율적으로 바인딩 가능
  • DescriptorHeap 종류

    • CBV / SRV / UAV는 같은 힙
    • Sampler는 별도 힙
    • 한 번에 바인딩 가능한 디스크립터 힙은 최대 2개

요약 및 느낀점 📝

  • 루트 시그니처를 디스크립터 테이블 기반으로 개편
  • ConstantBuffer는 테이블과 연동 가능한 구조로 재설계되었다.
  • GPU에 바인딩할 CBV를 다수 관리할 수 있도록 TableDescriptorHeap 클래스가 작성 되었다.
  • PushData()SetCBV()CommitTable() 순서로 렌더링 로직이 수행된다.

    느낀점 💡 Root Signature와 Descriptor Table내용을 이후 헷갈리지 않고고 잘 사용할 수 있도록 이해하는 것이 매우 중요하다고 느꼈다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.