사전적 의미론 일괄 이지만, 유니티에서는 단순 사전적 의미로 간주하지 않는다.
최적화 포스팅 에서도 다루었지만, CPU와 GPU간 통신을 줄일수록 시간과 자원이 절약된다.
통신이라 함은 CPU가 GPU에게 명령을 내리는 DrawCall 로 간주할 수 있는데 (엄밀히는 DrawCalls + SetPass Calls)
예를 들어 큐브 10개를 그리는데 GPU한테 10번을 명령하는 것과, 10개를 하나로 묶어 1번을 명령하는 방식이 있다면,
일반적인 경우에선 후자가 더 좋다는 것이다.
그렇다고 너무 많은 큐브 (이 기준은 GPU마다 다르다) 를 한꺼번에 묶으면 GPU의 대역폭 (BandWidth) 에 따라 메모리가 터질 수도 있다.
어쨋든, 이렇게 여러 드로우콜을 하나로 묶는 일련의 행위를 유니티에서는 (배칭)batching 이라고 표현하며,
방법은 또 여러가지가 있다.
그 중 유니티에서 지원하는 배칭은 현재 4가지인데 그 종류와 특징에 대해 짚고 넘어가보자
Dynamic Batching
작은 메시들 몇개를 큰 메시 하나로 합쳐서 드로우콜을 줄이는 방법으로, 별도의 작업없이 자동으로 수행된다.
단 수행될 조건이 몇가지가 있는데, 버텍스 갯수가 180 ~ 300 개 미만인 메시여야 하고, 같은 메테리얼일 경우에만 배칭해준다.
유념해야 할 점은 큰 메시를 하나로 합치는 과정을 CPU 에서 하는데, 이 작업이 GPU한테 드로우콜을 수행하는 것보다 비용이 더 적을 경우에만 유리하다는 것이다.
풀어서 쓰자면,
[옛날]
CPU : 야, GPU! 너한테 맡길일을 CPU인 내가 대신 해줄께 너 이거 하는데 오래 걸리잖아.
GPU : 응 고마워!
[지금 (Metal, Vulkan)]
CPU : 야, GPU! 너한테 맡길일을 CPU인 내가 대신 해줄께 너 이거 하는데 오래 걸리잖아.
GPU : 너가 해주는게 시간 더 걸릴껄?
최신 API 일 경우 Dynamic Batching이 전혀 유리하지 않을 수 있다.
Static Batching
다이나믹 배칭과 달리 크기에 관계없이 하나로 합쳐주고 그 과정에서 CPU 자원이 소모되는 것도 아니어서 장점만 있는 것 같지만, 움직이지 않는 메시에만 적용되며, (인스펙터에서 static 체크) 또한 과도하게 메모리를 사용할 수 있는 것이 단점이다.
예를 들어 동일한 나무 메시를 다수 배치한 숲 같은 배경일 경우 스태틱 배칭을 켤 경우 자칫 합쳐진 메시가 너무 비대해져 메모리가 뻗어버릴 수 있다.
GPU Instancing
동일 메시, 동일 메테리얼 오브젝트들을 하나의 배열에 모아서 GPU에 제공하는 방법으로, Graphics.DrawXXX API를 통해 수동으로 전달할 수 도 있고, 지원가능한 쉐이더의 Inspector를 통해서도 설정이 가능하다.
또 하나의 장점은 MaterialPropertyBlock을 통해 인스턴스별 (오브젝트별) 외형 변화를 줄 수 있다는 것
단점은 메시랑 메테리얼이 모두 같을때만 동작한다는 것과 SkinnedMeshRenderer 미지원 이 있다.
SRP Batcher
비교적 최근에 지원하기 시작한 배칭 방법으로 동일 쉐이더를 사용하되 다른 메테리얼을 쓰는 오브젝트들도 모두 배칭해주기 때문에 범용적으로 쓸 수 있지만, 셰이더 배리언트 에 대해 일정한 규칙을 고수할 경우에만 작동하며, 그 외에도 배칭 조건이 다소 까다롭다.
예를 들어 GPU Instancing의 인스턴스별 외형 변화는 지원하지 않는 것 등..
작동방식은 이전 URP 포스팅에서 다루었으므로 참고하시기 바랍니다.
배칭 우선순위는 SRP Batcher > GPU Instancing > Dynamic Batching 이다.