Unity와 Arm으로 모바일 게임 프로파일링 문제 해결하기

MARK HARKNESS / UNITY TECHNOLOGIESSenior Software Engineer
Mar 11, 2021|11 분
Unity와 Arm으로 모바일 게임 프로파일링 문제 해결하기
이 웹페이지는 이해를 돕기 위해 기계 번역으로 제공됩니다. 기계 번역으로 제공되는 콘텐츠에 대한 정확도나 신뢰도는 보장되지 않습니다. 번역된 콘텐츠의 정확도에 관해 의문이 있는 경우 웹페이지의 공식 영어 원문을 참고해 주시기 바랍니다.

Unity와 Arm의 프로파일링 툴로 모바일 성능 문제를 해결하는 방법을 알아보세요. Unity로 프로파일링하는 방법, 성능 저하를 최적화하는 방법, 게임 에셋을 최대한 활용하는 팁과 요령에 대해 자세히 알아보세요.

이 블로그에서는 Unity와 Arm의 프로파일링 툴을 사용하여 모바일 게임의 성능 문제를 파악하는 방법을 살펴봅니다. 모바일 게임 콘텐츠 최적화를 위한 모범 사례도 소개합니다.

게임의 성능 문제를 파악하려면 먼저 다양한 기기에서 게임을 테스트해야 합니다. 이를 수행하는 가장 좋은 방법은 실제 디바이스에서 성능 프로필을 캡처하는 것입니다. Unity 프로파일러프레임 디버거와 같은 툴을 사용하면 게임 요소의 리소스가 어디에서 사용되는지 파악할 수 있습니다. 또한 Arm 모바일 스튜디오와 같은 툴을 사용하면 디바이스에서 성능 카운터 활동 데이터를 캡처할 수 있으므로 게임에서 CPU와 GPU 리소스를 어떻게 사용하는지 정확히 확인할 수 있습니다. 저희가 사용한 기기에는 Mali GPU가 탑재되어 있지만, 여기에 소개된 개념은 다른 모바일 GPU에도 적용됩니다.

테스트 예제

테스트 중인 게임은 액션 RPG로, 플레이어는 근접 공격과 마법 공격으로 밀려오는 적 NPC의 파도에 맞서 싸워야 합니다. 이러한 유형의 게임은 화면에 등장하는 적의 수가 늘어나고 파티클 및 포스트 프로세싱 시각 효과가 많아지면서 모바일 기기에서 빠르게 GPU에 바인딩될 수 있습니다.

Unity 프로파일러 및 프레임 디버거를 사용한 프로파일링

유니티 프로파일러를 통해 게임을 실행하여 성능 저하를 확인했습니다. 우선순위가 높은 몇 가지 의심스러운 후처리 문제를 발견하고 타임스텝 및 인스턴스화 스파이크를 수정했습니다.

포스트 프로세싱

포스트 프로세싱 효과는 게임의 CPU 성능 저하의 주요 원인이었습니다.

렌더 카메라가 엄청난 시간이 걸리고 프레임 경계를 넘습니다.
렌더 카메라가 엄청난 시간이 걸리고 프레임 경계를 넘습니다.

모든 포스트 프로세싱 효과 중에서 씬의 밝은 부분을 빛나게 하는 블룸 패스가 가장 힘들었습니다.

위의 스크린샷에서 렌더 카메라가 엄청난 시간이 걸리고 프레임 경계를 넘나드는 것을 볼 수 있습니다. 그러면 메인 스레드는 렌더링 명령이 완료될 때까지 기다렸다가 다음 프레임을 준비합니다. Unity 프레임 디버거를 통해 무슨 일이 일어나고 있는지 알아보세요.

디바이스에서 전체 화면 해상도로 프레임 디버거 보기
디바이스에서 전체 화면 해상도로 프레임 디버거 보기

프레임 디버거에서 가장 먼저 눈에 띄는 것은 게임이 디바이스의 전체 화면 해상도로 렌더링되고 있다는 점입니다. 일반 모바일 디바이스의 경우 콘텐츠의 복잡성을 고려할 때 디바이스의 GPU에 과도한 부담을 줄 수 있습니다. 해상도를 1080p 또는 720p와 같이 더 합리적인 수준으로 낮추면 게임 렌더링 비용, 특히 포스트 프로세싱 효과를 크게 줄일 수 있습니다.

추첨을 보려면 블룸 피라미드가 필요합니다.
추첨을 보려면 블룸 피라미드가 필요합니다.

다음 관찰 포인트는 블룸 피라미드에 대한 25번의 추첨 호출에서 블룸 효과가 발생한다는 것입니다. 각 그리기 호출은 전체 화면 디바이스 해상도의 절반부터 시작하는 크기의 타겟 버퍼를 나타냅니다. 그런 다음 이 해상도는 반복할 때마다 절반으로 줄어듭니다. 초기 렌더링 해상도를 낮추는 것은 잠재적인 반복 횟수를 줄이는 한 가지 방법입니다. 또 다른 대안은 블룸 이펙트 소스 코드를 수정하여 반복 횟수를 줄이고 합리적인 제한을 두는 것입니다. 그러나 이 경우 후처리 효과를 처리하는 데 상당한 시간이 걸리므로 지금은 후처리 효과를 비활성화하는 것이 좋습니다. 즉, 적어도 나머지 게임이 초당 30프레임으로 원활하게 실행될 수 있을 때까지입니다.

고정 시간 간격

