スクリプタブルレンダーパイプライン (SRP) バッチャーはレンダリングループで、同じシェーダーバリアントを使用する多くのマテリアルを持つシーンで CPU レンダリングをスピードアップします。
スクリプタブルレンダーパイプライン (SRP) バッチャーを使用するには、プロジェクトで以下のいずれかの スクリプタブルレンダーパイプライン を使用する必要があります。
URP の SRP バッチャーを起動するには。
HDRPでは、SRP バッチャーはデフォルトで有効になっていますので、これを無効にしないでください。ただし、デバッグのために一時的に SRP バッチャーを無効にしたい場合は、以下を行います。
また,ランタイムに 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
モードでのみ使用できます。
Unity では、フレーム内でいつでもマテリアルのプロパティを変更できます。ただし、これにはいくつかの欠点があります。例えば、DrawCall (ドローコール) が新しい Material (マテリアル) を使用する場合、多くの作業が必要になります。つまり、シーン内のマテリアルが多いほど、GPU データを設定するために Unity が使用する CPU も多くなります。これを処理する従来の方法では、DrawCall の数を減らすことで CPU レンダリングコストを最適化します。Unity が DrawCall を送信する前に多くの設定を行う必要があるからです。実際の CPU コストは、GPU DrawCall 自体からではなくその設定によって発生します。GPU DrawCall 自体は、Unity が GPU コマンドバッファにプッシュするために必要な数バイトにすぎません。
SRP バッチャーは、一連の Bind
と Draw
の GPU コマンドをバッチ処理することで、DrawCall 間の GPU 設定を削減します。
レンダリングの最高のパフォーマンスを得るには、これらのバッチをできるだけ大きくする必要があります。これを実現するために、同じシェーダーで異なるマテリアルをいくつでも使用できます。ただし、使用するシェーダーバリアントはできるだけ少なくする必要があります。
内部のレンダリングループ中に、Unity が新しいマテリアルを検出すると、CPU はすべてのプロパティを収集し、GPU メモリにさまざまな定数バッファを設定します。GPU バッファの数は、シェーダーが CBUFFER を宣言する方法によって異なります。
シーンが多くの異なるマテリアルを使用するがシェーダーバリアントが非常に少ない、一般的なケースをスピードアップするために、 スクリプタブルレンダーパイプラインは GPU データ永続性などのパラダイムをネイティブに統合します。
SRP バッチャーは、マテリアルデータを GPU メモリに維持する低レベルのレンダリングループです。マテリアルコンテンツが変わらない場合、SRP バッチャーはバッファを設定して GPU にアップロードする必要はありません。代わりに、SRP バッチャーは専用のコードパスを使用して、以下のように大きな GPU バッファの Unity エンジンのプロパティをすばやく更新します。
CPU は、上の図で Per Object large buffer とラベル付けされている Unity エンジンのプロパティのみを処理します。すべてのマテリアルには、GPU メモリに配置された永続的な CBUFFER があり、すぐに使用できます。これにより、レンダリングが高速化されます。なぜなら、すべてのマテリアル コンテンツが GPU メモリに維持されるようになったからです。また、専用コードは、すべてのオブジェクトごとのプロパティに対して、オブジェクトごとの大きな GPU CBUFFER を管理します。
どのシーンでも、SRP バッチャーと互換性のあるオブジェクトと互換性のないオブジェクトがあります。互換性のないオブジェクトを使用する場合でも、Unity はシーンを適切にレンダリングします。これは、互換性のあるオブジェクトが SRP バッチャーのコードパスを使用し、他のオブジェクトは標準の SRP コードパスを使用するためです。
SRP バッチャーのコードパスでオブジェクトをレンダリングする場合、
シェーダーを SRP バッチャーと互換性を持たせる場合、
unity_ObjectToWorld
や unity_SHAr
などです。UnityPerMaterial
という名前の 1 つの CBUFFER にすべてのマテリアルプロパティを宣言する必要があります。シェーダーの互換性の状況は Inspector パネルで確認できます。
SRP バッチャーを使用する場合に、シーンでの速度の増加を測定するには、SRP バッチャーテンプレートから SRPBatcherProfiler.cs
C# スクリプトをシーンに加えます。このスクリプトの実行時には、F8 キーを使用してオーバーレイ表示を切り替えます。また、F9 キーを使用して、再生中に SRP バッチャーのオンとオフを切り替えることもできます。
オーバーレイは以下のように表示されます。
時間の測定値はミリ秒 (ms) 単位で、CPU が Unity の SRP レンダリングループに要した時間を示します。
ノート: ここでの時間は、スレッドの所有者にかかわらず、フレーム中に呼び出された RenderLoop.Draw
と Shadows.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 の数値を比較します。 |
Frame Debugger ウィンドウで SRP バッチャーの “バッチ” の状況を確認できます。
SRP バッチャーのバッチの状況を確認するには、以下の手順を行います。
SRP Batch の詳細には、使用されたドローコールの数、シェーダーにアタッチされたキーワード、特定のドローコールが前のものと一緒にバッチ処理されなかった理由が表示されます。以下の例では、理由は次のとおりです。Node use different shader keywords (ノードが異なるシェーダーキーワードを使用しています)。つまり、そのバッチのシェーダーキーワードが、前のバッチのキーワードとは異なります。 SRPバッチャーが別のシェーダーバリアントを使用したため、バッチが失敗しました。SRP バッチのドローコール数が少ない場合は、シェーダーバリアントの使用が多すぎる場合が多いです。
URP や HDRP を使用する代わりに、独自の SRP を作成する場合は、最小限のキーワードでジェネリックの “uber” シェーダーを作成するようにしてください (ただし、各マテリアル内で制限なくマテリアルパラメーターとマテリアルプロパティを使用できます)。