バージョン

menu_open
Wwise SDK 2024.1.2
CPU使用率の最適化

Audio Rendering Thread

デフォルトでは、Wwiseサウンドエンジンは専用のスレッド AK::EventManager で、AkPlatformInitSettings::threadLEngine パラメータが制御しながらすべてのコマンド処理とオーディオレンダリングを行っています。 AK::SoundEngine::RenderAudio をコールするとゲームフレームが終わることを意味するので、スレッドは、 RenderAudio への最後のコール以降に受領したすべてのAPIコマンドを消費することができます。

AkInitSettings::bUseLEngineThreadfalse に設定すると、このスレッドが無効になり RenderAudio が同期的に実行され、コマンドを処理し、必要に応じてオーディオをレンダリングします。オーディオ出力の実際のレートは、オーディオエンドポイントが引き続き制御します。 RenderAudio の呼び出し間隔が、 AkInitSettings::uNumSamplesPerFrame で定義したバッファ期間や、出力サンプルレートよりも短い場合は、 RenderAudio へのコールの一部が、オーディオレンダリングの部分を省略します。逆に、 RenderAudio の呼び出し間隔が出力バッファ期間よりも長い場合は、 RenderAudio が同時に複数のバッファを処理する可能性があり、CPU使用量が急上昇し、次第にオーディオが途切れる可能性があります。

オフラインのレンダリングを有効にすると、非同期コマンド処理や、オーディオスレッドからのオーディオレンダリングが無効になります。 RenderAudio への1回の呼び出しでレンダリングされるオーディオの量は、 AK::SoundEngine::SetOfflineRenderingFrameTime に送る0以外の正の値で決まります。値が0または負の値であれば、強制的に、 RenderAudio で処理されるオーディオバッファがちょうど1となります。

注意: オーディオレンダリングのスレッドを無効にした状態や、オフラインレンダリングを有効にした状態では、同期的な AK::SoundEngine::LoadBankAK::SoundEngine::UnloadBank のAPIコールを、 RenderAudio のコールと同じスレッドで行ってはいけません。理由は、これらのコールが、オーディオバッファがレンダリングされるまでブロックし、それからStop操作を完了させSoundBankメディアを解放する可能性がありますが、これは RenderAudio への並列のコールがなければ起きないからです。

Microsoftのプラットフォームではsingle-threaded apartment (STA) という並列モデルを使用するため、 AkInitSettings::bUseLEngineThreadfalse に設定するときに、 CoInitializeEx() のコールは、 AK::SoundEngine::RenderAudio をコールするのと同じスレッドで行う必要があります。

Query API関数を使う

一部の AK::SoundEngine::Query 関数はCPUのスパイクを引き起こすことがあります。無駄なCPU時間を最小限に抑えてパフォーマンスの最適化を確保するために、以下のガイドラインに従うことを推奨します:

  • Query関数を開発ビルドで使用し、プロダクションビルドで使用しないようにします。
  • Query関数を使用する必要がある場合はSoundEngineグローバルコールバックの中で使用します( AkGlobalCallbackLocation 参照)。例えばRTPC値を読み込む必要がある場合はコードを AkGlobalCallbackLocation_BeginRender または AkGlobalCallbackLocation_EndRender に入れます。

Job Managerを利用したオーディオレンダリングジョブの同時実行

デフォルトでは、Wwise Sound Engineはオーディオレンダリングスレッド上でさまざまなオーディオレンダリングタスク、すなわち「ジョブ」を順次実行します。このようなジョブにはバス処理やボイス処理タスクなどがあります。

Wwise Sound EngineがゲームマネージドスレッドでCPU時間を要求できるコールバックを指定することで、これらのオーディオジョブの同時実行を有効にできます。ゲームが AkJobMgrSettings::fnRequestJobWorker を介してこのコールバックを実装すると、Wwise Sound Engineでジョブの同時実行が有効になります。

注釈: ジョブの同時実行を有効にすると、同時ジョブワーカースレッドから数個のAK::SoundEngineコールバックが生成されます。ジョブの同時実行に対応していないプラグインもあります。

Sound EngineのJob Managerのしくみを理解するには、以下に示す2つの重要なコールバックの違いを知ることが大切です。

  1. ワーカー要求関数ゲームエンジンによって定義され、Wwise Sound Engineによって呼び出されます。
  2. ワーカー関数Wwise Sound Engineによって定義され、ゲームエンジンによって呼び出されます。