프로젝트의 또 다른 개선 사항은 고정된 타임스텝 간격의 빈도를 줄이는 것입니다. 현재 한 프레임에 여러 번 호출할 수 있을 만큼 짧다는 것을 알 수 있으며, 기본적으로 Unity는 이를 0.02 또는 50Hz로 설정합니다. 30fps를 목표로 하는 모바일 타이틀의 경우 타임스텝 값을 0.04로 고정해 볼 수 있습니다. 그 이유는 30fps에 해당하는 0.333에서는 한 프레임이 급상승하여 다음 프레임에서 두 번의 호출이 발생할 가능성이 있기 때문입니다. 즉, 시간이 더 오래 걸리고 프레임이 약간 더 길어지는 사이클을 절대 깰 수 없습니다. 또한 사용자는 최대 허용 시간 간격을 설정하여 원하는 시간보다 더 많은 시간이 소요되는 것을 방지할 수 있습니다.

이 타임스텝 기간은 고정 업데이트 함수를 사용하는 스크립트 및 고정 업데이트 간격으로 업데이트하는 모든 Unity 내부 시스템(예: 피직스 및 애니메이션)에 영향을 줍니다.

고정 타임스텝을 사용하는 타임라인
고정 타임스텝을 사용하는 타임라인

이 프로젝트에서는 피직스와 시네머신만 호출당 약 3밀리초의 시간이 소요되었으며, 이는 시스템이 완전히 업데이트되었음을 의미합니다(추가로 5번 호출하면 프레임당 최대 15밀리초의 시간 낭비가 발생할 수 있음).

후처리 효과로 인해 느려진 FixedUpdate.PhysicsFixedUpdate.
후처리 효과로 인해 느려진 FixedUpdate.PhysicsFixedUpdate.

이는 느린 후처리 효과로 인해 발생합니다. 이 기능을 끄면 소요 시간이 줄어들지만, CPU의 불필요한 작업을 피하기 위해 고정된 타임스텝 빈도를 줄이라는 이전 권장 사항은 여전히 유효합니다.

인스턴스화 급증

프로파일링 중에 프레임 시간에서 스파이크를 볼 수 있습니다. CPU 프로파일러 계층 구조 뷰에서 이를 추적해 보면 NPC 인스턴스화에서 비롯된 것으로 나타났습니다.

CPU 프로파일러 계층 구조에서 인스턴스화 스파이크 추적하기
CPU 프로파일러 계층 구조에서 인스턴스화 스파이크 추적하기

이를 위한 가장 일반적인 해결책은 캐릭터를 미리 인스턴스화하여 일종의 오브젝트 풀에 유휴 상태로 유지하는 것입니다. 그런 다음 이러한 NPC는 인스턴스화 비용 없이 풀에서 가져올 수 있습니다. 더 필요한 경우 필요에 따라 풀을 확장할 수 있습니다.

어빌리티도 객체를 인스턴스화하는 것이므로 어빌리티를 사용할 때도 동일한 문제가 발생합니다.

CPU 인스턴스화 급증
CPU 인스턴스화 급증

오브젝트 풀링은 이러한 문제를 해결하는 가장 쉬운 방법입니다. 로딩 시간에 영향을 줄 수 있지만 런타임에 프레임 속도가 훨씬 부드러워지므로 이 경우에는 두 가지 악 중 덜 나쁜 경우입니다.

Arm 모바일 스튜디오를 사용한 프로파일링

또한, 게임 동작에 대한 더 많은 인사이트를 얻기 위해 Arm 모바일 스튜디오를 사용했습니다. 모바일 스튜디오의 툴을 사용하면 CPU와 GPU의 성능 역효과 데이터를 얻을 수 있으므로 게임이 디바이스의 리소스를 어떻게 사용하는지 정확히 확인할 수 있습니다.

여기에서 Arm 모바일 스튜디오를 무료로 다운로드할 수 있습니다. 4가지 도구가 포함되어 있습니다:

  • 성능 관리자 - 읽기 쉬운 보고서를 생성하고 최적화 조언을 얻을 수 있습니다.
  • Streamline - 모든 카운터 활동을 캡처하는 포괄적인 성능 프로파일러
  • 말리 오프라인 컴파일러 - 셰이더 프로그램이 말리 GPU에서 어떻게 작동하는지 확인합니다.
  • 그래픽 분석기 - 그래픽 API 호출을 디버깅하고 콘텐츠가 렌더링된 방식을 분석합니다.
성능 관리자

성능 어드바이저는 게임 성능에 대한 간략한 요약을 제공하며, 정기적인 상태 점검을 위해 사용됩니다. 특히 야간 빌드 시스템과 함께 지속적 통합 워크플로에 보고서를 빌드하는 경우 보고서를 빠르게 생성할 수 있습니다. 성능 어드바이저는 게임 성능에 대한 간략한 요약을 제공하며, 정기적인 상태 점검을 위해 사용됩니다. 특히 야간 빌드 시스템과 함께 지속적 통합 워크플로에 보고서를 빌드하는 경우 보고서를 빠르게 생성할 수 있습니다.

성능 관리자 - 캡처 요약
성능 관리자 - 캡처 요약

