2013년 10월 17일 목요일

성능 좋고 효율 좋은 하드웨어 스케일러 사용하기

안드로이드 개발자 관계 팀(Android Developer Relations Team) 하크 마츠다(Hak Matsuda)와 더크 더퍼티(Dirk Dougherty) 작성
원문: Using the Hardware Scaler for Performance and Efficiency

성능이 중요한 3D 게임을 만든다면 항상 사용자에게 더 나은 그래픽, 높은 프레임율(frame rate, 주: 초당 그려야하는 화면(프레임)의 갯수), 나은 반응성을 제공할 방법을 찾게됩니다. 또 플레이 중에 사용자의 배터리를 아끼고 단말기가 뜨거워지는 것을 막고 싶을 겁니다. 이 모든 영역을 최적화하는 것을 보조하기 위해 오늘날 마켓에 있는 거의 대부분의 단말기가 지원하는 하드웨어 스케일러의 이점을 고려해봅시다.

어떻게 동작하고 왜 이것을 써야 하는가? 


사실 현대적인 안드로이드 단말기들은 하드웨어 비디오 스케일러를 가진 CPU/GPU 칩셋을 사용합니다. 안드로이드는 높은 수준의 통합을 제공하며 이는 앱이 안드로이드 표준 API를 사용하여 자바나 네이티브 (C++) 코드에서 사용할 수 있습니다. 하드웨어 스케일러가 가져오는 이점은 시스템이 제공하는 단말기의 전체 크기 해상도에 맞추어진 기본 버퍼들 대신에  고정된 사이즈의 그래픽 버퍼에 그리기만 하면 된다는 것입니다.

고정 크기 버퍼에 그리면 단말 하드웨어는 여러분의 화면을 단말의 해상도에 맞추어 키우거나 줄이고 비율에 맞추어 조정하죠. 일반적으로 단말의 전체 해상도 보다 작은 고정 크기 버퍼를 생성할 수 있는데 이는 더 효과적으로 그려집니다. 특히 오늘날의 고해상도 화면에서요.

하드웨어 스케일러를 쓰는 것은 몇가지 이유에서 더 효과적입니다. 첫째로, 하드웨어 스케일러는 매우 빠르며, 멀티탭(주: 한번에 여러 픽셀을 이용하여 보정된 확대나 축소를 하는 것)와 아티팩츠(주: 자연에서 발생하지 않는 인공적인 어색한 현상. 그림자가 반짝거리는 것 등)를 감소하는 알고리즘을 사용하여 훌륭한 시각적인 결과를 만들어냅니다. 둘째로, 앱이 적은 크기의 버퍼에 그릴 수 있기 때문에 GPU에서 연산양은 줄어들고 성능이 향상됩니다.셋째로, 계산할 작업이 줄어든 결과로 GPU는 더 시원하게 돌 수 있고 배터리를 덜 사용합니다. 마지막으로, 원하는 크기의 그리기 버퍼를 사용할 수 있기 때문에 실제 화면 해상도와 상관없이 모든 디바이스에서 동일하게 쓸 수 있습니다.

채움율 최적화


휴대 장비의 GPU에서 화소 채움율(pixel fill rate, 주: 초당 그리는 점의 갯수)은 고성능 게임 앱의 성능 문제에서 가장 중요한 것 중의 하나입니다. 새로운 폰과 타블렛은 점점 높은 해상도를 제공하고, 이런 단말에서 2D, 3D 그래픽을 그리는 것은 채움율을 눈에 띄게 낮출 수 있습니다. GPU가 화면에 최대로 화소를 채우고 있음에도 불구하고 더 많이 채워야 한다면 프레임율이 떨어집니다.

다양한 칩에서 해상도에 따라 달라지는 전력 소모량
(퀄컴 제공)
이 병목 현상을 해치우기 위해, 매 프레임에 그리는 화소의 수를 줄여야 합니다. 이를 달성할 방법은 다양합니다. 그 중 하나는 깊이 전 단계(depth prepass, 주: 아래에 있는 그림을 애당초 그리지 않게 배제하는 것)등을 이용하는 것입니다. 하지만 정말 간단하고 효과적인 방법은 하드웨어 스케일러를 이용하는 거죠.

