2015년 8월 30일 일요일

[유니티 최적화 기법] - 텍스처 편


모든 게임이 그렇지만 모바일이라고 예외는 아니다.
결국 리소스의 대부분은 텍스처다.
과거 MMORPG를 만들어서 배포해보면 10G짜리 게임의 5G정도는 텍스처였다. 모바일도 그 상황은 크게 다르지 않다.

PC는 아주 쉬웠다. 우리는 모두 DirectX기반으로 게임을 만들었고, DX가 지원하는 포맷으로 압축하면 끝이었다. 그래서 우리는 모든 텍스처를 DXT로 압축한 것이다.
그 시절에는 DXT1~5까지중에서 뭘 쓸지 고민했다. UI는 주로 Targa를 사용했고 말이다.

모바일에서는 상황이 많이 다르다.
더 이상 DX가 절대 강자가 아니고, OpenGL에 기반하고 있기 때문이다. OpenGL자체가 Open이다보니, GPU칩 제조사가 자기 하기 나름이다. 그래서 압축 포맷도 천차만별이다.

다행인것은 모바일 GPU가 그나마 많지 않아서 총 4가지 정도로 수렴된다는 것이 위안이다.

압축방식
대표GPU
제조사
특징
ETC
Mali
ARM
- ETC1 거의 모든 Android기기가 지원
- ETC1 Alpha 지원되지 않음
ATITC
Adreno
Qualcomm
-
PVRTC
PowerVR
Imagination
- 2^n크기의 정방형 텍스처만 압축가능
- 이에 해당하지 않을 경우 강제로 2^n 크기로 텍스처 변경
- 단, 압축하지 않는 텍스처는 정방형 제한 없음
DXT
Tegra
nvidia
- PC에서 사용된 DXT방식을 그대로 사용가능
- 지원하는 장비를 만나뵙기 힘듬
[표-1] 모바일 GPU의 대표적인 압축방식

[표-1]을 보면 총 4가지 정도의 압축방식이 있는 것을 알 수 있다. 이 중에서 가장 대표적인 것은 ETC방식인데, 안드로이드(이후 AOS)라면 기본적으로 지원하는 방식이기 때문이다. 물론 여기에는 약간의 함정이 있다. 모든 AOS 단말기가 100% ETC1을 지원해야 하겠지만, 가끔 그렇지 않은 물건이 있기 때문이다. 일단, AOS라면 일단 ETC1을 지원하면 거의 대부분의 경우 해결이 된다는 것을 명심해두자.

그런데, 보다시피 ETC1은 ARM에서 제안한 압축포맷인데, 스마트폰 초창기에 많이 사용된 Mali칩에서 지원하는 포맷이다. 최근 시장의 스마트폰 단말기들은 고성능일수록 Adreno계열을 사용한다. 특히 애플은 처음부터 지금까지 꿋꿋하게 PowerVR만을 외길로 고집하고 있다. 이는 중국산 폰과 국산 폰을 살펴보면 극명하게 알 수 있는 사실인데, 중국의 저가폰(태블릿 포함)은 주로 구형 Mali 칩을 사용한다. 그러나, 국내 고급폰은 거의 대부분이 예외없이 Adreno 330(이상) 칩을 사용한다.

요즘 중국에서 만드는 $200~$300의 저가폰과 국내 고가폰의 스펙차이가 거의 없다고 말하는 사람들을 보면 받아들이기 힘들다. 물론 일반인이 봤을때는 그렇게 보이겠지. 하지만 IT전문가라는 사람들조차 그렇게 단언하는 것을 보면 좀 실망스러운 것이 사실이다.

그들이 말하는 거의 차이없다라는 수준이 어떻게 오해받는지 한번 살펴보자.

스펙의 일반적 평가기준은 CPU코어수 , 화면해상도, RAM용량, 내장 메모리용량 정도일 것이다.

문제는 픽셀 필레이트가 떨어지는 저가 GPU칩에 고해상도 2048이상 디스플레이를 달고 나오는 저가폰이 수두룩 하다는 것이다. 게다가, 내장 메모리의 Read/Write속도 역시 분명하게 차이가 난다. 이런 폰에서 게임을 돌리면 초당 30프레임은 커녕 10프레임을 넘기기도 힘들다. 게다가 게임을 로딩할때는 어마어마한 딜레이가 걸린다. 이런 상황에서 최신 중국폰에서 게임이 잘 안돌아가니, 발적화 한것 아니냐고 말하는 사람들을 보면 어이가 없을 뿐이다. 중국산 저가폰에서는 HW사양에 맞춰서 국내폰보다 더 엄청난 최적화를 해야만 원활하게 돌아갈 수 있을 것이다. 폴리곤 깍는 노인이 되는 것도 좋겠지 ㅋ