게임 초반 2분 동안 성능 어드바이저는 초당 평균 프레임이 17프레임에 불과하다고 알려줍니다. 프레임 속도 분석 차트의 시작 부분의 녹색 부분은 게임이 로딩 중인 위치를 나타내다가 갑자기 차트가 파란색으로 바뀌면서 게임이 프래그먼트 바인딩되었음을 나타내며, 이 상태가 계속 유지됩니다. 이는 기기의 GPU가 조각 워크로드를 처리하는 데 어려움을 겪고 있다는 의미로, 게임이 너무 많은 작업을 요청하거나 픽셀을 효율적으로 처리하지 못하고 있음을 나타냅니다.

게임에 지역 주석을 추가했으므로 프레임 속도 분석 차트에 커스텀 지역 이름이 표시됩니다. 차트에 'S'로 표시된 마커가 있는 경우, Performance Advisor에서 해당 시점의 화면에서 어떤 일이 일어나고 있는지 파악할 수 있도록 게임 스크린샷을 찍어둔 것입니다. 초당 프레임 수가 지정된 값 아래로 떨어질 때 화면 캡처를 수행하도록 설정할 수 있습니다. 여기에서는 fps가 전체적으로 낮게 유지되므로 성능 관리자가 기본 간격인 200프레임마다 스크린샷을 찍습니다.

프레임당 GPU 사이클 차트를 살펴보면, 이 디바이스에 대해 프레임당 2,800만 사이클의 예산이 추가되어 있습니다. 이 디바이스가 30fps의 프레임 속도를 유지하면서 처리할 수 있는 최대 사이클 수는 이 정도입니다. 여기에서 GPU 사이클 수가 이 예산을 크게 초과하고 시간이 지남에 따라 사이클 수가 증가하는 것을 볼 수 있습니다.

성능 관리자 - 프레임당 GPU 주기
성능 관리자 - 프레임당 GPU 주기

성능 관리자가 문제를 발견하면 최적화 조언을 제공합니다. 프레임당 셰이더 사이클 차트를 보면 실행 엔진 사이클 수가 많다는 것을 알 수 있습니다. 말리 셰이더 코어 내부에서 실행 엔진은 산술 연산을 처리합니다. 퍼포먼스 어드바이저는 이를 문제로 표시하고 셰이더의 계산을 줄이라고 조언했습니다.

퍼포먼스 어드바이저 - 프레임당 셰이더 주기
퍼포먼스 어드바이저 - 프레임당 셰이더 주기

이에 대한 간단한 해결 방법이 있습니다. 셰이더 변수의 정밀도를 높은 수준이 아닌 중간 수준으로 낮추면 화면에서 눈에 띄는 변화 없이 사용할 수 있습니다. 이렇게 하면 셰이더 비용을 크게 줄일 수 있습니다. 이 작업에 대한 자세한 내용은 셰이더 데이터 유형 및 정밀도 문서를 참조하세요. 또한 앞서 Unity의 프레임 디버거를 통해 확인했듯이 게임은 현재 기기의 전체 화면 해상도로 렌더링되고 있습니다. 게임의 렌더링 해상도를 1080p 또는 720p로 낮추기 위해 변경하면 조각 셰이딩 비용도 감소합니다.

콘텐츠 지표

이 디바이스의 예산은 프레임당 500,000개의 버텍스로 설정했습니다. 45초 정도 지나면 예산이 초과되고 시간이 지남에 따라 그 수가 꾸준히 증가합니다.

성능 어드바이저 - 프레임당 버텍스
성능 어드바이저 - 프레임당 버텍스

프레임당 프리미티브 차트를 보면 보이는 프리미티브의 수는 상대적으로 일정하게 유지되지만 처리되는 프리미티브의 총 수는 시간이 지남에 따라 증가하는 것을 알 수 있습니다. 게임 시작 후 처음 2분 동안 생성되는 유일한 새로운 물체는 적 NPC이며, 이 NPC는 영웅의 번개에 의해 파괴됩니다. 이는 적을 파괴해도 적의 지오메트리가 눈에 보이지는 않지만 여전히 존재한다는 것을 의미합니다.

성능 어드바이저 - 프레임당 프리미티브
성능 어드바이저 - 프레임당 프리미티브

GPU가 게임의 요구 사항을 처리하지 못하는 데에는 몇 가지 이유가 있으므로 Streamline를 통해 Arm의 프로파일링 툴을 자세히 살펴볼 필요가 있습니다. Streamline는 이 무거운 조각 워크로드에 대해 자세히 알려주며, 다른 카운터를 살펴보면 부하를 줄이는 방법에 대한 단서를 찾을 수 있습니다.

분석 간소화

Streamline에서 게임의 동일한 섹션을 살펴보면 지오메트리 및 픽셀 처리의 다양한 단계에 대한 GPU 카운터 활동을 보여주는 다양한 차트를 살펴볼 수 있습니다. 이는 게임 콘텐츠가 GPU에서 처리되는 방식과 불필요한 처리가 있는지 여부를 보여줍니다.

말리 기반 GPU는 화면 공간을 타일로 분할하고 각 타일이 순서대로 완료될 때까지 처리하는 타일 기반 그래픽 워크로드 처리 방식을 취합니다. 각 타일에 대해 지오메트리 처리가 먼저 실행된 다음 픽셀 처리 중에 픽셀에 색을 입힙니다.

그래픽 워크로드를 처리하는 말리 기반 GPU
그래픽 워크로드를 처리하는 말리 기반 GPU

이미 디바이스의 GPU가 조각 워크로드로 인해 최대치에 도달했다는 것을 알고 있으므로 픽셀 처리 단계의 부담을 줄일 수 있는 방법을 찾아야 합니다.