2560x1600 만큼 큰 전체 사이즈 버퍼에 그리는 거 대신에, 조금 더 작은 버퍼에 그릴 수 있습니다. 예를 들면 1280x720이나 1920x1080에 그리는 거죠. 하드웨어 스케일러는 어떤 추가 비용이나 시각적인 품질에서 적은 손실도 없이 장면을 확대할 수 있습니다.

전력 소모와 발열 감소하기


고성능 게임은 배터리를 많이 소모하고 발열이 심할 수 있습니다. 게임의 전력 소모와 발열 상태는 사용자에게 중요하기 때문에 개발자에게 꽤 중요한 고려점이 됩니다.

도표에서 보듯, 단말 GPU의 전력소모는 그리는 해상도가 커질 수록 의미있게 증가합니다. 많은 경우 GPU에서 많이 전력을 소모하는 것은 단말의 배터리 수명의 감소로 이어집니다.

추가로 CPU/GPU의 그리기가 많아질 수록 단말을 잡기 불편할 정도로 열이 발생합니다. 열이 발생하면 CPU/GPU를 시원하게 만들기 위해 GPU/GPU 속도를 조절하기도 합니다. 이는 게임에서 사용가능한 프로세스 파워를 줄이게 됩니다.

전력 소모와 발열 현상을 줄이기 위해 하드웨어 스케일러를 사용하는 것이 중요합니다. 적은 버퍼에 그리기 때문에 GPU는 그리는 동안 에너지를 덜 쓰고 열을 덜 냅니다.

안드로이드 API에서 하드웨어 스케일러 접근하기


안드로이드는 자바 코드나, 안드로이드 NDK를 통한 네이티브 (C++) 코드에서 표준 API를 사용하여 하드웨어 스케일러에 쉽게 접근할 수 있습니다.

해야할 일은 API를 사용하여 고정 크기 버퍼를 만들고 여기에 그리는 것입니다. 실제 단말기의 해상도도 고려할 필요가 없습니다. 원래 비율을 지키고 싶다면 화면에서 사용되는 버퍼와 비율을 맞추거나 버퍼에 그리는 것을 조절하면 됩니다.

자바 코드에서 스케일러를 다루는 것은 API 레벨 1에서 도입된 SurfaceView를 통하면 됩니다. 1280x720 해상도의 고정 크기 버퍼를 만드는 것은 다음과 같습니다.
surfaceView = new GLSurfaceView(this);
surfaceView.getHolder().setFixedSize(1280, 720);
네이티브 코드에서 스케일러를 사용하고 싶다면 안드로이드 2.3 (API 레벨 9)에서 소개된 NativeActivity를 사용할 수 있습니다. NativeActivity에서 1280x720 해상도의 고정 크기 버퍼를 사용하는 법은 여기에 있습니다.
int32_t ret = ANativeWindow_setBuffersGeometry(window, 1280, 720, 0);
버퍼의 크기를 정하면 하드웨어 스케일러는 활성화되고 특정 윈도우에 그리는 것에 이점이 생깁니다.

그래픽 버퍼 크기를 고르기


고정 크기의 그래픽 버퍼를 사용하면 목표 단말에서의 시각 품질과 성능, 효율 확보 사이에서 균형있는 크기를 선택하는 것이 중요합니다.

대부분의 고성능 3D 게임은 하드웨어 스케일러를 사용합니다. 추천하는 크기는 1080p(주: 세로 화소의 갯수가 1080)에 그리는 것입니다. 1080p는 시각 품질, 프레임율, 전력 소모에서 아름다운 지점입니다. 물론 720p에 만족한다면 더 효율적인 연산을 위해 이사이즈를 선택할 수 있습니다.

더 많은 정보


앱에서 하드웨어 스케일러의 이점을 원한다면 안드로이드 프레임워크나 네이티브 API를 사용하여 그리는지 여부에 따라 SurfaceViewNatieActivity 문서 클래스를 보세요.

곧 나올 하드웨어 스케일러를 사용하는 견본 코드도 참고하세요!