본문 바로가기

TOOL/Unity

Draw call / Batch

Draw call


CPU가 GPU에게 Scene을 한번 그려라 라는 명령을 내리는 것이라 보면 된다.

Draw call은 CPU메모리를 많이 먹으므로 이 횟수를 줄이는 것이 최적화에 중요하다.


Batch


Unity에서는 기존에 Draw call이라는 것을 사용하다 5버전부터 Batch라는 단어로 대신 사용한다.

Batching 과 Draw call은 개념상 다르나 결국 1회의 Batching이 끝나면 1회의 Draw call이 발생하기때문에

Draw call 횟수 = Batching 횟수  이기 떄문에 단어의 차이일 뿐 의미는 같다고 볼 수 있다.


예를들어 Command Buffer상의 SetState( ) 호출작업, 그려질 Triangle의 정보들을 셋팅하는 작업, Rendering State를 셋팅하는 작업들 등이

Batching에 해당되며 batching이 다 끝나면 GPU에서 "택배 받으세요" 하고 해당정보들을 Draw call을 하여 넘겨준다.


Unity에서 Object의 inspector창에 있는 Static Object 옵션을 체크해주면 Static Batching이, 300개 미만의 Vertex를 가진 Object에 대해서

Dynamic Batching이 발생하지만 동일 material, 동일 shader를 사용한다는 가정 하에 발생한다.


또한 PlayerSetting에서 Static Batching / Dynamic Batching 의 옵션을 체크해주어야 한다.


그림 10.1은 작은 Draw data를 그리기 위해 draw call을 여러번 호출하는 것이고

그림 10.2는 그것들을 한곳에 모아 한번의 draw call로 그리는 것을 표현한것이다.

후자가 더 적은 연산 Overhead로 그려낸다.



Draw call 호출시의 State 변경에 대한 Overhead, 또한 Command Buffer의 Flushing Overhead를 최소화 시켜주는 것이

Performance와 직결되고 이는 Draw call을 줄이는 주요한 이유가 된다.

CPU와 GPU의 관점에서 봤을때 Geometry Data를 보내주는 동작은 충분히 빨라서 CPU가 GPU에게 그려질 Geometry를 빠르게

전달하지 않으면 GPU가 다른짓을 하며 놀게된다.

이런 상황이 작은 Vertex Data를 쪼개어 여러 Draw call을 호출했을때 발생하는 것 이다.(그림 10.1)

CPU는 state를 변경하고 Command Buffer를 새로 update하고 뭘 그릴지 setting하는 overhead를 버벅이며 감당하고 있을때

GPU는 놀고있는 상황이 발생하는 것 이다.


이는 마치 file copy와 비슷한데 1MB file을 1000개 copy하는 것 보다 1GB file 1개를 copy하는것이 훨신 빠른 경우이다.


따라서 동일한 Triangle Format, 동일한 Shader, 동일한 GL State, 동일한 Material을 사용하는 객체들 끼리 모아

한번에 Rendering하는 것이 Draw call을 줄일 수 있다.



Bathcing 


Unity에서 Runtime에 Single Draw Call로 가능한 Object들을 묶어주는 행위

Batching이 많이 이루어지면 Draw Call이 줄고 CPU Performance가 올라가게 된다.



Unity가 내부적으로 이런 Runtime Batching을 해준다는 것은 modeling tool에서 Object들을 묶어주거나

Standard Asset Package에서 CombineChildren Script로 묶는 것 보다 훨신 덜 귀찮은 일이다.

또한 묶는다고 해서 Culling이 발생하지 않는 것이 아닌 Culling은 개별 Object에 대해서 따로 계산이 되니

훌륭한 기능임이 분명하다.

(다만 수동으로 묶는것이 더 효율적일 수 밖에 없긴 하다.)


Unity에서는 동일한 material을 사용하는 object들에 대해서만 하나의 Draw Call로 묶는 Batching이 발생한다.

그러므로 Batching이 Engine에서 잘 일어나도록 하기 위해서는 가능한 동일한 Material을 사용해야 한다.

Texture만 다르고 다른 모든 값들은 동일하다면 Texture Atlasing을 사용해서 하나의 Texture로 묶은 후 단일 Material로 만들면

