D3D12 엔진 개발상황
스프라이트 한개를 가지고 위치를 바꿔가며 찍을 수 있게 됐다. 스샷참고.

같은 스프라이트를(캐릭터 모델의경우도 마찬가지) 위치 바꿔가며 여러번 렌더링한다는게 D3D12에선 간단하지가 않다.
D3D11은 즉시 상태를 바꾸로 렌더링하고 그 응답을 받고 다음을 진행한다.
하지만 D3D12는 배치처리를 한다.
Command를 레코딩해서 마지막에 Execute하는 방식이라 이전처럼 한개의 ConstantBuffer를 잡아놓고 내용 고쳐써가며 렌더링을 여러번 할 수 없다. 스샷 참고.

따라서 ConstantBuffer가 여러개 필요하다.
기본전략은 ConstantBuffer Pool을 만들어서 돌려쓰는건데 D3D12에선 렌더링에 필요한 리소스들을 DescriptorHeap에 바인딩해서 DescriptorHeap만으로 렌더링 리소스를 지정한다. 단순하게 ConstantBuffer를 pooling하는 정도로는 부족하다.
기본전략은 다음과 같다.
DescriptorHeap은 최대 참조 회수만큼의 사이즈로 할당하고 ConstantBuffer는 Draw할때마다 그때그때 할당해서 pooling하는걸로.
1. ConsantBuffer 1개, ConsatntBufferView, ShaderResourceVew를 바인딩한 DescriptorHeap의 CPU핸들1개, GPU핸들1개를 묶어서 Context구조체를 만든다.
2. 이 Context구조체를 pooling할 것이다. 임의의 스프라이트(또는 임의의 3D오브젝트)가 함 프레임동안 100번 정도 Draw콜 요청을 받는다 치면…Context구조체의 pool사이즈는 100이다.
3. DescriptorHeap과 Context구조체만 100개 만들어둔다. 배열형태의 자료구조면 충분하다. 여기에 현재 할당한 카운트변수 한개만 있으면 된다. ConstantBuffer는 실제로 Draw콜이 들어올때 생성한다.
4. Draw요청이 들어올때마다 앞에서부터 하나씩 할당. 현대 할당된 카운트를 인덱스로 Context를 리턴해주면 된다. 그리고 할당된 카운트를 1증가.
5. 처음엔 Context구조체를 할당 받아도 ConstantBuffer포인터는 null이고 CBV,SRV도 DescriptorHeap에 바인드 되어있지 않다. ConstantBuffer를 할당하고 DescriptorHeap에 바인딩한다. 텍스쳐도 DescriptorHeap에 바인딩한다. 이렇게 만들어진 Context는 다음번에 재할당 될때 새로 세팅할 필요없이 이 상태로 계속 재활용된다.
6. Execute() -> Present()가 끝나면 ContextPool의 할당 카운트를 0으로 설정한다. 다음번 Draw요청이 들어오면 0번째부터 다시 할당받는다.
;
2개의 스프라이트를 각각 다른 위치로 렌더링하고 있을때 DescriptorHeap의 상태를 보면…
첫번째 DrawCall시
DescriptorHeap에서 0번째 offset에 CBV | SRV,
두번째 DrawCall시
DescriptorHeap에서 2번째 offset에 CBV | SRV,
이런식이다…
DescriptorHeap에서 0번째 offset에 CBV | SRV,
두번째 DrawCall시
DescriptorHeap에서 2번째 offset에 CBV | SRV,
이런식이다…
스샷은 실제로 스프라이트 한개를 위치를 바꿔서 렌더링할때 DescriptorHeap의 상태이다.
인덱스 0,1에 첫번쩨 렌더링시의 ConsantBufferView와 ShaderResoruceView가 설정되어있다.
인덱스 2,3에는 두번째 렌더링시의 CBV와 SRV가 설정되어있다.
OnDemand방식으로 Context를 할당하고 있으므로 나머지 영역들은 아직 사용하지 않고 있다.
3번째 Draw요청이 들어오면 인덱스 4,5번의 디스크립터는 세번째 렌더링시의 CBV와 SRV로 설정된다. 그리고 곧바로 재사용 가능한 Context는 3개가 되는 것이다.

이 스프라이트(또는 기타 등등 3D오브젝트)가 해제될때는 ContextPool을 한번에 제거한다.