注釈: Wwise Sound Engineは、ワーカー要求ごとにワーカー関数が正確に1回呼び出されることを想定します。例えば、ワーカー要求関数がタイプ AkJobType_AudioProcessing のワーカーを3つ要求するために1回呼び出されてから、タイプ AkJobType_Generic のワーカーを2つ要求するために再度呼び出されると, Sound Engineはゲームが AkJobType_AudioProcessing を指定してワーカー関数を3回呼び出し、 AkJobType_Generic を指定して2回呼び出すことを想定します。関数の呼び出しは複数のスレッドから順不同、順次、または同時に発行される可能性があります。

ワーカー要求関数が定義されると、オーディオレンダリングスレッドは次のように動作します。

「図:ワーカー実行のシーケンス図」
  1. オーディオレンダリングスレッドは、複数のスレッドで実行可能なジョブ(ボイス処理やバス処理など)を識別します。
  2. オーディオレンダリングスレッドはゲームのワーカー要求関数を呼び出して、別のスレッドでCPU時間を要求します。このステップで、ゲームエンジンは呼び出すワーカー関数のアドレスを受け取ります。
  3. ゲームエンジンはスレッドプール上の要求をスケジュールします。ワーカースレッドが適宜起こされます。
  4. ゲームのワーカースレッドは、ステップ2でSound Engineから受け取ったワーカー関数を呼び出します。
  5. ワーカー関数が呼び出されるたびに、オーディオレンダリングジョブが少なくとも1つ実行されます。複数のレンダリングジョブがある場合は複数のジョブが実行されることもあります。
  6. オーディオレンダリングスレッドは、必要なすべてのジョブの実行が終了するとすぐに処理を再開します。

このプロセスが1つのオーディオレンダリングパスを通して何度も繰り返される場合があり、オーディオレンダリングスレッドは作業をできる限りパイプライン処理しようとします。例えばバスグラフのレンダリング時、すべての入力処理が終了するとすぐに所定のバスで処理時間が要求されるため、ほかのバスと独立して実行されることがあります。このように、Job Managerは常にスループットを最大化しようとします。

注釈: ワーカー要求関数は、 Sound Engineコードを実行しているどのスレッドからでも呼び出すことができるため、スレッドセーフな方法で実装する必要があります

ゲームエンジンの既存のジョブスケジューラとの統合

Wwise Sound EngineのJob Managerは既存のジョブスケジューラと連携するように設計されているため、協調的マルチタスク処理を実現できます。ジョブスケジューラがすでに組み込まれているゲームエンジンでは、既存のジョブシステム内でワーカー関数の実行がスケジュールされるように、ワーカー要求関数を実装する必要があります。

ゲームエンジンのジョブスケジューラは、ワーカー関数を呼び出す時にタイムアウトをマイクロ秒単位で指定できます。これにより、Sound Engineが呼び出し中のスレッドで消費するCPU時間が長くなりすぎるのを防ぐことができます。このタイムアウトを過ぎると、ワーカー関数は停止します。実行対象のジョブがある場合は、追加のワーカーを要求します。これにより、高い優先順位のゲームエンジン作業などをこのスレッドで実行できます。

注釈: ワーカー関数の実行を遅らせたりSound Engine作業の実行時間を制限したりすると、ボイススターベーション(音声枯渇)が発生する可能性があるため、注意が必要です。Sound Engineジョブを既存のジョブスケジューラに組み込む際、オーディオレンダリングジョブを優先順位の高い作業として扱うことを推奨します。

ジョブスケジューラが組み込まれていないゲームエンジンについては、そのようなスケジューラのサンプル実装が SDK/samples/SoundEngine/Common/AkJobWorkerMgr.[h,cpp] のSDKサンプルで提供されます。このサンプルは、オーディオレンダリングジョブの同時実行を実現するための最適なスターティングポイントです。また、IntegrationDemoで提供されるコードは、実際のエンドユーザアプリケーションにこのサンプル実装を組み込む方法をデモしています。

Job Managerを使用する際のベストプラクティス