일반적인 App을 돌릴때는 문제가 안되지만, 게임은 CPU, GPU, Memory, 배터리를 모두 극한수준으로 써먹는 악독한 놈이기 때문에 저가폰과 고가폰이 큰 차이를 보이게 된다.

혹시나 노파심에서 하는 말인데, 국내 대기업제품들도 중국산 저가폰이나 하는 얄팍한 짓을 가끔씩 저지르는 경우가 있다는 것이다. [저가GPU + 고해상도 디스플레이]로 구성된 경우가 없는지 주변의 최신 폰들을 살펴보자. 최근 사내에서 다양한 폰을 테스트하며 경악한 경우가 있었기에 하는 말이다. -_-;

얘기가 잠시 샜는데, GPU마다 고유한 압축포맷이 있고, 이 포맷으로 압축하면 실제 배포되는 데이터의 크기도 줄어들고, 당연히 메모리에 올라갈때도 그 크기 그대로 올라가기 때문에 반드시 압축을 해서 배포해야만 한다.

대략적인 리소스 배포 시스템은 [그림-1]과 같다.
[그림-1] GPU에 최적화된 리소스 다운하기

AOS는 총 4가지 포맷(Adreno, Mali, PowerVR, Tegra)를 지원하는데 반해서 IOS는 PowerVR만을 지원하고 있다. 애플의 일관된 정책은 때때로 개발자에 편안함을 준다. 물론, 대부분의 경우에는 애플 덕분에 피곤한 경우가 더 많지만 말이다.

압축은 유니티의 AssetBundle을 사용하고 있다.
좀 더 정리하자면, 배포될 리소스(AssetBundle)을 빌드할때 GPU에 따른 4가지 버전을 준비해 두고, 클라이언트는 실행될때 GPU를 판독해서 자신의 폰에 최적화된 리소스를 다운받는 방식이다.

여기서 우리가 격었던 황당한 경험 2가지를 기억해보자.

1. ETC1을 지원하지 않는 AOS가 있다.
삼성 갤럭시4 초기모델은 놀랍게도 PowerVR칩을 탑재하고 나왔는데, 이 폰이 ETC1을 지원하지 않는다. 이상하게도 이 모델에서만 메모리가 급증하기에 확인해보니
PowerVR 탑재된 갤4에서 ETC1을 지원하지 않음 → Unity가 ETC1텍스처 압축을 해제함 → 압축해제된 원본 크기의 텍스처가 갤4 메모리에 로드됨

이런 상황이 벌어지고 있었던 것이다. 안드로이드라면 ETC1을 무조건 지원할 것이라 생각하고 개발했는데, 그 덕분에 이러한 상황에 맞닥뜨린 것이다. 처음에는 모든 안드로이드 폰을 ETC1으로 압축하려 하였으나, 이 사건이후로 GPU별로 압축하는 방식을 도입하였다.

2. iPhone 5와 5S는 다르다.
애셋번들을 리소스 서버로부터 요청할때 클라이언트 프로그램은 일단 단말기의 GPU를 판별하게 되는데, 이때 우리는 Unity로부터 전달받은 GPU의 시그니쳐를 사용했다. 문제는 대부분의 경우 정확힌 칩셋명이 날아오기 때문에 별다른 문제가 없었는데, iPhone 5S에서 문제가 생긴 것이다.

iPhone 5까지는 GPU명이 "PowerVR+모델번호"로 날아왔고, 우리는 "PowerVR"이라는 스트링을 기준으로 GPU를 판별한 것이다.

그런데, iPhone 5S는 놀랍게도 "Apple GPU"라는 이름으로 날아오는 것이다. 어디에도 PowerVR이라는 문자열을 찾을 수가 없었다. 이 사건 덕분에 애플제품일 경우에는 무조건 PowerVR로 리소스를 빌드하도록 코드가 수정되었다. 아마도 iPhone 5S이후부터 Metal을 지원하면서 생긴 변화가 아닌가 추측한다.





이것 외에도 다양한 리소스 최적화 기법들이 있겠지만, 일단 처음이니 이정도로 하자. 앞으로 차근차근 더 다양한 방법들에 대해서 알아보도록 하자.




댓글 3개:

피해의식 :

역시 지존이십니다~

dragonjoon :

헉... 과찬입니다. ^^

Unknown :

GPU별로 따로 로드할 AssetBundle을 만드려 하는데, 어떤 식으로 해당 AssetBundle을 뽑으셨나요?
구글링을 이것저것 해보니 EditorUtility.CompressTexture 를 이용해서 에셋번들 뽑는 클래스에서 압축 포맷을 달리해서 뽑으면 될 듯도 싶긴 한데, 사용방법을 잘 모르겠네요.
이 방법이 맞는지 아닌지 모르겠지만, 어떻게 처리하셨는지 여쭤보아도 될까요?

댓글 쓰기