Version: 2020.1
言語: 日本語
スクリプタブルレンダーパイプラインにおけるレンダリングコマンドのスケジューリングと実行
カスタムレンダーパイプラインの作成

スクリプタブルレンダーパイプラインバッチャー

スクリプタブルレンダーパイプライン (SRP) バッチャーはレンダリングループで、同じシェーダーバリアントを使用する多くのマテリアルを持つシーンで CPU レンダリングをスピードアップします。

スクリプタブルレンダーパイプライン (SRP) バッチャーは、同じシェーダーバリアントを使用する多くのマテリアルを持つシーンでの CPU レンダリングをスピードアップします。
スクリプタブルレンダーパイプライン (SRP) バッチャーは、同じシェーダーバリアントを使用する多くのマテリアルを持つシーンでの CPU レンダリングをスピードアップします。

SRP バッチャーの使用

スクリプタブルレンダーパイプライン (SRP) バッチャーを使用するには、プロジェクトで以下のいずれかの スクリプタブルレンダーパイプライン を使用する必要があります。

URP の SRP バッチャーを起動するには。

  1. Project ウィンドウで、URP アセット を選択します。
  2. アセットの Inspector で Advanced セクションに移動し、SRP Batcher チェックボックスを有効にします。
URP または HDRP のアセットでそれぞれ SRP Batcher を無効にすることができます。SRP Batcher はデフォルトで有効になっています。
URP または HDRP のアセットでそれぞれ SRP Batcher を無効にすることができます。SRP Batcher はデフォルトで有効になっています。

HDRPでは、SRP バッチャーはデフォルトで有効になっていますので、これを無効にしないでください。ただし、デバッグのために一時的に SRP バッチャーを無効にしたい場合は、以下を行います。

  1. Project ウィンドウで、HDRP アセット を選択します。
  2. アセットの Inspector で、デバッグモード にします。これにより、HDRP アセットのプロパティの表示方法が変わり、SRP Batcher のプロパティが表示されるようになります。
  3. SRP Batcher のチェックボックスを無効にします。

また,ランタイムに SRPバッチャーを有効/無効にすることもできます。そのためには、C# コードの中で以下のグローバル変数を切り替えます。

