D3D12예제에서 Constant Buffer를 System Memory에 두는 이유.

D3D12 예제를 보면 Constant Buffer를 system memory에 만들어 사용하고 있다. (CPU write, GPU read).
D3D11에선 Constant Buffer를 GPU메모리에 두느냐, 시스템 메모리에 두느냐에 따라 성능차이가 꽤 난다. 20-30%정도는 차이가 나는것 같다.
D3D12에서 테스트해보면 대략 10%정도 성능 차이가 난다. 당연히 GPU메모리에 두는 쪽이 빠르다. 크다면 크고 작다면 작은 수치다. 그럼 왜 D3D12예제에선 시스템 메모리에 Constant Buffer를 잡았을까.

D3D12에선 시스템메모리에 Constant Buffer를 잡으면(Dynamic Buffer로) Map()해놓은 후 Unmap()할 필요가 없다. 즉 한번 써넣을 어드레스를 받아놓고 그 위치에 계속 써넣으면 별도의 API호출없이 렌더링시에 그대로 반영된다. 후술할 이유 때문에 이것은 의도된 API 설계로 보인다.
반면에 Constant Buffer를 GPU메모리에 두면 API를 통해서 시스템 메모리-> GPU 메모리로 업데이트를 해야한다. 업데이트를 하려면 Command List에 기록을 하고 Command Queue를 통해서 Execute()를 호출해야한다. Command Queue를 여러개 동시 사용하는 경우 Fence를 걸고 작업이 끝날때까지 wait해야할 수 있다.
그리고 D3D12에선 copy를 하거나 draw를 하거나 상황에 따라서 리소스의 상태를 수동으로 바꿔줘야한다.
따라서 Constant Buffer로 사용할 GPU메모리에 뭔가를 써넣으려면 다음과 같은 코드가 된다.

1) 한번에 갱신할 경우

pCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_pResourceGPU, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, D3D12_RESOURCE_STATE_COPY_DEST));
	pCommandList->CopyResource(m_pResourceGPU, m_pResourceCPU);
	pCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_pResourceGPU, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER));

불필요하게 큰 용량을 PCI BUS를 통해서 전송해야한다. 이 메모리 영역의 극히 일부만 갱신이 된다해도 PCI BUS를 통해서 전송되는 양은 버퍼 전체 크기이다.

2) 부분적으로 갱신할 경우

for (DWORD i = 0; i ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_pResourceGPU, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, D3D12_RESOURCE_STATE_COPY_DEST));
		pCommandList->CopyBufferRegion(m_pResourceGPU, DestOffset, m_pResourceCPU, SrcOffset, size);
		pCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_pResourceGPU, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER));
}

ResourceBarrier()를 호출해서 리소스의 상태를 수시로 바꿔야한다. 상당한 오버헤드가 걸린다.

절충안으로 후자의 방법을 사용하되 ConstantBuffer로 사용할 GPU메모리를 일정 사이즈 단위로 잘라서 관리하면 오버헤드를 줄일 수 있다. 안그래도 번거로운데 더 번거로워 진다.

[결론]
그러니까 D3D12샘플에서 Constant Buffer를 GPU메모리에 둔 이유는 다음과 같이 추측할 수 있다.
하려면 할 수는 있지만…이런 엄청 비대해진 코드를 만들지 않기 위해 그냥 쉽게 system memory에 Constant Buffer를 잡은걸로 보인다.

지금 두가지 버전을 다 만들어놨지만 결국 system memory에 잡아두는걸로 되돌릴 생각이다. 번거로워서 안되겠다.


답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

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

Google+ photo

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

Twitter 사진

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

Facebook 사진

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

w

%s에 연결하는 중