픽셀 처리 부하를 줄이는 한 가지 방법은 애초에 픽셀 처리를 위해 전송되는 지오메트리의 복잡도를 낮추는 것입니다. 완전히 화면에서 벗어나거나 뒷면에 있는 지오메트리는 픽셀 처리 전에 죽지만, 2×2 픽셀 쿼드를 부분적으로만 덮는 작은 삼각형은 조각 효율을 떨어뜨리고 출력 픽셀당 높은 대역폭 비용을 초래할 수 있습니다.

Streamline의 말리 지오메트리 사용량말리 지오메트리 컬링 비율 차트는 GPU가 지오메트리를 얼마나 효율적으로 처리하는지 보여줍니다. GPU로 전송되는 프리미티브의 수와 지오메트리 처리 중에 컬링되는 프리미티브의 수를 확인할 수 있습니다. 이 단계에서 컬링된 작업은 픽셀 처리 단계로 넘어가지 않습니다. 이는 좋은 소식이지만, 보이지 않는 기본 요소가 전혀 전달되지 않도록 콘텐츠를 더 효율적으로 구성할 수 있습니다.

스트림라인의 말리 지오메트리 사용량 및 말리 지오메트리 컬링 비율 차트
스트림라인의 말리 지오메트리 사용량 및 말리 지오메트리 컬링 비율 차트

말리 지오메트리 사용량 차트에서 , 107만 개의 프리미티브가 선택한 시간(약 0.05초) 동안 지오메트리 처리(주황색 선)에 들어가지만 이 단계에서 70만 개의 프리미티브가 컬링되는 것을 볼 수 있습니다(빨간색 선).

말리 지오메트리 도태율 차트는 말리 지오메트리가 도태되는 이유를 보여줍니다. 페이싱 테스트(주황색 선)에 의해 약 절반이 컬링되는데, 이는 3D 오브젝트의 뒷면을 향한 삼각형이므로 예상되는 결과입니다. 더 우려스러운 점은 샘플 테스트에서 31.9%의 프리미티브가 도태된다는 것입니다(보라색 선). 이상적으로는 이 수치가 5% 미만이어야 합니다. 샘플 테스트는 이러한 프리미티브가 너무 작아서 래스터화할 수 없고, 단일 샘플 포인트에 도달하지 못하여 보이지 않는 것으로 간주되었음을 나타냅니다. 복잡한 메시를 가진 오브젝트가 카메라에서 멀리 떨어져 있고 메시의 삼각형이 너무 작아 보이지 않을 때 이런 문제가 발생할 수 있습니다. 숫자가 높을수록 게임 오브젝트 메시가 화면상의 위치에 비해 너무 복잡하다는 의미일 수 있습니다.

이 문제는 샘플 테스트를 통과할 만큼 충분히 크지만 여전히 몇 픽셀만 커버하는 프리미티브의 경우 더욱 심각해집니다. 이러한 '마이크로 트라이앵글'은 픽셀 처리로 전달되며 처리 비용이 많이 듭니다. 이는 프래그먼트 셰이딩 중에 삼각형이 쿼드라고 하는 2×2 픽셀 패치로 래스터화되기 때문입니다. 작은 삼각형은 쿼드 내부의 픽셀 하위 집합에만 닿지만 처리를 위해 전체 쿼드를 보내야 합니다. 즉, 프래그먼트 셰이더가 하드웨어의 유휴 레인을 사용하여 실행되므로 셰이더 실행 효율이 떨어집니다.

쿼드 내부의 픽셀 하위 집합에 닿는 작은 삼각형
쿼드 내부의 픽셀 하위 집합에 닿는 작은 삼각형

마이크로트라이앵글에 문제가 있는지 확인하려면 Streamline의 Mali 코어 워크로드 속성 차트를 사용하여 커버리지의 효율성을 모니터링할 수 있습니다. 이상적으로는 10% 미만이어야 합니다. 일부 구간에서는 부분 커버리지 비율(녹색 선)이 70% 이상으로 매우 높다는 것을 알 수 있습니다. 이 값은 콘텐츠에 마이크로트라이앵글의 밀도가 높다는 것을 의미하며, 이는 앞서 높은 샘플 컬링률로 인해 지적된 문제를 확인시켜 줍니다.

말리 핵심 워크로드 속성 차트
말리 핵심 워크로드 속성 차트

화면에 표시되는 지오메트리는 해당 위치에 맞는 적절한 크기를 지정해야 합니다. 멀리 떨어져 있는 복잡한 풍경은 장면에 크게 기여하지 않으므로 매우 세밀하게 묘사할 필요가 없습니다. 카메라에서 멀리 떨어진 오브젝트에 LOD(레벨 오브 디테일) 메시를사용하여 복잡성을 줄이고 처리 능력과 DRAM 대역폭을 절약할 수 있습니다. 또는 지오메트리 대신 텍스처와 노멀 맵을 사용하여 오브젝트의 표면 디테일을 구축할 수도 있습니다.

셰이더 분석

