D3D12의 Map()에 대한 고찰.

최근에 VOXEL HORIZON에서 와이어 프레임으로 렌더링되는 박스들이 상당히 성능을 잡아먹고있음을 알게됐다. 본래라면 이런건 디버깅용 매시로나 쓰는거다.
VOXEL HORIZON에서는 다수의 오브젝트를 선택해서 회전/이동을 시킬때 다수의 박스를 그리게 되므로 문제가 됐다.
첨부한 이미지와 같이 커틀러옹의 이미지로부터 변환된 복셀 오브젝트는 250개 정도 되고 이 오브젝트들을 선택했을때, 250개 정도의 박스를 렌더링 한다. 또한 회전/이동 시킬때 프리뷰 화면으로 250개 정도의 블럭(geometry shader이용)을 렌더링 하게 된다. 여기서 250개 정도의 오브젝트를 선택했을 때(250개의 박스를 그릴 때) D3D12렌더러에선 프레임이 2/3토막 나고 프리뷰 화면을 렌더링 할때 1/3토막 났다.

이게 dynamic buffer를 렌더링하는데 있어서 성능을 전혀 고려하지 않았기 때문이다.
요 몇일간 성능개선작업에 매달렸고 만족할만한 수준의 결과를 얻었다.
어떻게 성능 향상을 시켰는가는 나중에 자료를 다시 만들 예정이다.
그 과정에서 Map()에 대해서 여러가지로 생각해보게 되어서 D3D11의 Map()과 D3D12의 Map()의 차이점에 대해서 적어본다.

D3D11의 Map()

*D3D11_MAP_WRITE_DISCARD플래그를 줄 경우

드라이버에서 리소스 리네이밍을 수행한다.

1) A라는 버퍼가 있을때 먼저 Map()으로 포인터를 따서 내용을 적어넣고 Unmap()후 Draw…()를 호출한다.

2) 아직 렌더링이 끝나지 않은 상태에서 다시 A버퍼를 Map()해서 값을 쓰려고 한다.

3) 렌더링 중인 리소스의 상태를 보호해야하므로 드라이버는 다른 메모리 포인터를 돌려준다. 렌더링이 끝나고나면 먼저 사용된 메모리는 pool에 반환되고 나중에 써넣기한 메모리가 이 리소스의 내부 메모리가 된다.

이러한 원리로 D3D11에선 아직 렌더링 중인지 여부에 상관없이 마구 써넣기를 해도 렌더링이 무사히 된다.

*D3D11_MAP_WRITE_NO_OVERWRITE플래그를 줄 경우

해당 버퍼는 결코 덮어쓰기가 일어나지 않는 것으로 간주된다. 따라서 Map()을 호출하면 항상 같은 어드레스가 리턴된다.

당연히 렌더링이 아직 끝나지 않은 상태에서 여기다 내용을 써넣으면 렌더링 상태가 엉망이 된다.

어쨌든 리소스 리네이밍도 CPU자원을 소비하므로 버퍼 안에서 프로그래머가 메모리를 잘 쪼개 사용할 수 있다면 이쪽을 사용하는 것이 빠르다.

D3D12의 Map()

리소스 리네이밍 따위 없다. D3D11의 Map()에 D3D11_MAP_WRITE_NO_OVERWRITE플래그를 준것과 똑같다.
Map()함수는 항상 동일 어드레스를 리턴한다.
렌더링이 끝날때까지 해당 리소스의 내용은 변경되어선 안된다.
당연히 버퍼 안에서 프로그래머가 메모리를 잘 쪼개서 사용해야한다.

애초에 dynamic buffer는 선/원/박스 등 디버그용으로 사용하는 매시 그릴때나 주로 쓰지 게임 렌더링용 오브젝트 그릴때는 잘 사용하지 않는다. 이런종류의 오브젝트들은 출시버전에선 렌더링 될 일이 없으니 성능을 다소 깍아먹더라도 별로 신경쓰지 않는다. 그러니까 기존에 D3D11쓰던 프로그래머들은 성능상의 이득이 있다해도 D3D11_MAP_WRITE_NO_OVERWRITE 플래그는 잘 사용하지 않았다. 물론 나도 그랬다.

그러다가 D3D12로 넘어오면 Map()을 처음 사용할 때 약간 멘붕이 온다. 11에선 됐는데 12에선 왜 안되지? 어떻게 Map()을 한번 호출하면 종료할때까지 그 어드레스가 계속 유지되지? 라고 의문을 갖게 된다. D3D11은 자동화된 시스템이 사라졌으므로 느끼게 되는 당혹감이다. 뭐 깨닫고 나면 별거 아니다. 그냥 다 손으로 만들어주면 되지.

리소스 리네이밍에 대해서는 다음의 nvidia자료를 참고.

https://developer.nvidia.com/content/constant-buffers-without-constant-pain-0


답글 남기기

댓글을 게시하려면 다음의 방법 중 하나를 사용하여 로그인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중