ここではJob Managerを最大限に活用するための推奨事項をいくつか紹介します。

  1. 新しいワーカー要求が入ってきた時、スレッドをオンデマンドで作成しないでください。新しいスレッドを作成すると、一般的にシステム運用コストが高くなります。代わりに、Sound Engineを初期化する前に既定の数のスレッドを事前に割り当て、それらのスレッド内でワーカー要求を分散させます。
  2. Sound Engineジョブの十分な並列化を達成するために、必要以上のワーカースレッドを使わないでください。ワーカー要求のオーバーヘッドにより、ほかのタスク用としてより有効に使われるはずのCPU時間が失われる場合があります。またワーカー数が増加すると、Sound Engineのメモリアロケータなどのシステムでスレッドのローカルキャッシュが使用されるため、Sound Engineが要求するメモリ量の合計が増加することがあります。
  3. ジョブの実行をサポートするゲームエンジンのワーカースレッドでは、スレッドを初期化および終了する時に AK::MemoryMgr::InitForThread および AK::MemoryMgr::TermForThread を呼び出して、スレッドのローカルメモリリソースを適切に初期化および終了することを推奨します。またワーカー関数の実行後に非アクティブ期間に入る場合は、 AK::MemoryMgr::TrimForThread を呼び出して、すぐに再使用する可能性がないスレッドのローカルメモリリソースを解放することを推奨します。
  4. プラットフォーム上のCPUコア数が固定で事前に分かっている場合は、同じCPUコア上で各スレッドの実行が継続されるように、ワーカースレッドのアフィニティを設定してください。スレッドが別のコアに移行した時にCPUキャッシュがリフレッシュされるのを避けるため、オーディオ作業が実行中にCPUコア間を移動しないようにすることが望ましい対応です。
  5. 複数のClusterやCore Complex(CCX)を搭載したシステムでは、コア間のキャッシュの一貫性を向上させるために、ワーカースレッドとオーディオレンダリングスレッドがすべて同じCCX上で実行されるようにスレッドアフィニティを設定してください。
  6. Simultaneous Multi-Threading(SMT)を搭載したシステムでは、ワーカースレッドが同じコアを共有するのではなく、物理的に離れたコアで実行されるようにスレッドアフィニティを設定し、CPUリソースの競合を軽減してください。
  7. サウンドエンジンを初期化せずに要求できるワーカーの最大数を変更したい場合は、 AK::SoundEngine::SetJobMgrMaxActiveWorkers を使用してください。これはタイトルの動作状況の変更にいち早く対応したり、マルチスレッド作業でさまざまなコンフィギュレーションを気軽に試したり、プロファイリングしたりするために役立ちます。

上記の推奨事項はゲームのほかのニーズと照らして検討する必要があります。これらの推奨事項のいくつかに従わなくても、Job ManagerがSound Engineの全体的なスループットを向上させる有効な手段であることは間違いありません。

Android

Androidプラットフォームの場合、3つ以上のアクティブなワーカースレッドを AK::SoundEngine::SetJobMgrMaxActiveWorkers で設定してJob Managerで使用することは推奨していません。Androidデバイスで多くのワーカースレッドを使用すると、CPU使用率が高くなりサウンドエンジンの全体的なパフォーマンスが低下する可能性があります。

Job Managerのメモリ使用量の最適化

ジョブの割り当て中に発生したメモリ不足は、致命的な不具合とみなされます。これは、オーディオレンダリングの論理フローが中断され、再開できないためです。これにより、未定義の状態やリソースのリークが発生する場合があります。

これを防ぐために、Job Managerはメモリのスラブを割り当てます。メモリスラブはSound Engineが終了されるまで保持されて再利用されます。これらのスラブのほとんどはSound Engineの初期化時に事前に割り当てられますが、必要に応じて割り当てられるスラブもあります。

メモリスラブのサイズや初期化時に事前に割り当てるスラブの数は、 AkInitSettings::settingsJobManager により制御できます。

注釈: AK::MemoryMgr::Malloc がレンダリング時に新しいメモリスラブを割り当てることができない場合、Job Managerはアロケーションが成功するまで再試行を続けます。Sound Engineが低メモリ状態であることが認められる場合は、初期化設定で事前に割り当てるスラブ数を増やしてください。

このページはお役に立ちましたか?

サポートは必要ですか?

ご質問や問題、ご不明点はございますか?お気軽にお問い合わせください。

サポートページをご確認ください

あなたのプロジェクトについて教えてください。ご不明な点はありませんか。

プロジェクトを登録していただくことで、ご利用開始のサポートをいたします。

Wwiseからはじめよう