퍼포먼스 어드바이저 보고서를 통해 저희는 셰이더가 너무 비싸고 정밀도를 낮추면 이점을 얻을 수 있다는 사실을 발견했습니다. Streamline에서 말리 가변 사용량 차트를 사용하여 32비트(고정밀) 또는 16비트(중간 정밀) 보간이 활성화된 사이클 수를 확인할 수 있습니다. 여기에서 대부분의 주기에서 32비트 보간이 사용되는 것을 볼 수 있습니다. 16비트 변수는 32비트 변수보다 두 배 빠르게 보간하고 셰이더 레지스터의 절반 공간을 사용하여 보간 결과를 저장하므로 가능하면 중간값(16비트)의 다양한 입력을 사용하여 셰이더를 조각화하는 것이 좋습니다.

말리 다양한 사용량 차트
말리 다양한 사용량 차트
말리 오프라인 컴파일러를 사용한 셰이더 분석

셰이더를 탐색하려면 Arm 모바일 스튜디오의 정적 오프라인 컴파일러 툴을 사용하여 셰이더 프로그램에 대한 빠른 분석을 생성할 수 있습니다.

이렇게 하려면 Unity가 제공하는 컴파일된 파일에서 셰이더 코드를 가져온 다음 해당 파일에서 Mali 오프라인 컴파일러를 실행해야 합니다:

1. Unity에서 에셋 폴더에서 직접 분석하려는 셰이더를 선택하거나 머티리얼을 선택하고 톱니바퀴 아이콘을 클릭한 다음 셰이더 선택을 선택합니다.

2. 인스펙터에서 코드 컴파일 및 표시를 선택합니다. 컴파일된 셰이더 코드가 기본 코드 에디터에서 열립니다. 이 파일에는 여러 셰이더 코드 변형이 포함되어 있습니다.

3. 이 파일의 버텍스 또는 프래그먼트 셰이더 변형을 새 파일에 복사하고 확장자를.vert 또는 .frag로 지정합니다. 버텍스 셰이더는 #ifdef VERTEX로 시작하고 프래그먼트 셰이더는 #ifdef FRAGMENT로 시작합니다. 각각의 #ENDIF로 끝납니다. (새 파일에 #ifdef 및 #endif 문을 포함하지 마세요).

4. 명령 터미널에서 이 파일에서 Mali 오프라인 컴파일러를 실행하고 테스트할 GPU를 지정합니다. 예: malioc -c Mali-G72 myshader.frag 자세한 지침은 Mali 오프라인 컴파일러 시작하기를 참조하세요.

적 NPC가 사망할 때 발생하는 디졸브 이펙트를 담당한 조각 셰이더를 분석하기로 했습니다. 다음은 Mali 오프라인 컴파일러 보고서의 관심 섹션을 강조 표시한 내용입니다:

말리 오프라인 컴파일러 보고서

16비트 정밀도에서 산술 연산이 효율적으로 수행되는 비율은 2%에 불과하다는 것을 알 수 있습니다. 정밀도를 높음에서 중간으로 낮추면 셰이더가 더 효율적으로 작동합니다. 이렇게 하면 에너지 소비와 레지스터 압력이 모두 감소하고 성능이 두 배로 향상될 수 있습니다. 위치 및 깊이 계산과 같이 항상 높은 정밀도가 필요한 상황도 있지만, 대부분의 경우 정밀도를 중간 정밀도로 낮춰도 화면에서 눈에 띄는 차이가 거의 없습니다.

이 보고서는 말리 셰이더 코어의 주요 기능 유닛에 대한 대략적인 사이클 비용 분석을 제공합니다. 여기서 산술 단위가 가장 많이 사용되는 것을 볼 수 있습니다.

셰이더 속성 섹션에서 이 셰이더에는 리터럴 상수 또는 균일 값에만 의존하는 균일 계산이 포함되어 있음을 알 수 있습니다. 이렇게 하면 그리기 호출 또는 계산 디스패치의 모든 스레드에 대해 동일한 결과가 생성됩니다. 이상적으로는 이러한 종류의 균일한 계산은 CPU의 애플리케이션 로직으로 옮겨야 합니다.

또한 셰이더가 각 픽셀의 어떤 샘플 포인트가 조각에 포함되는지 결정하는 조각 커버리지 마스크를 수정하여 알파 임계값 아래로 조각을 떨어뜨리는 디스워드 문을 사용할 수 있음을 알 수 있습니다. 수정 가능한 커버리지가 있는 셰이더는 후기 ZS 업데이트를 사용해야 하므로 초기 ZS 테스트의 효율성과 동일한 좌표에서 이후 프래그먼트에 대한 프래그먼트 스케줄링이 저하될 수 있습니다. 가능하면 조각 셰이더에서 디스워드 문과 알파 투 커버리지 사용을 최소화해야 합니다. 삭제 문 사용에 대한 조언은 Arm 말리 모범 사례 가이드를 참조하세요.

그래픽 분석기를 사용한 그래픽 API 호출 분석

Arm 모바일 스튜디오의 그래픽스 분석기에서는 애플리케이션이 수행한 모든 그래픽스 API 호출을 확인하고 하나씩 단계별로 살펴보면서 씬이 어떻게 빌드되는지 확인할 수 있습니다. 이렇게 하면 화면 크기와 카메라로부터의 거리에 비해 너무 복잡한 물체를 식별하는 데 도움이 됩니다. 다음은 이 게임에서 찾은 몇 가지 예시입니다:

씬의 맨 구석에 있는 벽돌은 지오메트리로 제작되었으며 2064개의 버텍스를 사용합니다. 최종 결과물에서 디테일이 잘 드러나지 않으므로 처리 시간이 낭비됩니다.

2064 버텍스의 브릭워크 샘플
2064 버텍스의 브릭워크 샘플

