Android용 Godot Engine Vulkan 최적화

Godot Engine 마스코트 이미지

개요

Godot Engine은 Android를 강력하게 지원하는 인기 있는 멀티플랫폼 오픈소스 게임 엔진입니다. Godot은 거의 모든 장르의 게임을 만드는 데 사용할 수 있으며 2D 및 3D 그래픽을 모두 지원합니다. Godot 버전 4에서는 고화질 그래픽을 위한 고급 기능이 포함된 새로운 렌더링 시스템을 도입했습니다. Godot 4 렌더기는 Vulkan과 같은 최신 그래픽 API용으로 설계되었습니다.

Godot Foundation은 The Forge Interactive의 그래픽 최적화 전문가를 참여시키고 Google과 협력하여 Godot 4 Vulkan 렌더러를 분석하고 개선했으며 이러한 최적화를 프로젝트 저장소에 다시 병합했습니다. 이 최적화는 개발자가 Android에서 맞춤 Vulkan 렌더러를 개선하는 데 도움이 됩니다.

최적화 방법론 및 결과

최적화 프로세스에서는 Godot의 두 가지 3D 장면을 벤치마킹 타겟으로 사용했습니다. 최적화의 각 반복 중에 여러 기기에서 장면의 렌더링 시간이 측정되었습니다. 포함되려면 렌더러 변경사항이 테스트된 기기 중 일부에서 성능 개선을 보여야 했으며, 어떤 기기에서도 성능 회귀를 일으키면 안 되었습니다.

테스트에는 여러 개의 널리 사용되는 Android GPU 아키텍처가 사용되었습니다. 많은 최적화로 전반적인 개선이 이루어졌지만 일부 최적화는 특정 GPU 아키텍처에 더 큰 영향을 미쳤습니다. 모든 최적화 작업의 합계로 인해 GPU 프레임 시간이 일반적으로 10~20% 감소했습니다.

일반적인 Vulkan 최적화

Forge는 성능을 개선하고 증가하는 콘텐츠 렌더링 수요에 맞춰 백엔드를 확장할 수 있도록 Godot Vulkan 렌더링 백엔드에서 일반적인 아키텍처 리팩터링을 실행했습니다. 최적화는 모바일 하드웨어에만 국한되지 않으며 모든 Godot Vulkan 플랫폼에 도움이 됩니다.

동적 UBO 오프셋 지원

동적 균일 버퍼 객체(UBO)가 포함된 설명자 집합을 바인딩할 때 Vulkan은 바인드 매개변수에서 UBO의 동적 오프셋을 지정할 수 있도록 허용합니다. 이 기능을 사용하면 여러 렌더링 작업의 데이터를 단일 UBO로 패킹하고 다른 동적 오프셋으로 설명자 세트를 재바인딩하여 셰이더에 적절한 데이터를 선택할 수 있습니다. Godot Vulkan 렌더러가 항상 오프셋을 0으로 초기화하는 대신 동적 오프셋을 사용할 수 있도록 업데이트되었습니다. 이 개선사항을 통해 향후 효율성 최적화가 가능합니다.

선형 설명자 집합 풀

이전에는 Godot Vulkan 렌더러의 기본 동작이 VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT 플래그를 사용하여 모든 설명자 세트 풀을 만드는 것이었습니다. 즉, 설명자 세트 할당을 풀에 다시 해제하고 풀에서 재할당할 수 있었습니다. 이 모드는 선형 할당만 허용하고 그 후 풀을 완전히 재설정하는 설명자 세트 풀에 비해 추가 오버헤드를 부과했습니다.

이제 가능하면 설명어 집합 풀이 VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT를 설정하지 않고 선형 풀로 생성됩니다. 그런 다음 필요에 따라 선형 풀이 전체적으로 재설정됩니다. 또한 이 작업에는 가능한 경우 일괄 설명자 세트 결합에 대한 추가 최적화가 포함되어 vkCmdBindDescriptorSets()에 대한 개별 호출 수가 줄어듭니다.

변경 불가능한 샘플러 지원

