반응형

http://www.gpgstudy.com/forum/viewtopic.php?topic=8829





엔진 속도를 올려볼려고, 파티클의 빌보드 한개당 DrawPrimitive하던것을 
긴 버텍스 버퍼에 월드 좌표로 때려밖은후에 렌더링 하려고 고치는 중입니다. 

DrawPrimitive횟수도 많이 줄이고요, SetRenderState, SetTexture횟수도 줄이도록 정렬하고있습니다. 

그런데.. 버텍스 버퍼가 크다보니 락/언락만 해도 프레임이 10%로 내려가더군요.. 
엄청난 속도 저하이죠..^^ 정확히 이야기하면 락/언락 하고 그버퍼의 폴리곤 1개만 찍어도 그러더군요.. 
안찍으면 락/언락해도 전혀 안내려가고요... 

버텍스 버퍼를 D3DPOOL_MANAGED로 만들어서 DrawPrimitive하는순간 시스템메모리에있는 복사본을 
VGA로 넘기나 봅니다. 
그래서 D3DPOOL_DEFAULT로 생성했더니 속도저하가 없더군요..다만 디바이스 리셋시 삭제/복구만 잘해주면 
될듯 싶습니다.. 그게 귀찮아서 이제껏 D3DPOOL_MANAGED만 사용했었거든요.. 

지오메트리랑, 스킨모두 D3DPOOL_MANAGED로 사용하고있거든요.. 
지오메트리야 정점 버퍼 자체는 변하지 않아서 첨 생성해서 만든다음 그냥 사용하고 
스킨은 Tick()마다 락/언락을 하거든요.. 

궁금한점 
1. 락/언락을 하지 않는 버퍼는 D3DPOOL_MANAGED와 D3DPOOL_DEFAULT가 성능이 같나요? 
2. 락/언락을 하는 D3DPOOL_MANAGED버퍼는 DrawPrimitiveUP하고 성능이 같나요? 
3. 모두 D3DPOOL_DEFAULT로 바꾼다면 비디오메모리가 모자랄경우 D3DPOOL_MANAGED에 비해 단점이 있나요? 혹은 디바이스 리셋시 삭제/복구말고, 락할때 옵션이라던지 다른 관리들이 필요한지 궁금하네요..








SDK 도움말에 설명이 나와있하지만.. 그래도 꽤 많은 분들이 헷갈려하시는거 같습니다. 

D3DPOOL_MANAGED 는 풀이 시스템메모리에 백업되고 필요시에 비디오메모리로 로드됩니다. 한번 로드된 풀은 해제되거나 아니면 메모리의 부족으로 강제로 내려갈때까진 메모리상에서 유효합니다. 
시스템메모리에 백업되어있기때문에 디바이스 리셋시에도 별다른 조치를 할 필요가 없습니다. 

D3DPOOL_DEFAULT 는 풀이 비디오메모리에 바로 생성되고 메모리가 부족하면 풀을 만들때 오류를 뱉어냅니다. 따로 백업되어있지않기때문에 디바이스 리셋시에 더이상 유효하지 않게 됩니다. 

D3DPOOL_MANAGED 는 시스템메모리에 백업되어있기때문에 'Read' 하는것에는 별다른 문제가 없습니다. 다만 'Write' 는 하게될때마다 메모리에서 내렸다가 다시 로드되어야되기때문에 무리가 따릅니다. (레퍼런스상에서도 D3DPOOL_MANAGED 로 생성된 버텍스버퍼나 인덱스버퍼는 런타임상에서 업데이트하는걸 성능상에 문제로 추천하고 있지 않습니다. 같은 이유로 렌더타겟같은것들은 D3DPOOL_MANAGED 로 만들수가 없습니다.) 

D3DPOOL_DEFAULT 는 따로 시스템메모리에 백업이 없기때문에 'Read' 에 무리가 있습니다. 다만 'Write' 하는것에는 D3DPOOL_MANAGED 로 만들어진것보단 적합해서 각종 다이나믹 버텍스버퍼/인덱스버퍼 등에 쓰이게 됩니다. 

다이나믹 버텍스버퍼나 인덱스버퍼를 쓸때 자주 쓰이는 옵션인 D3DLOCK_DISCARD 와D3DLOCK_NOOVERWRITE 는 CPU 와 GPU 의 병목현상을 막기위한 플래그들입니다. 
D3DLOCK_DISCARD 는 현재 드라이버가 잡고있는 풀은 그대로 내버려두고 같은 크기의 새로운 풀을 잡아서 거기에 업데이트를 할수 있게합니다. 그리고 잡고있던 풀이 다 쓰여지고 나면 그 풀을 해제되고 새롭게 만들어졌던 풀이 쓰이게 되는거죠. 드라이버가 다 그릴때까지 멈춰있을수없으니 이런식으로 쓰게 됩니다. 
D3DLOCK_NOOVERWRITE 는 현재드라이버가 잡고있는 풀을 업데이트하지 않겠다고 명시적으로 말하는거가 되겠네요. 렌퍼런스에서는 저 두개의 옵션중에 한가지는 꼭 Lock 할때 써주는것을 추천하고 있습니다. (두개같이 쓰는건 비추하고 있습니다.) 

이런저런 이유로 보통 다이나믹 버텍스버퍼나 인덱스버퍼를 쓸때는 조금 큰 하나의 풀을 잡아놓고 거기에 조금씩 알맞는 플래그로 업데이트해가며 렌더링하는게 여러가지면에서 좋은거 같습니다. 

unsigned int uOffset = 0; 
Loop { 
unsigned int uVertexSize = ...; 
if(uOffset+uVertexSize > uVertexBufferSize) { 
uOffset = 0; 

unsigned long dwLockFlag = D3DLOCK_DISCARD; 
if(uOffset > 0) dwLockFlag = D3DLOCK_NOOVERWRITE; 
pVertexBuffer->Lock(uOffset, uVertexSize, ..., dwLockFlag); 
... 
pVertexBuffer->Unlock(); 
DrawPrimitive(...); 
uOffset += uVertexSize; 


1. 
D3DPOOL_MANAGED 나 D3DPOOL_DEFAULT 나 업데이트를 하지 않는다는 조건에서는 성능은 같습니다. (다만 D3DPOOL_MANAGED 로 생성된 많은양의 풀들이 한꺼번에 비디오메모리로 로드되는 순간에는 버벅임같은것을 느낄수는 있습니다.) 
2. 
D3DPOOL_MANAGED 로 생성된 풀을 런타임상에서 계속 Lock/Unlock 하는건 DrawPrimitiveUP 보다 더 느릴수도 있습니다. 
3. 
모두 D3DPOOL_DEFAULT 로 바꾼다면 비디오메모리가 부족하면 아예 풀생성 자체가 안됩니다. 용도에 따라 꼭 D3DPOOL_MANAGED 가 되어야되는경우도 있습니다. (텍스쳐같은걸 Lock/Unlock 등을 통해서 읽어야되는경우) 레퍼런스상에서는 특별한 경우를 제외하곤 D3DPOOL_MANAGED 를 쓰라고 하고 있습니다.

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

스크린 스페이스 데칼  (0) 2013.02.13
기하정보 저장 버퍼  (0) 2013.02.10
Primitive 종류 설명  (0) 2013.02.09
TGA파일에서 알파채널 만들기  (1) 2013.01.31
포샵에서 DDS파일 만들기(2)  (0) 2013.01.31

+ Recent posts