바닥 타일에서도 동일한 문제를 발견했습니다. 각각 1170개의 버텍스가 있지만 오브젝트가 카메라에 가까이 있어도 씬이 복잡해져서 실제로 이점을 얻지 못합니다. 여기서는 삼각형으로 만드는 것보다 노멀 맵을 사용하여 범프와 각진 모서리를 표현하는 것이 더 효율적입니다. 또한 이러한 객체가 별도의 그리기 호출을 사용하여 그려지는 것을 볼 수 있습니다. 오브젝트를 일괄 처리하거나 오브젝트 인스턴싱을 사용하여 드로우 호출 횟수를 줄이면 성능이 향상될 수 있습니다.

1170 버텍스의 바닥 타일 샘플
1170 버텍스의 바닥 타일 샘플

또 다른 예로 장면 뒤쪽의 동상을 들 수 있는데, 각각 6966개의 버텍스가 있습니다. 메시가 상당히 복잡해서 플레이어가 조각상에 가까이 다가가면 시각적으로 멋진 결과를 얻을 수 있지만, 이 카메라 위치에서는 거의 눈에 띄지 않습니다. 카메라에서 이렇게 멀리 떨어져 있는 오브젝트를 표현하기 위해 메시 LOD를 사용하면 처리 능력을 크게 절약할 수 있습니다.

6966 버텍스의 동상 샘플
6966 버텍스의 동상 샘플

많은 유사한 오브젝트의 복잡성을 줄이면 지오메트리 처리를 크게 절약할 수 있으며, 결과적으로 필요한 조각 셰이딩의 양이 줄어든다는 점을 기억하세요. 이렇게 하면 조각 워크로드가 줄어들고 초당 프레임이 증가할 뿐만 아니라 APK의 설치 공간도 줄어듭니다.

게임 최적화

성능을 개선하기 위해 게임을 변경할 수 있는 몇 가지 영역을 발견했습니다. 구현하기로 선택한 기능과 구현 방법은 다음과 같습니다.

고정 시간 간격

고정 시간 간격은 프레임 속도와 무관한 간격으로, 피직스 계산과 FixedUpdate() 이벤트가 수행되는 시기를 제어합니다. 기본적으로 50fps로 실행되도록 설정되어 있습니다. 하이엔드 모바일 디바이스에서는 50프레임 또는 60프레임도 가능하지만, 이 타이틀이 타겟으로 하는 30프레임의 메인스트림 디바이스가 더 많습니다. 편집 > 프로젝트 설정으로 이동한 다음 시간 카테고리로 이동하여 고정 시간 간격 속성을 0.04로 설정합니다. 이렇게 하면 피직스 계산, FixedUpdate(), 업데이트가 모두 동기화되어 실행됩니다.

프로젝트 설정에서 고정 타임스텝을 0.04로 설정하기
프로젝트 설정에서 고정 타임스텝을 0.04로 설정하기

Unity에서 고정 타임스텝을 조정한 후 메인 게임 루프의 고정 업데이트 부분은 프레임당 한 번만 호출되어 평균 1.5ms가 소요되었습니다. 이는 이전에 걸렸던 12ms에서 크게 개선된 것으로, 일반적인 성능 함정에 대한 간단한 해결책입니다.

리소스 폴더

앱이 시작되면 기본 제공 장면 또는 리소스 폴더에서 참조하는 모든 개체에 대한 데이터가 인스턴스 ID 캐시에 로드됩니다. 이러한 자산은 하나의 큰 자산 번들처럼 취급되므로 항상 메모리에 로드되는 메타데이터와 인덱싱 정보가 있습니다. 이 번들의 에셋은 한 번 사용하면 메모리에서 언로드할 수 없습니다.

메모리 소비를 개선하고자 할 때 에셋과 리소스를 처리하는 권장 방법은 더 이상 필요하지 않은 콘텐츠를 메모리에서 효율적으로 언로드하는 방법을 제공하는 주소 지정 가능 에셋 시스템을 사용하는 것입니다.

GPU 인스턴싱

우리 환경에는 여러 번 나타나는 객체가 많이 있습니다. 벽, 바닥 타일 및 기타 환경 소품이 모두 복제되어 이 씬을 구성합니다. 오브젝트의 머티리얼에서 GPU 인스턴싱을 활성화하면 드로 콜을 절약할 수 있습니다. GPU 인스턴싱은 적은 수의 드로 콜로 동일한 메시를 렌더링하며 각 인스턴스마다 색상이나 스케일과 같은 다른 파라미터를 가질 수 있습니다. 이 수정으로 CPU 성능이 향상될 수 있습니다. 아래에서 GPU 인스턴싱이 활성화되기 전의 성능 관리자 데이터를 확인할 수 있습니다.

GPU 인스턴싱이 활성화되기 전의 데이터
GPU 인스턴싱이 활성화되기 전의 데이터

여기에서는 애플리케이션의 동일한 부분을 볼 수 있지만 GPU 인스턴싱이 활성화되어 있어 목표인 30fps를 향해 작지만 측정 가능한 이득을 얻을 수 있습니다.

GPU 인스턴싱이 활성화된 데이터
GPU 인스턴싱이 활성화된 데이터
텍스처 렌더링

