[GEG1] 10.camera-centric engine design for multithreaded rendering

Preview:

Citation preview

Game Engine Gems 1 Chap 10. Camera-Centric Engine Design for Multithreaded Rendering

ohyecloudy http://ohyecloudy.com

shader café http://cafe.naver.com/shader

2011.04.11

Uses of Multi-Core in Video Games

Multithreaded Command Buffers

Device-Independent Command Buffers

A Camera-Centric Design

Future Work

Sim Update

Anim Physics Update

Particle Update

Shadow Maps

Reflect Maps

Main View

Post- Process

frame

Main thread

Thread Pool

Sim Update

Anim Physics Update

Particle Update

Shadow Maps

Reflect Maps

Main View

Post- Process

frame

Main thread

Thread Pool

Rendering API를 호출할 필요가 없는 작업만 multithread

Sim Update

Anim Physics Update

Particle Update

Shadow Maps

Reflect Maps

Main View

Post- Process

frame

Main thread

Thread Pool

Stage 별로 그룹화 각 스테이지에서 직접 device call 그래서 device를 소유하는 thread에서 대부분 일을 처리

Uses of Multi-Core in Video Games

Multithreaded Command Buffers

Device-Independent Command Buffers

A Camera-Centric Design

Future Work

• 그리기 명령을 수행하는데 필요한 정보

– device level

• rendering API 내부에 존재

– API를 호출하면 버퍼를 채움

– CPU 사용

• command buffer를 추상화 – multithread로 command buffer를 채울 수 있게

– device 독립

• DX9 – multithread command buffer 불가능

– device를 소유한 thread에서만 API call

– multithread를 지원 옵션이 있긴 있다 • 모든 call에 베타제어

• 성능 저하가 심함

• 제외

Uses of Multi-Core in Video Games

Multithreaded Command Buffers

Device-Independent Command Buffers

A Camera-Centric Design

Future Work