샘플링 구성 데이터가 포함된 샘플러 객체는 전통적으로 설명자 세트 데이터의 일부로 바인딩됩니다. 이 메서드를 사용하면 샘플러 객체를 설명자 세트 데이터에서 동적으로 전환할 수 있습니다. Vulkan은 샘플러 데이터를 설명자 세트 레이아웃에 직접 인코딩하는 불변 샘플러도 지원합니다. 이 샘플러 구성은 설명자 세트와 파이프라인 상태를 만들 때 바인딩되며 생성 후에는 변경할 수 없습니다.

불변 샘플러는 더 이상 개별 샘플러 객체를 관리하고 바인딩할 필요가 없도록 유연성을 희생합니다. 변경 불가능한 샘플러 사용을 지원하도록 Godot Vulkan 렌더기가 업데이트되었습니다. 샘플러 사용이 실용적인 경우 변경 불가능한 샘플러를 사용하도록 변경되었습니다.

모바일 중심 최적화

특히 모바일 그래픽 하드웨어의 렌더링 성능을 개선하기 위해 추가 최적화가 구현되었습니다. 이러한 최적화는 일반적으로 아키텍처 설계가 다르기 때문에 데스크톱 클래스 그래픽 하드웨어와 관련이 없습니다.

최적화에는 다음이 포함됩니다.

  • 대규모 푸시 상수 사용 대체
  • 지연 버퍼 할당
  • 영구 버퍼 지원
  • ASTC 디코딩 모드 변경
  • 화면 사전 회전

대규모 푸시 상수 사용 대체

푸시 상수는 활성 셰이더 프로그램의 상수 값을 명령 버퍼에 삽입할 수 있는 기능입니다. 푸시 상수는 버퍼 생성 및 채우기가 필요하지 않고 설명자에 연결되어 있지 않으므로 편리합니다. 그러나 푸시 상수는 최대 크기가 제한되어 있으며 모바일 하드웨어의 성능에 부정적인 영향을 미칠 수 있습니다.

Android 기기에서 테스트하는 동안 16바이트가 넘는 푸시 상수 사용을 균일 버퍼로 대체하여 성능이 개선되었습니다. 상수 데이터를 16바이트 이하로 사용하는 셰이더는 푸시 상수를 사용하면 성능이 향상되었습니다. 성능 고려사항 외에도 일부 그래픽 하드웨어에는 균일 버퍼의 최소 정렬이 64바이트이므로 푸시 상수를 사용할 때와 비교하여 사용되지 않는 패딩으로 인해 메모리 효율이 저하됩니다.

지연 버퍼 할당

대부분의 모바일 그래픽 하드웨어는 카드 기반 지연 렌더링 (TBDR) 아키텍처를 사용합니다. TBDR을 사용하는 GPU는 더 큰 화면 영역을 더 작은 타일의 그리드로 분할하고 타일별로 렌더링합니다. 각 카드는 GPU가 카드를 렌더링할 때 GPU의 저장소에 사용되는 소량의 고속 RAM으로 지원됩니다. TBDR을 사용하면 렌더링 패스 외부의 다른 타겟에서 샘플링되지 않는 렌더링 타겟이 사실상 타일 RAM에 완전히 유지될 수 있으며 기본 메모리 백업 저장소에 버퍼가 필요하지 않습니다.

VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT는 기본 색상 및 깊이 타겟과 같은 적절한 렌더링 타겟을 만드는 동안 추가되었습니다. 이는 사용되지 않을 버퍼 메모리를 할당하지 않기 위함입니다. 샘플 장면에서 지연 할당 메모리 절감량은 최대 50MB의 RAM으로 측정되었습니다.

영구 버퍼 지원

모바일 하드웨어는 기본 RAM과 그래픽 RAM 간의 하드웨어 구분 대신 통합 메모리 아키텍처 (UMA)를 사용합니다. 기본 RAM과 그래픽 RAM이 분리된 경우 GPU에서 사용할 데이터를 기본 RAM에서 그래픽 RAM으로 전송해야 합니다. Godot은 이미 스테이징 버퍼를 사용하여 Vulkan 렌더기에서 이 전송 프로세스를 구현하고 있습니다. UMA 하드웨어에서는 많은 유형의 데이터에 스테이징 버퍼가 필요하지 않습니다. 메모리는 CPU와 GPU에서 모두 사용할 수 있습니다. Forge는 가능한 경우 스테이징을 제거하기 위해 지원되는 하드웨어에서 영구 공유 버퍼 지원을 구현했습니다.