렌더 텍스처는 UI에 3D 요소를 추가하는 방법이며 다른 많은 사용 사례도 있습니다. 렌더 텍스처에 카메라 렌더링이 있는 경우 카메라가 화면에 표시되지 않을 때는 카메라를 비활성화해야 합니다. 사용자에게 보이지 않는 것을 렌더링할 필요가 없습니다. 그래픽스 애널라이저 또는 Unity의 프레임 디버거를 사용하여 이러한 텍스처가 화면 밖에서 업데이트되지 않는지 확인합니다.

개체 풀링

동일한 객체를 반복해서 생성하고 소멸하여 CPU에 추가적인 작업을 부과하는 대신 객체 풀링을 사용해 보세요. 객체 풀링은 필요한 객체를 미리 생성하여 CPU의 작업을 미리 로드하는 디자인 패턴입니다. 그런 다음 파기하지 않고 풀에 다시 추가하여 같은 유형의 개체가 다시 필요할 때 재사용할 수 있습니다. 이는 CPU의 처리 능력을 완화하여 게임에서 더 중요한 작업을 자유롭게 수행할 수 있는 환상적인 방법입니다.

오브젝트 풀링으로 전환하면 Unity 프로파일러 캡처에서 화면에 나타나는 적의 파도에 스파이크가 부착되지 않으며 프레임 속도에도 눈에 띄는 영향을 미치지 않습니다.

레벨 오브 디테일(LOD) 메시

메시가 화면에 표시되면 GPU는 아무리 작더라도 메시의 모든 트라이앵글을 렌더링하는 데 시간을 소비합니다. 카메라나 에셋이 움직일 수 있는 게임에서는 프레임에 보이지 않을 정도로 작은 메시 트라이앵글을 렌더링하는 데 많은 GPU 리소스가 소모되는 상황이 종종 발생합니다. 이 문제를 해결하려면, 레벨 오브 디테일(LOD) 메시 를 사용합니다 . 이렇게 하면 카메라가 에셋에서 멀어질수록 게임에서 덜 복잡한 메시를 활용할 수 있으므로 GPU가 렌더링해야 하는 메시 복잡성이 감소하고 프레임당 버텍스 수가 줄어들어 더 큰 삼각형을 픽셀 처리에 사용할 수 있습니다. 이렇게 하면 효율성이 향상될 뿐만 아니라 장면의 예술적 무결성도 그대로 유지됩니다.

LOD 메시
LOD 메시

다른 에셋 최적화 팁은 Arm의 게임 아티스트 가이드를 확인하세요.

텍스처 아틀라스

동일한 머티리얼 속성을 가진 일부 에셋이 같은 씬에서 사용된다는 것을 알고 있는 경우, 이를 함께 배치할 수 있습니다. 텍스처 데이터를 하나의 텍스처 아틀라스로 결합하면 한 번에 그려서 그리기 호출을 절약하고 여러 개의 개별 파일에 비해 압축 시 설치 공간을 줄일 수 있습니다.

플로트 대 하프 셰이더 정밀도

커스텀 셰이더를 직접 작성하거나 셰이더 그래프를 사용할 때 사용할 정밀도를 플로트 또는 반으로 결정할 수 있습니다. 가능하면 절반을 선택하면 셰이더 성능이 향상되지만, 월드 스페이스 위치나 깊이 계산을 처리하는 모든 것에 플로트를 사용해야 할 가능성이 높다는 점을 기억하세요!

셰이더 그래프에서 정밀도를 절반으로 설정
셰이더 그래프에서 정밀도를 절반으로 설정
통합 및 포스트 프로세싱 V2 기능 세트

프로젝트의 포스트 프로세스 효과를 계획할 때 기존 통합 기능 세트 또는 새로운 포스트 프로세싱 v2 기능 세트 중에서 선택할 수 있는 두 가지 옵션이 있습니다. 아래에서 통합 기능 세트를 사용한 게임을 확인할 수 있습니다.

포스트 프로세싱이 없는 GPU 프로파일러 v2
포스트 프로세싱이 없는 GPU 프로파일러 v2

3~4프레임마다 시스템이 렌더링할 프레임을 기다리는 V-Sync가 급증하는 것을 볼 수 있습니다. 이로 인해 게임이 지속적으로 30fps 미만으로 떨어지고 기기의 전력이 낭비됩니다. 하지만 이번에는 포스트 프로세싱 v2 기능 세트를 사용하여 동일한 효과를 사용하여 게임의 프로파일러 데이터를 확인할 수 있습니다.

포스트 프로세싱 v2가 포함된 GPU 프로파일러
포스트 프로세싱 v2가 포함된 GPU 프로파일러

포스트 프로세싱 v2가 모바일 하드웨어에서 실행되도록 최적화되었기 때문에 이 프로파일러 그래프가 훨씬 더 좋아졌습니다. 프로젝트에 사용하여 최고의 포스트 프로세싱 성능을 얻으세요.

포스트 프로세싱 효과

게임에 포스트 프로세싱 효과를 추가하면 프로젝트에 멋진 광택과 시각적 깊이를 더할 수 있습니다. 하지만 이러한 효과와 성능의 균형을 맞추는 것도 중요합니다. 결국 이러한 효과는 비용이 많이 들 수 있습니다. 대중적인 기기에서 이 기능을 끄면 전력을 많이 절약하고 플레이어의 손에서 기기가 뜨거워지는 것을 방지할 수 있습니다.