GraphicsSettings.useScriptableRenderPipelineBatching = true;`

サポートするプラットフォーム

SRP バッチャーはほとんどすべてのプラットフォームで動作します。この表は、サポートされているプラットフォームと必要最低限の Unity のバージョンを示しています。

Platform 必要な最低限の Unity バージョン
Windows DirectX 11 2018.2
PlayStation 4 2018.2
Vulkan 2018.3
OSX Metal 2018.3
iOS Metal 2018.3
* Nintendo Switch 2018.3
Xbox One DirectX 11 2019.2
OpenGL 4.2 以上 2019.1
OpenGL ES 3.1 以上 2019.1
Xbox One DirectX 12 2019.1
Windows DirectX 12 2019.1

ノート: XR の場合、SRP バッチャーは SinglePassInstanced モードでのみ使用できます。

SRP バッチャーの仕組み

Unity では、フレーム内でいつでもマテリアルのプロパティを変更できます。ただし、これにはいくつかの欠点があります。例えば、DrawCall (ドローコール) が新しい Material (マテリアル) を使用する場合、多くの作業が必要になります。つまり、シーン内のマテリアルが多いほど、GPU データを設定するために Unity が使用する CPU も多くなります。これを処理する従来の方法では、DrawCall の数を減らすことで CPU レンダリングコストを最適化します。Unity が DrawCall を送信する前に多くの設定を行う必要があるからです。実際の CPU コストは、GPU DrawCall 自体からではなくその設定によって発生します。GPU DrawCall 自体は、Unity が GPU コマンドバッファにプッシュするために必要な数バイトにすぎません。

SRP バッチャーは、一連の BindDraw の GPU コマンドをバッチ処理することで、DrawCall 間の GPU 設定を削減します。

Bind と Draw コマンドのバッチ処理により、ドローコール間の GPU 設定が削減されます。
Bind と Draw コマンドのバッチ処理により、ドローコール間の GPU 設定が削減されます。

レンダリングの最高のパフォーマンスを得るには、これらのバッチをできるだけ大きくする必要があります。これを実現するために、同じシェーダーで異なるマテリアルをいくつでも使用できます。ただし、使用するシェーダーバリアントはできるだけ少なくする必要があります。

内部のレンダリングループ中に、Unity が新しいマテリアルを検出すると、CPU はすべてのプロパティを収集し、GPU メモリにさまざまな定数バッファを設定します。GPU バッファの数は、シェーダーが CBUFFER を宣言する方法によって異なります。

シーンが多くの異なるマテリアルを使用するがシェーダーバリアントが非常に少ない、一般的なケースをスピードアップするために、 スクリプタブルレンダーパイプラインは GPU データ永続性などのパラダイムをネイティブに統合します。

SRP バッチャーは、マテリアルデータを GPU メモリに維持する低レベルのレンダリングループです。マテリアルコンテンツが変わらない場合、SRP バッチャーはバッファを設定して GPU にアップロードする必要はありません。代わりに、SRP バッチャーは専用のコードパスを使用して、以下のように大きな GPU バッファの Unity エンジンのプロパティをすばやく更新します。

これは SRP バッチャーのレンダリングワークフローです。SRP バッチャーは専用のコードパスを使用して、大きな GPU バッファの Unity エンジンのプロパティをすばやく更新します。
これは SRP バッチャーのレンダリングワークフローです。SRP バッチャーは専用のコードパスを使用して、大きな GPU バッファの Unity エンジンのプロパティをすばやく更新します。

CPU は、上の図で Per Object large buffer とラベル付けされている Unity エンジンのプロパティのみを処理します。すべてのマテリアルには、GPU メモリに配置された永続的な CBUFFER があり、すぐに使用できます。これにより、レンダリングが高速化されます。なぜなら、すべてのマテリアル コンテンツが GPU メモリに維持されるようになったからです。また、専用コードは、すべてのオブジェクトごとのプロパティに対して、オブジェクトごとの大きな GPU CBUFFER を管理します。

SRP バッチャーの互換性

どのシーンでも、SRP バッチャーと互換性のあるオブジェクトと互換性のないオブジェクトがあります。互換性のないオブジェクトを使用する場合でも、Unity はシーンを適切にレンダリングします。これは、互換性のあるオブジェクトが SRP バッチャーのコードパスを使用し、他のオブジェクトは標準の SRP コードパスを使用するためです。

SRP バッチャーのコードパスでオブジェクトをレンダリングする場合、

  • レンダリングされるオブジェクトはメッシュかスキンメッシュでなければなりません。パーティクルにすることはできません。
  • シェーダーは、SRP バッチャーと互換性がある必要があります。HDRP と URP のすべての Lit と Unlit シェーダーはこの要件に適合します (これらのシェーダーのパーティクルバージョンを除く)。
  • レンダリングされたオブジェクトは、MaterialPropertyBlock を使用できません。

シェーダーを SRP バッチャーと互換性を持たせる場合、

  • “UnityPerDraw” という名前の 1 つの CBUFFER ですべてのビルトインのエンジンプロパティを宣言する必要があります。例えば、unity_ObjectToWorldunity_SHAr などです。
  • UnityPerMaterial という名前の 1 つの CBUFFER にすべてのマテリアルプロパティを宣言する必要があります。

シェーダーの互換性の状況は Inspector パネルで確認できます。

特定のシェーダーの Inspector でシェーダーの互換性を確認できます。
特定のシェーダーの Inspector でシェーダーの互換性を確認できます。

SRP バッチャーによるプロファイリング

SRP バッチャーを使用する場合に、シーンでの速度の増加を測定するには、SRP バッチャーテンプレートから SRPBatcherProfiler.cs C# スクリプトをシーンに加えます。このスクリプトの実行時には、F8 キーを使用してオーバーレイ表示を切り替えます。また、F9 キーを使用して、再生中に SRP バッチャーのオンとオフを切り替えることもできます。

オーバーレイは以下のように表示されます。

SRP バッチャーオーバーレイでは、SRP バッチャーで何が起こっているかに関する詳細情報を見ることができます。
SRP バッチャーオーバーレイでは、SRP バッチャーで何が起こっているかに関する詳細情報を見ることができます。

時間の測定値はミリ秒 (ms) 単位で、CPU が Unity の SRP レンダリングループに要した時間を示します。

ノート: ここでの時間は、スレッドの所有者にかかわらず、フレーム中に呼び出された RenderLoop.DrawShadows.Draw マーカーのすべての累積時間です。例えば、1.31ms の SRP バッチャーコードパスがある場合、おそらくドローコールはメインスレッドで 0.31ms を費やしており、1ms はすべてのグラフィックスジョブにスプレッドに分散しています。

オーバーレイ情報

次の表では、 再生モードで表示される SRP バッチャーオーバーレイの各設定について説明します。

オーバーレイ内の名前 説明
(SRP batcher ON) / (SRP batcher OFF) 現在の SRP バッチャーが有効かどうかを示します。 SRP バッチャーのオンとオフを切り替えるには、F9 を押します。
CPU Rendering time どのマルチスレッドモードが使用されているかにかかわらず (シングル、クライアント/ワーカー、 グラフィックスジョブなど)、SRP ループが CPU で費やした合計時間を示します。ここで、SRP バッチャーの効果を最もよく把握することができます。バッチャーの最適化を確認するには、バッチャーのオンとオフを切り替えて CPU 使用率の違いを確認します。この例では、合計は 2.11 ミリ秒です。
(RT アイドルを含む): SRP がレンダリングスレッドで費やしたアイドル時間を示します。これは、アプリケーションがグラフィックスジョブのないクライアント/ワーカーモードであったことを意味します。これは、レンダリングスレッドがメインスレッドで グラフィックスコマンドを待機する必要があるときに発生します。この例では、レンダリングスレッドは 0.36 ミリ秒間アイドル状態でした。
SRP Batcher code path (flushes) SRP バッチャーのコードパスでゲームやアプリが費やした時間を示します。これは、ゲームが All objects (すべてのオブジェクト、ただしシャドウパスを除く) (1.18 ミリ秒) と Shadows (影) (1.13 ミリ秒) をレンダリングした時間に分けて表示されます。 Shadows の値が高い場合は、シーン内の影を作るライトの数を減らすか、レンダーパイプラインアセットでカスケードの数を減らしてみてください。この例では 1.31ms でした。
(flush(s)) の数値は、新しいシェーダーバリアント (この例では 89) の検出によって Unity がシーンをフラッシュした回数を示しています。フラッシュの数は、常に少ないほど良いと言えます。なぜなら、フレーム内のシェーダーバリアント数が少ないことを意味するためです。
Standard code path (flushes) パーティクルなど SRP バッチャーに対応していないオブジェクトのレンダリングに Unity が費やした時間を示します。
この例では、SRP バッチャーは 81 個のオブジェクトを 0.80 ミリ秒 (シャドーパスに 0.09 ミリ秒、その他のパスに 0.71 ミリ秒)でフラッシュ (出力) しました。
Global Main Loop: (FPS) グローバルなメインループ時間をミリ秒単位で、それに相当するものをフレーム/秒 (FPS) 単位で示します。ノート: FPS はリニアではないため、FPS が 20 増加しても、必ずしもシーンが最適化されたとは言えません。SRP バッチャーがシーンレンダリングを最適化するかどうかを確認するには、それを ON と OFF に切り替え、CPU Rendering time の数値を比較します。

Unity フレームデバッガーの SRP バッチャーデータ

Frame Debugger ウィンドウで SRP バッチャーの “バッチ” の状況を確認できます。

SRP バッチャーのバッチの状況を確認するには、以下の手順を行います。

  1. エディターで、 Window > Analysis > Frame Debugger > Render Camera > Render Opaques の順に移動し、RenderLoopNewBatcher.Draw リストを展開します。
  2. 検査したい SRP Batch をクリックします。

SRP Batch の詳細には、使用されたドローコールの数、シェーダーにアタッチされたキーワード、特定のドローコールが前のものと一緒にバッチ処理されなかった理由が表示されます。以下の例では、理由は次のとおりです。Node use different shader keywords (ノードが異なるシェーダーキーワードを使用しています)。つまり、そのバッチのシェーダーキーワードが、前のバッチのキーワードとは異なります。 SRPバッチャーが別のシェーダーバリアントを使用したため、バッチが失敗しました。SRP バッチのドローコール数が少ない場合は、シェーダーバリアントの使用が多すぎる場合が多いです。

Frame Debug ウィンドウでは、SRP バッチャーが既存のバッチを継続する代わりになぜ新しいバッチを作成したかなど、個々のバッチの詳細を確認できます。
Frame Debug ウィンドウでは、SRP バッチャーが既存のバッチを継続する代わりになぜ新しいバッチを作成したかなど、個々のバッチの詳細を確認できます。

URP や HDRP を使用する代わりに、独自の SRP を作成する場合は、最小限のキーワードでジェネリックの “uber” シェーダーを作成するようにしてください (ただし、各マテリアル内で制限なくマテリアルパラメーターとマテリアルプロパティを使用できます)。

スクリプタブルレンダーパイプラインにおけるレンダリングコマンドのスケジューリングと実行
カスタムレンダーパイプラインの作成