Batching이 발생하여 Draw Call이 줄어들게 된다.


또한 Script에서 Material을 사용할 떄 Render.material 호출은 Material을 Copy하여 생성하는 것 이므로

Draw call이 추가 발생하게 된다.

대신 Render.sharedMaterial을 사용하여 Batching이 발생하도록 공유하는 형태로 사용하는 것이 좋다.




Dynamic Batching


움직이고 있는 Object에 대해서 Unity가 자동으로 batching을 하기 위해서는 동일 material을 사용하는 것 외에 추가적인 조건이 필요하다.


Dynamic Batching의 경우 Per Vertex Overhead가 발생한다. 따라서 Batching이 되는 Object의 vertex가 많으면

CPU 부하가 많이 발생하므로 모두 합쳐서 900개의 Vertex 이하의 Object에 대해서만 Dynamic Batching이 발생하도록 되어있다.


Object가 일반적으로 동일한 scale을 가져야 dynamic batching이 일어난다.

크기값이 모두 제각각일 경우 batching이 일어나지 않는다.


동일한 material이더라도 다른 Material Instance를 사용할 경우 dynamic batching이 발생하지 않는다.


추가적인 파라메터(lightmap index, offset, scale)가 있는 lightmap object의 경우 dynamic batching이 발생하지 않는다.

그래서 일반적으로 dynamic lightmap object의 경우 완벽하게 동일한 lightmap 위치를 가져야만 batching이 발생한다.


Multi pass shader를 적용한 object는 batching이 되지 않는다.

거의 모든 unity shader는 Forward Rendering에서 효율적인 lighting 계산을 위해 여러개의 light를 지원한다.

추가적인 per pixel light들의 draw call은 batching이 되지 않는다.


Legacy Deffered(광원 프리패스) rendering pass는 object를 2번 draw call해야 하기 때문에 dynamic batching이 불가능하다.

Real time shadow를 받는 object는 batching이 되지 않는다.



Static Batching


Unity에서 Static batching은 어떤 size의 vertex size를 가진 object들도 모두 지원한다.

(단 이동이 없어야 하고 동일한 material을 사용해야 한다.)

Static batching은 dynamic batching에 비해 cpu사용이 현저이 적게 소모되므로 가능한

Static batching을 사용해야 한다.

(Object inpector의 우측 상단에 static 체크박스를 체크해주어야 한다.)


Static batching을 사용하게 되면 하나로 묶여진 geometry를 memory에 저장해야하기 때문에 추가적인 memory를 차지한다.

따라서 빽빽한 숲의 나무를 만든다고 했을때, 해당 나무들을 static으로 셋팅하게되면 묶여진 나무 geometry가 모두

memory에 올라가기 때문에 memory 부족을 발생시킬 수 있다.

이 경우 나무의 static batching을 꺼서 rendering쪽을 희생시키는 것이 더 나은 선택일 수 있다.

따라서 맹목적인 static batching 신뢰는 피하는 것이 좋다.



Mesh Renderer, Particle System, Trail Renderer, Sprite Renderer만 Batching된다.(추후 더 추가될거같음)

Character animation에서 사용되는 Skinned Meshes, Clothes는 batching되지 않는다.

투명한 object는 ordering때문에 불투명한 object보다 batching이 잘 되지 않는다.


가까이 있는 gameobject의 경우 combined mesh를 이용해서 묶으면 도움이 된다.











PPT에 있는

'1 batch for many objects' 라는 문구가 모든걸 요약해주는 좋은 문구인듯 하다.


전에 DX9으로 모작을 할 때 동일한 Shader를 사용하는 Object들을 한번에 모아서 Rendering했던 것도 이것을 줄이기 위해 했던것이다.




참고

http://rapapa.net/?p=2694

https://www.slideshare.net/ozlael/unite-seoul-2016-60714130

http://rapapa.net/?p=2472

'TOOL > Unity' 카테고리의 다른 글

Unity 문제  (0) 2019.03.22
Frame 고정값 셋팅  (0) 2019.03.11
Scriptable Object  (0) 2019.03.11
Coroutine / IEnumerator / IEnumerable  (0) 2019.03.06
Unity CG / Boehm-Demer-Weiser / 점진적 GC  (0) 2019.03.05