📗
【Unity Summary】 Graphic's performance & profile
Tutorial
reference:https://learn.unity.com/tutorial/fixing-performance-problems-2019-3#
Reduce redering CPU cost
- 最も影響するのは、GPU に Rendering command を送信するためのコスト
- Rendering command は以下から構成される
- (Geometry を描画する前に)GPU の設定を変更する command
- Geometry を描画する command(Draw call)
Object 数を減らす
solution | note |
---|---|
Skybox を使用 | 遠くの Geometry の効果を作成 |
厳密な Culling を使用 | 描画する Object 数を削減 |
Occlusion Culling を使用 | 他 Object の後ろに隠れている Object を描画しない |
Camera の Far Clip 面を小さくする | より遠くにある Object がその錐台の外になるようにする |
Object を 別 Layer に入れる | Camera.layerCullDistances で Layer 毎に Culling の距離設定 |
Rendering 回数を削減
- Light Mapping を使用して、必要に応じて Light と影を "Bake"(事前計算)する
- Runtime の Performance 向上可能
- Build time、Runtime memory usage、Storage space は増加する
- Runtime の Performance 向上可能
- Forward Rendering(使用する場合)
- Object に影響を与える pixel 単位の Realtime Light の数を減らす
- Realtime Shadow は、非常に多くの Resource を必要とするので、控えめかつ効率的に使用する
- Reflection Globe(使用する場合)
- 使用方法を最適化する
Rendering command を準備し送信するのに必要な作業量を減らす
- 通常より効率的な "Batch" で GPU に送信する方法を使用
Reduce redering GPU cost
以下、GPU が frame を rendering する時間内に作業を完了できない主な理由3つ
Application が Fill rate によって制限されている場合
原因
- GPU が frame 当たりに処理可能な pixel 数よりも多く描画しようとしている
対策
- Application の over draw を特定・削減する
- over draw の最も一般的な原因は、UI、Particle、Sprite(2D Graphic Object)などの重なり合った透明な要素
- Unity Editor では Overdraw mode を使用して特定可能
- Fragment shader の実行コストを削減
- Buit-in Shader を使用する場合、「Mobile」または「Unlit」の category から選択する
- より複雑な Shader の簡素化され、近似化された version
- mobile でない Platform でも動作する
- より複雑な Shader の簡素化され、近似化された version
- Dynamic Resolution を検討
- 個々の Render target を動的に scale する機能
Application が memory 帯域幅によって制限されている場合
原因
- frame 内で処理できる以上のデータを専用 memory に読み書きしようとしている
- Texture が 多すぎ or 大きすぎ
対策
- Runtime に Camera からの距離が変化する Texture(3D Scene で使用されるほとんどの Texture)に対して、Mipmap を有効にする
- Runtime の GPU Performance 向上可能
- Texture の memory usage と storage space は増加する
- Runtime の GPU Performance 向上可能
- 適切な圧縮形式を使用して、memory 内の Texture の size を削減
- load 時間を短縮し、memory foot print(専有領域)を縮小し、GPU Rendering Performance を改善
Application が頂点処理によって制限される場合
原因
- GPU が 1 frame で処理できるよりも多くの頂点を処理しようとしている
対策
- 頂点 Shader の実行コストを削減
- Geometry を最適化する
- 必要以上の三角形を使用しない
- UV mapping の継ぎ目と Hard edge(2重化した頂点)をできるかぎり少数に抑える
- Level Of Detail system を利用する
Optimize Draw call
- 画面に Geometry を描画するために、Unity は Graphics API に対して Draw call を送信する
- Draw call は Graphics API に対して、「何」を「どのように」描画するかを指示する
- 各 Draw call には、 Texture・Shader・Buffer に関する情報など、Graphics API が画面に描画するために必要なすべての情報が含まれている
- Draw call は Resource を消費するが、多くの場合 Draw call 自体よりも、 Draw call の準備の方に多く Resource が消費される
- Draw call に備えるため、CPU は Resource を準備し、GPU の内部設定を変更する
- これらの設定はまとめて「Render 状態」と呼ばれる
- Render 状態の変更(別 Material に切り替えるなど)は、 Graphics API が実行する中で最も Resource を消費する操作
- Render 状態の変更を最適化する主な方法は、「Render 状態の変更の回数を減らす」こと
- Draw call の総数を減らす
- Render 状態の変更回数を減らす方法で Draw call を整理
- Graphics API が同じ Render 状態を使用して複数の Draw call を実行する場合、 Draw call を Group 化し、 Render 状態の変更をそれほど多く実行する必要がなくなる
- 以下、Draw call と Render 状態の変更を最適化することによる利点
- frame 時間が改善(main)
- Application が必要とする電力量を削減
- device の電池消耗を抑制
- Application の実行時に device が発する熱も減少
- Application の今後の開発における保守性向上
- Draw call や Render 状態の変更を早期に最適化することで、 Performance の大きな overhead を発生させることなく、Scene に GameObject を追加可能
methods
GPU Instancing
- 同じ Mesh の複数 copy を同時に Rendering
- 樹木や茂みなど、Scene に何度も現れる Geometry を描画するのに便利
静的 Batch 処理
- 静的 GameObject の Mesh を事前に結合しておき、結合したデータを GPU に送る
- 結合された各 Mesh は個別に Rendering される
- Unity は Mesh を個別に Culling することができるが、データの状態が変化しないので、各 Draw call の Resource 消費は少なくなる
動的 Batch 処理
- CPU 上で Mesh の頂点を変換し、同じ構成を共有する頂点を Group 化
- 1 回の Draw call で Group 化した頂点を Rendering
- 頂点が同じ構成を共有するのは、例えば、position(位置)と normal(法線)のような同じ数と種類の属性をもつ場合など
手動で Mesh 結合
-
Mesh.CombineMeshes()
を使用して、複数の Mesh を手動で1つの Mesh に結合- Mesh 毎に1回の Draw call ではなく、結合 Mesh を1回の Draw call で Rendering
SRP Batcher
- project で Scriptable Render Pipeline (SRP) を使用する場合、同じ Shader variant を使用する Material の Draw call の準備と dispatch に必要な CPU 時間を短縮する
GPU Instancing
Static Batch Process
- 静的 GameObject に対して、Unity はそれらを結合し、まとめて描画
- 結合された Mesh を World 空間に変換し、1 つの共有頂点と Index Buffer を構築
- その後、Unity はこの結合された Mesh を使用して Batch 内の全ての Object を一度に描画する単一の Draw call を実行
- 静的 Batch 処理は CPU で頂点を変換しないので、動的 Batch 処理 よりも効率的
- memory と Strage の overhead が発生する点に注意
- memory foot print(専有領域)を小さくしたい場合は、 Rendering Performance を犠牲にして、いくつかのGameObject の静的 Batch 処理を避けることが必要かもしれない
- たとえば、密集した森林環境で樹木を静的とマークすると、 memory に深刻な影響を与える可能性がある
Dynamic Batch Process
- 「かなり小さい Mesh」に対し、その頂点を「CPU」上に変換して多数の類似したものを群にし、1回の Draw call で描画
- GPU ではなく CPU で全ての頂点を World 空間に変換して行う
- CPU の overhead が発生する点に注意
- 元々は古い lowend device での最適化のために用意された機能
- 最近のハードウェアでは、動的 Batch 処理が CPU で行う作業が Draw call の overhead よりも大きくなる可能性がある
- 例えば、コンソールや Apple Metal のような最新の API では、一般に Draw call の overhead ははるかに低く、多くの場合、動的 Batch 処理では Performance の向上は望めない
手動による Mesh 結合
Scriptable Render Pipeline (SRP) Batcher
- 「同じ Shader variant を使用する Material を多く含んだ Scene」の Rendering に要する CPU 時間を短縮
Statistics
statistics | description |
---|---|
FPS | 1 秒間に描画可能な frame 数 |
CPU(Main) | 1 frame を処理するのに掛かった合計時間(frame 更新処理や Editor task 処理に掛かった時間など) |
CPU(Render) | 1 frame の Rendering に掛かった時間 |
Batches | 1 frame で処理する Draw call Batch の総数(静的、動的 および Instance Batch が含まれる) |
Saved by batching | Batch にまとめた Draw call の数 |
Tris | 1 frame 中に処理する三角形の数 |
Verts | 1 frame 中に処理する 頂点 の数 |
Screen | 画面の解像度や画面が使用する memory 量 |
SetPass | frame 中の GameObject の Rendering に使用する Shader path を Unity が切り替えた回数(CPU overhead が発生) |
Shadow casters | frame 中の影を作る GameObject の数 |
Visible skinned meshes | frame 中の スキンされた Mesh Renderer の数 |
Animation components playing | frame 中に再生される Animation component の数 |
Animator components playing | frame 中に再生される Animator componenent の数 |
Frame Debugger window
- Rendering イベントの情報を表示し、構築中の frame の再生を制御
- イベント階層からイベントを選択すると、そのイベントまでの(そのイベントも含む)Scene が表示される
- イベント情報パネルにはイベントに関する情報が表示される
- UI 上のボタン操作により、frame 間を liner(リニア:直線的)に移動可能
- 詳細な分析方法(画面の見方、それぞれの値が表す意味など)は以下を参照
Discussion