D3D12엔진개발-CommandList 사용 실수

밖이 워낙 추우니 일단 집밖으로 나가기 싫은지라 추운 방에서 떨면서 작업을 했다.
현재 Post-effect를 적용하진 않았지만 준비는 다 끝났다.
아웃라인을 처리하기 위한 Normal과 Depth, 오브젝트 타입별 ID를 저장하는 별도의 렌더타겟 버퍼들을 만들고 렌더링하고 직접 눈으로 볼 수 있도록 했다.
그 외에 glow와 dof를 적용하기 위한 준비도 끝냈다.


d3d12_pre_post_effect

그 와중에 너무 잘 돌아가는게 이상하다 싶어 Graphics Debugging을 돌려보니 뭔가 이상하다.
Shadow Map생성을 위한 CommandList를 중복해서 execute하고 있었다. 이런 비싼 작업을 중복해서 하다니…절대 있어선 안될 일이다.
원인은 금방 찾았다.
D3D11부턴 렌더링할때 Begin,End를 지정하는 API가 따로 없다. 그렇지만 그쪽이 생각하기 편하기 때문에 엔진코드에선 여전히 BeginRender()와 EndRender()함수를  만들어서 사용한다.
그리고 EndRender()에서 ShadowMap생성을 위한 CommandList와 scene 전체를 렌더링하는 CommandList를 한번에 execute한다.
그리고 이 엔진을 사용하는 뷰어 어플리케이션(스크린샷의)에선 2pass로 렌더링한다.
즉 다음과 같다.
BeginRender() ->  World Scene 렌더링 – EndRender() -> BeginRender(프레임버퍼 지우지 않기) -> Text Window 렌더링 -> EndRender()
EndRender()에서 CommandList를 execute하니까 ShadowMap생성을 위한 CommandList도 두번 execute되는 것이다.
그렇다해도 ShadowMap생성  CommandList는 첫번째 BeginRender(),EndRender()사이에서 recording된다. 두번째 Execute시점에선 ShadowMap생성 CommandList는 reset되어있어야 하는거 아닌가?
라고 생각해서 찾아보니
ShadowMap생성을 시작하는 BeginBuildCascadeShadowMap()함수에서 CommandList가 reset하고 있었다.
따라서 두번째 렌더링 pass에서도 ShadowMap생성을 위한 CommandList는 reset되지 않은 상태이고 그대로 execute될 수 있는 것이다.
뭐 해결책은 간단하다. 처음 ShadowMap생성 CommandList를 execute한 후에 해당 CommandList가 유효하지않음을 표시해두면 된다. 아니면 CommandList를 바로 reset해버리던가.
일단 첫번째 방법으로 처리했다.
문제점을 수정한 후 Grpahics Debugger에서 타임라인을 보면 다음과 같다.


execute_command_list

Execute()가 두번 호출되는데 첫번째는 world를 렌더링할때, 두번째는 화면 하단의 Text Window를 렌더링할때 호출된다.
첫번째 Execute()를 확장해보면 Obj:19와 Obj:17두개의 CommandList를 실행한다.
Obj:19는 ShadowMap생성을 위한 CommandList이고 Obj:17은 일반적인 world렌더링을 위한 CommandList이다.
참고로 디버깅 팁 하나.
ShadowMap을 생성하기 위해 광원시점에서 Shadow Caster오브젝트를 렌더링하는데 이 경우 PixelShader를 그냥 null로 세팅하면 된다. 그럼 depth만 기록할 수 있다.
따라서 이 특성을 이용하면 Grphics Deubgger에서 ShadowMap을 생성하는 Draw call은 비교적 쉽게 찾을 수 있다.
Shadow Caster를 렌더링한 Draw call을 디버거에서 찍어보면 다음과 같이 VertexShader 이후로는 출력이 없다고 나온다.
 
gen_shadow_map
CommandList를 중복해서 호출하다니. D3D11같으면 이런 문제는 전혀 생각할 이유가 없는 실수다.
D3D12는 CommandList를 이용한 batch처리를 하다보니 생각지도 못한 문제가 많이 생긴다.
하여간 Graphics Debugging 돌리지 않았으면 전혀 몰랐을것이다.
특별히 문제가 없어도 틈날때마다 Graphics Debugging을 돌려서 의도한대로 작동하고 있는지 확인해야겠다.

댓글 남기기