영구 버퍼를 사용 설정했을 때와 사용 중지했을 때의 프로파일링 정보를 보여주는 Godot 장면의 이미지
그림 1. 샘플 장면에서 사용 설정된 영구 버퍼와 사용 중지된 영구 버퍼 간의 차이를 프로파일링합니다.

ASTC 디코딩 모드 변경

적응형 확장형 텍스처 압축 (ASTC)은 모바일 하드웨어에서 선호되는 최신 텍스처 압축 형식입니다. 압축 해제 중에 GPU는 기본적으로 텍셀을 시각적 충실도에 필요한 것보다 더 큰 정밀도의 중간 값으로 디코딩할 수 있으므로 텍스처링 효율성이 저하될 수 있습니다. 타겟 하드웨어에서 지원하는 경우 VK_EXT_astc_decode_mode 확장자가 디코딩 시 16비트 부동 소수점 값 대신 구성요소당 8비트 비정규화된 값을 지정하는 데 사용됩니다.

화면 사전 회전

Android에서 Vulkan을 사용할 때 최적의 성능을 얻으려면 게임에서 화면의 기기 방향을 렌더링 노출 영역 방향과 조정해야 합니다. 이 프로세스를 사전 회전이라고 합니다. 사전 회전을 실행하지 않으면 Android OS에서 이미지를 수동으로 회전하기 위해 컴포지터 패스를 추가해야 하므로 성능이 저하될 수 있습니다. Android의 사전 회전 지원이 Godot 렌더러에 추가되었습니다.

디버깅 개선사항

The Forge는 성능 최적화 외에도 다음과 같은 추가사항을 통해 Godot 렌더러에서 그래픽 문제를 디버그하는 환경을 개선했습니다.

  • 기기 결함 연장
  • 현재 위치
  • 디버그 마커

기기 결함 연장

렌더링 작업 중에 GPU에 문제가 발생하면 Vulkan 드라이버가 Vulkan API 호출에서 VK_ERROR_DEVICE_LOST 결과를 반환할 수 있습니다. 기본적으로 드라이버가 VK_ERROR_DEVICE_LOST를 반환한 이유에 관한 추가 컨텍스트 정보는 제공되지 않습니다. VK_EXT_device_fault 확장 프로그램은 드라이버가 오류의 특성에 관한 추가 정보를 제공할 수 있는 메커니즘을 제공합니다. Godot는 기기 오류 확장 프로그램(사용 가능한 경우)을 사용 설정하고 드라이버에서 반환한 정보를 보고하는 지원을 추가했습니다.

GPU 비정상 종료 또는 실행 중단은 디버깅하기 어려울 수 있습니다. 오류 발생 시 렌더링되었을 수 있는 그래픽 콘텐츠를 식별할 수 있도록 탐색경로 지원이 Godot 렌더러에 추가되었습니다. 탐색경로는 렌더링 그래프의 그리기 목록에 있는 콘텐츠에 연결할 수 있는 사용자 정의 값입니다. 새 렌더링 패스가 시작되기 전에 탐색경로 데이터가 작성됩니다. 비정상 종료나 실행 중단이 발생하면 현재 탐색경로 값을 사용하여 문제를 일으킨 데이터를 파악할 수 있습니다.

디버그 마커

디버그 마커는 드라이버에서 지원하는 경우 리소스 이름 지정하는 데 사용됩니다. 이렇게 하면 RenderDoc과 같은 그래픽 도구를 사용할 때 사용자가 읽을 수 있는 문자열을 렌더링 패스와 같은 작업 및 버퍼 및 텍스처와 같은 리소스와 연결할 수 있습니다. 디버그 마커 주석 지원이 Godot Vulkan 렌더러에 추가되었습니다.

Godot Engine 블로그 - Google 및 The Forge와의 공동작업 관련 업데이트

Godot Engine Vulkan 공동작업 pull 요청