(사실 이해했는지 모르겠다. 어렴풋이 느껴질 뿐... 그래도 그 느낌을 정리한다.)
1. FrameResource를 이용한 지형 + 파도 그리기 예제(까지)가 연습시켜주는 기술
1_1 어뎁터 초기화 단계
( 이전 예제 에서 한 초기화와 같다.)
- 창(window) 생성
- 어뎁터 (D3DDevice) 생성
- GPU와 CPU 동기화를 위한 Fence 생성
- GPU와 CPU의 [데이터 전송을 위한 Descriptor View]의 Handle Size 초기화
(아마 요걸로 데이터 블록(아마도 테이블?)을 점프하면서 데이터를 읽을 것 같다.)
- Command Queue, Command Allocator, Command List 생성
(멀티 스레딩을 위해 새로 바뀐 GPU에게 렌더링 동작을 요청하는 방법)
- Swap Chain에서 Render Target 얻기
- Render Target 의 정보를 GPU와 연결할 Descriptor (View)
- Render Target 의 정보를 GPU와 연결할 Descriptor 를 또 (GUID로 구분하는) 공간인 Descriptor heap에 연결
- GPU에서 사용할 Depth - Stencil의 정보를 가지는 Descriptor (View)
- GPU에서 사용할 Depth - Stencil의 정보를 가지는 Descriptor 를 또 (GUID로 구분하는) 공간인 Descriptor heap에 연결
- Viewport 설정
1_2. FrameResource 아이디어와 그것을 사용하기 위한 준비
- 이전 글 과 거의 같다.
- 하지만 1_4 항목을 위해 추가된 부분이 있다.
1_3. Root Signature를 Root Constant로 사용하기
(얘는 Descriptor Heap 안쓴다. 직접 Shader에 꽂아 넣는 느낌.)
- Root Signature를 생성할때, D3D12_ROOT_PARAMETER_TYPE을 D3D12_ROOT_CONSTANTS로 만든다.
(d3dx12.h에서 편하게 CD3DX12_ROOT_PARAMETER를 사용하도록 하자.)
- View Heap이 없으니 Shader에 넘겨주는 것도 ID3D12Resource::GetGPUVirtualAddress()을 통해 얻은
- D3D12_GPU_VIRTUAL_ADDRESS 으로 Shader에 넘겨준다.
- D3D12_ROOT_PARAMETER를 생성할 때, 슬롯 번호와 레지스터 번호를 맞춰서
- ID3D12GraphicsCommandList::SetGraphicsRootConstantBufferView으로 IA 단계에서 Shader에 넘어가게 된다
1_4. CPU에서 실시간으로 바꾸는 Wave Vertex 정보
- 예제에서 제공된 Waves::Update 함수는 실시간(조건부)로 호출 된다. 그 업데이트 된 정보는 실시간으로 적용이 되어야 한다. ( 이건 뭔가 엄청 수학적인 내용이고, 내가 이해를 못했으니 여기에 적지 않는다.)
- Wave를 나타내는 Vertex 정보가 FrameResource 에 맴버로 들어가면? Buffer 오염도 되지 않고 편하게, 성능적으로 큰 문제(?) 없이 실행할 수 있게 된다.
- 이렇게 실시간으로 CPU가 접근해서 Buffer의 값을 바꾸려면, D3D12_HEAP_TYPE_UPLOAD 을 이용하는 Buffer여야 하고, Map을 용해서 얻은 CPU 주소를 가지고 값을 변경하게 된다.
- 이전 글에서 언급했는지는 모르겠는데, Upload Heap을 사용하여 Buffer를 올리면, Default Heap을 사용하는 Buffer 보다 느리다고 한다.
- 매번 바뀌는 Buffer를 한번 만들면 GPU 만 접근할 수 있는 Default Heap을 통하는 Buffer를 만드는 것은...
- 중간에 Upload Heap Buffer를 사용해서 처음 값을 올려줘야 하고, ID3D12Device::CreateCommittedResource() 를 쓰고, ID3D12GraphicsCommandList::ResourceBarrier 가지고 막 상태를 바꿔주고 해야하니까... 뭐랄까 복잡해보인다.
1_5. Initialize 와 Update 와 Draw 단계 간단 정리
1_5_1. Initialize
- landscape를 예제에서 제공한 Grid 생성 함수와, height(x, z)를 이용해서 Default Buffer를 만든다.
- wave 를 예제에서 제공한 Waves 클래스를 이용해서 Upload Buffer를 만든다.
- landscape와 wave를 RenderItem 화 시킨다.
- 새로운 맴버가 추가된 FrameResource를 생성한다.
- Constant Buffer를 직접 받는 Root Constant로 Root Signature를 받는다.
- PSO를 만든다.
1_5_2. Update
- 현재 FrameResource를 얻는다.
- 혹시 모를 Fence를 체크하고
- Object Constant, Frame Constant와 Wave의 Vertex 정보를 업데이트한다.
1_5_3. Draw
- 현재 FrameResource의 Allocator를 초기화하고
(이전 글 처럼 기본적인 것을 Command List에 넣어주고)
- 일단 Frame 공통 Buffer를 넘겨주는데, SetGraphicsRootConstantBufferView로 설정했던 slot 번호와 Buffer의 GPU Address와 함께 쉐이더로 넘겨준다. ( D3D12_GPU_VIRTUAL_ADDRESS )
- Object 별 (Render Item) Buffer도 넘겨주는데 이것도, Object Buffer 안에 Object에 맞는 Offset 값을 점프한 것을 GPU Address로 slot 번호에 맞게 쉐이더에 넘겨준다.
- DrawIndexedInstanced 에도 Render Item에 지정해 놓은 값을 넣어줘서 렌더링 요청을 한다.
(이전 글 처럼 Command Queue를 마무리 해주고)
- Frame Resource Index를 하나 늘려주고,
- 작업이 끝나면 GPU에게 fence 하나 늘리도록 요청한다.
2. 아직 잘 모르는 것
- 역시 제품을 만들면서 새로 삽질을 해야 진짜로 내것이 되는법
- 일단 다음 챕터로 간다.
'Programming > D3D12' 카테고리의 다른 글
[책공부] Texturing 예제 + chap 9 연습 문제 (0) | 2024.01.13 |
---|---|
[책공부] Lighting 예제 + chap 8 연습 문제 (0) | 2024.01.11 |
[책공부] Chap7 연습 문제 (0) | 2024.01.08 |
[책공부] FrameResource 예제 ( + Descriptor Table) (0) | 2024.01.04 |
[책공부] 박스 그리기 예제 (0) | 2023.12.27 |