📗

【Unity Summary】 Graphic's performance & profile

2025/02/18に公開

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 は増加する
  • 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 でも動作する
  • 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 は増加する
  • 適切な圧縮形式を使用して、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