오디오 제작자에게 힘을 실어준다는 것은, 한편으론 이들의 손에 일부 게임 리소스의 책임을 넘긴다는 것을 뜻합니다. Wwise는 편집기와 SDK를 통해 최소한의 CPU 예산을 지킬 수 있도록 깔끔하고 효율적인 음향 환경을 제공합니다. 반면, 사용자는 Wwise를 통해 수많은 예술적 기능과 제작 방법을 사용하게 되어 그만큼 CPU를 쉽게 써버릴 수 있다는 위험도 있는 셈입니다. 그렇기 때문에 게임의 다른 방면에도 사용할 수 있도록 처리 내용을 줄이고 게임 경험을 매끄럽게 유지하려면 Wwise를 효율적으로 사용하는 것이 중요하죠. 이 글은, 저작 도구나 Wwise SDK를 사용하는 프로그래머와 사운드 디자이너가 함께 힘을 모아 소중한 처리 주기를 절약할 수 있는 해결책을 찾기 위해 쓰였습니다.
Wwise를 최적의 방법으로 사용하고 있는지 확인할 수 있는 몇 가지 주요 요소가 있습니다. 이 글은 Wwise 프로파일러를 사용하는 도중 Performance Monitor에서 가져올 수 있는 주요 데이터에 초점을 맞추고 있습니다.
첫 번째 단계는 바로 Wwise Profiling, 특히 Performance Monitor에 익숙해지는 것입니다. Wwise에서 프로파일링, 문제 해결, 디버깅하기 포스팅을 보시면 이 부분을 아주 잘 설명하고 있죠.
또한 게임 안에서 직접 AK::SoundEngine::StartProfilerCapture()를 사용하면 프로파일링 세션을 자동으로 만들 수 있습니다.
Performance Monitor를 사용할 때에는, 뷰 설정을 커스터마이징하여 필요한 값을 그래픽의 형태로 표시하도록 할 수도 있습니다. 이 기능은 값이 치솟는 부분이 어디인지 찾고 Audio Thread(오디오 스레드) CPU% 그래프와 상관 관계를 확인하는 데 유용합니다.
(이미지를 클릭하면 크게 볼 수 있습니다)
위의 예시에서 Audio Thread CPU에서 치솟는 부분이 Number of Transitions/Interpolations(전환효과/보간의 개수) 및 Number of Voices(보이스 개수) (Total)(전체)와 연관된 것을 볼 수 있습니다.
Audio 스레드 CPU
Audio thread CPU는 CPU와 관련된 결정을 내리는 데 중요한 참조 항목입니다. Audio thread CPU는 Wwise가 하드웨어에 전송될 최종 오디오 프레임을 렌더링하는 데 걸리는 시간이라고 할 수 있습니다. 오디오 프레임의 크기는 사운드 엔진의 초기화 때 AkInitSettings::uNumSamplesPerFrame을 통해 결정됩니다. Windows 플랫폼에서는 1,024 샘플이 기본 크기로 설정되어 있습니다. 원래의 샘플 레이트가 48,000Hz이기 때문에 Wwise는 21.333ms 마다 오디오 프레임을 제출해야 합니다 (바로 이것이 1,024 / 48,000이 입니다). 오디오 스레드가 한 프레임을 만드는 데 21.333ms가 걸릴 경우 Performance Monitor에서 100% CPU로 표시됩니다. 보통 Audio thread CPU 사용률이 50% 이하가 되도록 목표를 두는 것이 좋은데, 이 경우 한 프레임을 채우는 데 10.666ms가 걸립니다.
Wwise는 안전을 위해 두 개 이상의 프레임을 미리 버퍼하기 때문에 한 오디오 프레임이 누락될 경우 (혹은 사용률이 100%를 초과할 경우) 단일 오디오 프레임에 문제가 될 수 있습니다. 이렇게 Wwise가 안전상 버퍼해두는 프레임의 개수를 Refill(리필) 개수라고 하며, AkPlatformInitSettings::uNumRefillsInVoice에서 4로 기본 설정되어 있습니다. 모든 리필이 고갈되고 오디오 스레드가 현재 프레임에서 다른 리필 프레임을 렌더링할 시간이 없을 경우 Voice Starvation (보이스 고갈 상태) 오류가 일어납니다. 이 오류가 여러 프레임 걸쳐 일어나면 따닥 하는 소리가 생길 수 있습니다. Capture Log에서 % 값이 100% 이하일 경우에도 Voice Starvation 오류가 일어날 수 있습니다. 이 현상은 Performance Monitor의 리프레시 비율이 200ms이며 CPU가 급격히 치솟는 것을 놓칠 수 있기 때문에 일어납니다.
Voice Starvation이 일어나는 세 가지 주요 원인이 있습니다.
1) 오디오 스레드(EventManager 스레드 혹은 LowerEngine 스레드)가 게임에서 또다른 스레드에 의해 획득될 경우 Wwise 자체가 처리하는 내용이 많지 않더라도 백분율이 높게 나타날 수 있습니다. 기본적으로 오디오 스레드는 Above Normal(일반 이상)의 우선 순위를 갖습니다. 이 스레드가 높은 우선 순위에 있는 것이 매우 중요합니다. 또한 사용하는 플랫폼이 지원하는 경우, AkPlatformInitSettings::threadLEngine에서 동질 관계(affinity)를 강요하여 오디오 스레드를 동일한 CPU 코어에 유지하는 것이 좋습니다.
2) Wwise 콜백 함수에서 게임이 처리하는 내용이 너무 많은 경우입니다. 콜백에서 잠금이 생길 경우 오디오 스레드를 대기시켜 CPU 사용량이 보다 높게 표시될 수 있습니다.
3) Wwise 자체가 처리하는 양이 너무 많을 때에도 Voice Starvation이 일어날 수 있습니다. 이 경우 Performance Monitor에 표시되는 다른 여러 값들을 주의 깊게 모니터링하는 것이 중요합니다.
보이스 개수 (물리적)
물리적 보이스의 개수는 보통 CPU 리소스에 가장 큰 영향을 미칩니다. 가장 먼저 이 값을 확인해봐야 합니다. 물리적 보이스의 목표 개수를 몇 개로 하는 것이 좋을까요? 이 질문은 궁극적으로 디자인 및 음향 믹스로 어떤 소리를 만들고자 하는지와 더 깊은 관련이 있습니다. 각 보이스의 CPU 사용량이 다 제각각이라는 점을 감안할 때, 게임 유형에 상관 없이 평균적으로 30~70개의 물리적 보이스를 사용합니다. 채널의 개수, 적용된 기본 속성(예: LPF, HPF, 피치) 및 각기 다른 변환 설정, 등 모두 보이스 당 CPU 사용량에 영향을 미칩니다. 예를 들어 Vorbis 파일을 디코딩할 경우 경우 PCM 파일을 디코딩할 때보다 CPU를 더 많이 사용합니다. 그렇기 때문에 변환 설정을 주의 깊게 선택하는 것이 아주 중요하죠.
물리적 보이스의 개수를 직접 감소하는 한 가지 방법은 바로 Playback 제한과 우선 순위, 가상 보이스 시스템을 사용하는 것입니다. 이 부분은 Wwise 도움말과 다음 Wwise 101 과정 수업 자료에서 자세히 설명하고 있습니다.
보이스 개수 (가상)
사실 가상 보이스는 I/O, 메모리, CPU 주기를 절약하기 위해 사용되지만, 이 개수가 500개 이하로 유지되면 활성화된 게임 오브젝트와 이들의 Number of Active Events(활성화된 Event 개수)를 게임에서 잘 관리하고 있다는 좋은 신호입니다. Number of Active Events 값 또한 항상 예의주시하는 것이 좋습니다. Virtual 작동 방식은 기본적으로 'Kill if finite, else virtual(무한 반복 재생될 경우 제거, 그렇지 않은 경우 가상으로 전송)'로 설정되어야 합니다. 이 옵션은 가장 쉽고 효율적인 가상 보이스 옵션입니다. 이 옵션은, 반복 재생되지 않으며 들리지 않는 보이스를 제거함과 동시에 반복 재생되는 보이스를 가상으로 유지해줍니다.
전체 플러그인 CPU
Performance Monitor와 Advanced Profiler의 Plug-ins 탭에 Total Plug-in CPU 값을 추가하려면 Profiler Settings (Alt+G)에서 Plug-in Data 옵션이 활성화되어야 합니다. 이 뷰는 현재 활성화된 인스턴스의 개수와 사용되고 있는 CPU의 양을 표시합니다. 이 활성화된 플러그인 인스턴스의 개수가 Total Plug-in CPU 로드를 결정합니다. Actor-Mixer나 Interactive Music Hierarchy에 삽입된 플러그인은 재생되는 각 사운드에 한 개의 인스턴스를 만듭니다. 이러한 사운드를 동시에 많이 재생할 경우 CPU 사용량이 빠르게 증가할 수 있기 때문에 렌더(render) 체크 상자를 클릭하여 미디어 WEM 파일 자체에 Effect를 '렌더링해넣을' 수 있는지 고려해봐야 합니다. 버스에 적용된 플러그인은 각 버스에 한 인스턴스만 만듭니다. 그렇기 때문에 실제 재생되는 사운드의 개수보다 플러그인이 삽입된 활성화된 버스의 개수가 CPU에 더 많은 영향을 미칩니다.
플러그인에서 CPU에 영향을 줄 수 있는 또다른 옵션은 바로 처리되는 채널의 개수입니다. 예를 들어 7.1 버스에 활성화된 한 Effect 인스턴스(8 채널)보다 Actor-Mixer Hierarchy 안의 모노 사운드에 활성화된 세 개의 Effect 인스턴스(3 채널)가 더 저렴합니다. 따라서 모든 인스턴스가 차지하는 채널의 총 개수가 버스의 채널 개수보다 적을 경우 Actor-Mixer 안에 Effect를 삽입하는 것이 더 유용할 수 있습니다. 모든 Effect 플러그인에서 CPU 사용량은 처리해야 할 채널의 개수에 비례해 선형적으로 증가합니다. 하지만 예외적으로 Reverb(잔향)는 채널당 성능 소비량이 거의 일정하며 웬만한 경우 Auxiliary Bus에 사용하는 것이 가장 좋습니다.
등록된 게임 오브젝트의 개수
일부 게임 오브젝트는 오랫동안 비활성화되는 경우가 있습니다. 그렇기 때문에 필요하지 않는 것을 골라내 등록 해제하는 것이 좋겠죠. 그러면 게임에서든 사운드 엔진 자체에서든 오브젝트의 위치나 매개 변수를 업데이트하기 위해 줄줄이 늘어선 모든 오브젝트 목록을 탐색할 필요가 없게 됩니다. 등록된 게임 오브젝트의 개수는 몇 개가 적당할까요? 일부 오픈 월드 게임은 이 개수를 80개 이하로 유지하기도 합니다. 반면 또 다른 개발자들은 특정 맵/레벨 안에 있는 모든 오브젝트를 영구적으로 활성화하도록 결정하여 오브젝트의 개수가 1,000개를 초과하면서도 좋은 성능을 유지하기도 하죠. 하지만 대량의 게임 오브젝트를 처리할 경우 성능 문제가 일어날 가능성이 더 커집니다. 뿐만 아니라 게임에 등록된 게임 오브젝트의 개수가 적으면 Profiling 레이아웃에서 문제를 찾아내기도 더 쉬워지죠.
API 호출
게임에서 위치 정보, 차단 값, 게임 싱크 값이 얼마나 자주 업데이트될까요? 이러한 호출이 여러 게임 프레임에 걸쳐 일어날까요, 아니면 한 프레임에서 수많은 SDK 호출이 한꺼번에 일어날까요? 모든 게임 오브젝트가 각 프레임마다 RTPC 값을 업데이트해야 할까요? Profiler Settings (Alt+G)에서 API Calls를 활성화하면 각 프레임에서 Wwise에 과도하거나 불필요한 API 호출이 일어나지 않는지 확인할 수 있습니다.
전환 효과/RTPC 보간의 개수
Performance Monitor에서의 전환 효과는 특정 비율/속도에 따라 속성을 증가하거나 감소하는 것입니다 (음악 전환 효과와 다르니 혼동하지 않도록 주의하세요). 가장 흔한 전환 효과는 바로 페이드하는 동안 Volume 속성에 적용하는 것입니다. 기본적으로 RTPC로 제어할 수 있는 모든 속성은 시간에 따른 전환 효과를 만들 수 있으며 이러한 각 전환은 사운드 엔진에서 소량의 처리력을 필요로 합니다. 이 값이 500일 경우 CPU가 급격히 치솟는 원인이 될 수 있습니다. 전환 효과를 쉽게 생성할 수 있는 한 예시는 바로 Distance와 같은 내장 매개 변수와 결합된 Game Parameter 보간(interpolation)을 사용하는 것입니다. 이렇게 하면 게임 오브젝트나 리스너가 움직일 때마다 전환 효과를 생성할 수 있습니다.
저성능 플랫폼과 모바일
상대적으로 성능이 낮은 프로세서에서는, Wwise의 하위 플랫폼 시스템을 활용할 때 ( Managing Platforms(플랫폼 관리하기) 참조) 연결 및 제외 기능과 함께 사용하는 것이 특히 중요합니다. 그렇기 때문에 하위 플랫폼의 경우 위에서 언급한 모든 권장 사항을 더 효율적으로 사용해야 할 수 있습니다. 예를 들어 저성능 모바일 기기의 경우 물리적 보이스를 70개가 아닌 30개를 목표로 하고 활성화된 플러그인의 인스턴스를 줄이는 것이 좋습니다. 또한 짧거나 자주 반복되는 사운드에 PCM 사운드의 음질과 저렴한 비용을 활용하는 사례도 많습니다.
결론
이 밖에도 Wwise에서 CPU에 영향을 미칠 수 있는 다른 요소가 더 있겠지만, 최소한 위에서 언급한 값들을 잘 관리하면 CPU 최적화에 가장 큰 도움이 될 것입니다.
댓글