다른 최적화가 완료된 후에도 일부 영역에서 여전히 스파이크가 발생하는 것을 확인할 수 있었습니다. 이진 검색을 사용하여 기능을 켜고 끄는 방식으로 결국 두 가지를 추적했습니다: 하나는 사용 중이던 포스트 프로세싱 스택이었습니다. 이는 총 시간에는 도움이 되었지만, 테스트에 사용한 최저 사양의 기기에서도 일부 포스트 프로세싱을 계속 사용할 수 있을 정도로 앤티 앨리어싱을 끄면 프레임 속도가 결국 평준화되었습니다.

GPU 프로파일러 - 최적화된 예제
GPU 프로파일러 - 최적화된 예제

게임을 최적화한 후 다시 Arm 모바일 스튜디오에서 실행하여 차이점을 확인했습니다. 이제 퍼포먼스 어드바이저 보고서에 따르면 평균 초당 프레임이 28.9(이전에는 17)에 달하고 전반적인 프래그먼트 경계가 줄어든 것으로 나타났습니다. 게임의 일부 구간에서 조각 활동이 여전히 높기 때문에 아직 해야 할 일이 남아 있지만, 조사를 위한 좋은 데이터를 확보하면 이러한 구간을 최적화하여 성능을 더욱 개선할 수 있을 것입니다.

Arm 모바일 스튜디오 - 캡처 요약
Arm 모바일 스튜디오 - 캡처 요약

이제 프레임당 버텍스 수가 예산인 50만 개를 훨씬 밑돌고 있으며, 적 NPC가 파괴되는 지점이 규칙적으로 줄어드는 것을 볼 수 있습니다.

Arm 모바일 스튜디오 - 프레임당 버텍스
Arm 모바일 스튜디오 - 프레임당 버텍스

이제 지오메트리 사용과 컬링이 훨씬 더 효율적이며, 표시되는 프리미티브의 수가 입력 프리미티브 수에 비해 훨씬 더 건전한 비율로 유지됩니다. 대면 테스트는 예상대로 도태된 프리미티브의 약 50%를 차지하며, 샘플 테스트에 의한 도태는 10% 미만으로 매우 작은 트라이앵글의 수를 줄였음을 보여줍니다.

말리 지오메트리 사용량 및 컬링 비율
말리 지오메트리 사용량 및 컬링 비율
요약

유니티의 프로파일러와 프레임 디버거를 Arm 모바일 스튜디오와 함께 사용하여 모바일 기기에서 성능을 개선하고 CPU와 GPU의 부담을 줄일 수 있는 다양한 방법을 발견할 수 있었습니다. 저희가 발견한 문제 중 일부는 콘텐츠에 대한 모범 사례를 준수함으로써 향후 타이틀에서 피할 수 있는 것들이었습니다.

물론 최적화로 인해 화면 비주얼의 품질이 저하되는 것은 원하지 않습니다. 다음은 최적화 버전의 게임과 원본 버전의 비교 모습입니다.

사전 예방적 성능 테스트

성능 테스트는 개발 주기 후반에 이루어지는 경우가 많습니다. 최적화를 위한 추가 기회를 찾는 것은 좋지만 출시 마감일 전에 문제를 해결할 시간이 없다면 어떻게 해야 할까요? 처음부터 콘텐츠를 최적으로 디자인하는 것이 훨씬 더 실용적입니다. 메시 복잡도, 셰이더 복잡도 및 텍스처 압축을 중심으로 콘텐츠 예산을 설정하면 팀이 모바일용으로 효율적으로 디자인할 수 있는 최상의 기회를 얻을 수 있습니다. 다음은 팀에 도움이 될 수 있는 몇 가지 리소스입니다:

대부분의 애플리케이션과 에셋이 모범 사례를 따르고 있다는 것을 알고 나면 개발 주기 전반에 걸쳐 정기적인 성능 테스트를 수행하여 문제를 조기에 발견하고 수정할 수 있습니다.

지속적 통합 시스템을 사용하는 팀은 Arm 모바일 스튜디오 프로페셔널 에디션에서 제공되는 자동화된 성능 테스트를 활용할 수 있습니다. 이 버전은 디바이스 팜의 여러 디바이스에서 실행할 수 있으며 수동 프로파일링의 번거로움을 덜어줍니다. 보고된 데이터는 JSON 호환 데이터베이스에 입력할 수도 있으므로 시각적 대시보드와 알림을 구축하여 시간에 따른 성능 변화를 모니터링하고 문제를 더 빨리 플래그 지정할 수 있습니다.

프로파일링 도구를 사용해 본 적이 없으신가요?

Unity의 빌트인 프로파일러는 시작하기에 좋은 도구입니다. Unity 문서에서 애플리케이션을 프로파일링하는 방법에 대해 알아보세요. 또는 개별 프레임이 어떻게 구성되는지 조사할 수 있는 프레임 디버거를 살펴보세요.

Arm 개발자 웹사이트에서 Arm 모바일 스튜디오를 무료로 다운로드하고 성능 어드바이저, 스트림라인, 말리 오프라인 컴파일러그래픽스 분석기에 대한 시작 가이드를 확인하여 빠르게 시작하고 실행할 수 있습니다.

연락하기

유니티 프로파일러와 프레임 디버거로 프로파일링하는 데 도움이 더 필요하면 포럼에서 언제든지 질문해 주세요.

Mali 디바이스 또는 Arm 모바일 스튜디오로 작업하는 동안 추가 지원이 필요하면 Arm의 그래픽 및 게임 포럼으로 이동하여 질문할 수 있으며, Arm에서 기꺼이 도와드리겠습니다.