드로우 콜을 줄였는데 느려졌다면
2D 게임이 모바일에서 버벅입니다. 검색하면 첫 줄에 “드로우 콜을 줄이세요” 가 나옵니다. Stats 창을 열어 보니 700 이 넘습니다. 이것저것 손봐서 500 으로 줄였습니다.
그런데 더 느려졌습니다.
이런 일이 실제로 생깁니다. 드로우 콜은 렌더링 비용을 재는 숫자가 아니기 때문입니다. 정확히는, 렌더링 비용을 재는 숫자가 하나가 아니기 때문입니다.
GPU 는 상태 기계다
GPU 에게 “이 사각형을 그려라” 라고만 말하면 아무것도 안 그려집니다. 어떤 텍스처로, 어떤 셰이더로, 어떻게 섞어서, 어디에 그릴지를 전부 먼저 세팅해 줘야 합니다. GPU 는 그렇게 세팅된 상태를 들고 있다가, 그리라고 하면 그 상태 그대로 그립니다.
여기서 두 숫자가 갈립니다.
| 무엇을 세는가 | 언제 늘어나는가 | |
|---|---|---|
| 드로우 콜 | “지금 그려라” 라는 명령 자체 | 그리는 덩어리가 늘어날 때 |
| SetPass Call | 그 앞에 붙는 상태 변경을 묶은 단위 | 앞 오브젝트와 상태가 다를 때 |
같은 상태로 이어서 그릴 수 있으면 드로우 콜만 늘고 SetPass Call 은 안 늡니다. 반대로 오브젝트마다 텍스처가 다르고 셰이더가 다르면 둘이 나란히 늡니다.
그리고 실무에서 더 아픈 쪽은 대개 SetPass Call 입니다. 1번과 2번이 CPU 가 명령을 만들어 드라이버에 넘기는 일이고, 3번은 그에 비하면 짧습니다. 모바일에서 발열의 상당 부분이 여기서 나옵니다.
숫자 두 개를 같이 본 실측
Unity 의 2D 데모 프로젝트인 Happy Harvest 를 Galaxy Tab S7 에서 돌리고 설정 하나만 바꿔서 잰 결과가 있습니다.
드로우 콜은 524 에서 765 로 늘었습니다. 46퍼센트 증가입니다. 그런데 SetPass Call 은 517 에서 300 으로 떨어졌고, 총 CPU 시간은 줄었습니다.
드로우 콜 500 에 SetPass 500 은 재앙이고, 드로우 콜 700 에 SetPass 300 은 그보다 빠릅니다.
앞의 “드로우 콜을 줄였더니 느려졌다” 는 이 표의 화살표를 거꾸로 밟은 것입니다. 메시를 합치느라 CPU 를 더 쓰면서 드로우 콜 숫자만 예뻐진 상태입니다.
그래서 무엇을 봐야 하나
Stats 창에서 두 숫자를 같이 봅니다. 그리고 비율을 봅니다.
- SetPass 가 드로우 콜에 거의 붙어 있다 → 오브젝트마다 상태가 다르다는 뜻입니다. 텍스처와 셰이더를 합칠 여지가 남아 있습니다
- SetPass 가 드로우 콜의 절반 이하다 → 상태가 잘 이어지고 있습니다. 이때부터는 드로우 콜을 더 줄여도 얻는 게 적습니다
- 둘 다 낮은데 여전히 느리다 → CPU 문제가 아닙니다. 픽셀을 칠하는 쪽, 즉 GPU 를 봐야 합니다
마지막 줄이 2D 에서 특히 중요합니다. 2D 는 반투명 스프라이트가 겹겹이 쌓이는 구조라 같은 픽셀을 여러 번 칠하는 일이 흔하고, 그건 드로우 콜을 아무리 줄여도 안 줄어듭니다.
이 시리즈가 갈 길
정리하면 프레임을 먹는 자리가 크게 둘입니다.
| 무엇이 비싼가 | 무엇으로 줄이는가 | |
|---|---|---|
| CPU | 명령을 만들어 넘기는 시간 | 배칭, 아틀라스, 셰이더 통일 |
| GPU | 픽셀을 칠하는 시간 | 오버드로우 줄이기, 라이트 수, 해상도 |
이 둘을 섞어서 이야기하면 답이 안 나옵니다. “라이트를 줄이면 배칭이 좋아진다” 같은 말이 절반만 맞는 이유가 그것입니다. 라이트 배칭은 CPU 쪽이고 라이트 버퍼와 그림자는 GPU 쪽이라, 같은 설정 하나가 두 축을 동시에 건드립니다.
그러니 무엇을 고치든 어느 쪽 숫자가 움직였는지 확인하면서 가야 합니다.