struct RenderCommand { ResourceHandle VertexBufferHandle; uint32 VertexDeclEnumIndex; uint32 NumTriangles; uint32 NumVerts; enum PrimType { kTriList, kTriStrip }; PrimType PrimitiveType; enum BlendType { kBlend_None, kBlend_Standard, kBlend_Additive, kBlend_Subtractive }; BlendType BlendType; // and so on… };

RenderCommand 드로우 콜 단위

void RenderObject::fillCommandBuffer (RenderCommand *RC) { ThreadAssert(ThreadPoolThread); if (ObjectType == kTypeOpaqueMesh) { RC->VertexBufferHandle = mVBHandle; RC->VertexDeclEnumIndex = kVD_Mesh; RC->PrimitiveType = kTriList; RC->BlendType = kBlend_None; RC->NumTriangles = numTrisFromPrimType(); RC->NumVerts = mNumVerts; } else if (ObjectType == kTypeTransparentMesh) { // and so on… } }

void RenderObject::fillCommandBuffer (RenderCommand *RC) { ThreadAssert(ThreadPoolThread); if (ObjectType == kTypeOpaqueMesh) { RC->VertexBufferHandle = mVBHandle; RC->VertexDeclEnumIndex = kVD_Mesh; RC->PrimitiveType = kTriList; RC->BlendType = kBlend_None; RC->NumTriangles = numTrisFromPrimType(); RC->NumVerts = mNumVerts; } else if (ObjectType == kTypeTransparentMesh) { // and so on… } }

렌더링 리소스 수명을 제어하는 객체 오브젝트 하나가 여러 개 RenderCommand를 만들 수 있음 character, terrain, …

void RenderObject::fillCommandBuffer (RenderCommand *RC) { ThreadAssert(ThreadPoolThread); if (ObjectType == kTypeOpaqueMesh) { RC->VertexBufferHandle = mVBHandle; RC->VertexDeclEnumIndex = kVD_Mesh; RC->PrimitiveType = kTriList; RC->BlendType = kBlend_None; RC->NumTriangles = numTrisFromPrimType(); RC->NumVerts = mNumVerts; } else if (ObjectType == kTypeTransparentMesh) { // and so on… } }

RenderObject 상태를 단지 읽기만 한다. thread safe

void renderControl::executeDrawCommandDx9 (const RenderCommand *params) { ThreadAssert(DeviceOwningThread); const VertexBufferContainer *vbc = mManagedVBs.getElement(params->vbHandle); DX9Dev->SetStreamSource( 0, (IDirect3DVertexBuffer9 *)vbc->devicehandle, 0, vbc->perVertSizeInBytes); SetShaderData(params); SetRenderStates(params); DX9Dev->SetVertexDeclaration( StaticVDeclHandles[params->vDecl]); D3DPRIMITIVETYPE type = PrimTypeMappingLUT[params->PrimitiveType]; DX9Dev->DrawPrimitive(type, 0, params->NumTriangles); }

Uses of Multi-Core in Video Games

Multithreaded Command Buffers

Device-Independent Command Buffers

A Camera-Centric Design

Future Work

• load balancing 필요

– command buffer 채우는 작업을 할당

– thread 별로 어떻게 할당?

• 최종 장면이 나오기 전까지 여러 장면을 렌더링

– shadow map, reflection, post processing, …

– 카메라

• 장면마다 공유

• camera 단위

– command buffer 생성을 쪼갠다.

• draw call 묶기

– API 호출에 따른 오버헤드 최소화

– render state 변경 최소화

– batch

Sim Update

Anim Physics Update

Particle Update

frame

Main thread

Thread Pool

Render View Filling

Submit to

Device

struct Camera { Float3 at, up, right; float aspectRatio; }; struct RenderView { Camera ViewCamera; Frustum Frust; RenderTargetHandle DestColorRTT; RenderTargetHandle DestDepthRTT; List<RenderCommand *> RenderCommands; enum ViewType { kVT_ShadowMap, kVT_ReflectionMap, kVT_MainCamera, kVT_PostProcessing, kVT_Count }; ViewType ViewType; };

void renderControl::CreateRenderViews() { List<RenderView *> currentViews; for (int i = 0; i < mCameras.size(); ++i) { currentViews.add( new RenderView(mCameras[i], kVT_MainCamera)); } for (int i = 0; i < mLights.size(); ++i) { if (mLights[i].IsShadowCasting()) { currentViews.add( new RenderView( mLights[i].getShadowCamera(), kVT_ShadowMap)); } } for (int i = 0; i < currentViews.size(); ++i) { ThreadPool.QueueWork( procThreadedFillRenderView, currentViews[i]); } ThreadPool.waitForWorkToFinish(); }

void renderControl::procThreadedFillRenderView (

void *DataPacket) {

RenderView *currView = (RenderView *)DataPacket;

List<RenderObject *> objects =

gObjectManager.giveFrustumCollision(

currView->frustum);

for (int q = 0; q < objects.size(); ++q) {

RenderCommand *RC = new RenderCommand();

Objects[q]->fillCommandBuffer(RC);

currentViews[i].RenderCommands.add(RC);

}

}

void renderControl::serializeRenderView (List<RenderView *> Views) { for (int viewType = 0; viewType < Count; ++viewType) { for (int i = 0; i < Views.size(); ++i) { if (Views[i].mViewType != viewType) continue; BindRenderTarget( Views[i]->renderTarget, Views[i]->DepthTarget); if (Views[i]->clearTargets) { ClearTarget( Views[i]->clearFlags, Views[i]->clearColor, Views[i]->clearDepths); } for (int k = 0; k < Views[i]->commands.size(); ++k) { executeDrawCommand(Views[i]->commands[k]); } } } }

Uses of Multi-Core in Video Games

Multithreaded Command Buffers

Device-Independent Command Buffers

A Camera-Centric Design

Future Work

• Sorting and Instancing

– material index, vertex data, object type…

– instancing command

• draw command 여러 개를

• Better Load Balancing

– draw call을 job 하나로

– job을 잘게 나눠 thread utilization을 높임