Unity Oculus Quest パフォーマンス最適化で便利なツール


年末にOculus Quest 2を購入してUnityで開発を始めました。
まだ絶賛開発中ですが最適化で使った便利なツールたちをサクッと紹介します。

## 作っているもの
Oculus Riftが発売されたときにホラーゲームを作りました。
Questも2世代目になり、Riftで動かしていたクォリティをQuestにどこまで落とし込めるか試してみました。

Oculus Storeで無料で配信中です。ちなみにこれはUE4で作りました。
<img width="400" src="https://cgworld.jp/interview/images/201802_gray/gray_f2_2.jpg">
https://www.oculus.com/experiences/rift/1811961072194113/?locale=ja_JP

## 最適化フロー
大まかな手順としては上から順に以下のような流れで行いました。
・OVRメトリックツール
・Unity Profiler
・Unity Frame Debugger
・Render Doc
・OVR GPU Profiler
・Snapdragon Profiler

### OVRメトリックツール
まずはOVRメトリックツールを使用してフレームレートやCPU・GPUの負荷をざっくり把握します。
https://developer.oculus.com/documentation/tools/tools-ovrmetricstool/

<img width="400" src="https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/94243477_542562443340939_4457165421673447424_n.png?_nc_cat=110&ccb=2&_nc_sid=ad8a9d&_nc_ohc=INQN3Yr1rVwAX8VKSrh&_nc_ht=scontent-nrt1-1.xx&oh=060fa8e1c6f308942b806883ebda1b67&oe=601A5050">
開発アプリにオーバーレイでパフォーマンスを知ることができます。
利用方法はAPKを開発PCにダウンロードし、adbでQuestにインストールします。

### Unity Profiler
<img width="400" src="https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/107548291_600087624255087_3041950727849110642_n.png?_nc_cat=111&ccb=2&_nc_sid=ad8a9d&_nc_ohc=csTJtbUATWcAX8DHlT4&_nc_oc=AQkyCdAIZIYHRITikt_PNEnQsmSCaf8FB-lfg9y0-YiqkEtv81i-rlruR8wvvtGsBBM&_nc_ht=scontent-nrt1-1.xx&oh=aed98f2e9d248f2adb21e70e0d6c865c&oe=601902A4">
https://docs.unity3d.com/ja/2018.4/Manual/ProfilerWindow.html
次にUnity Profilerを使用してもう少し詳細な状況を把握します。
主にCPU側の負荷を詳しく見ることができます。

描画が重すぎると「Gfx.WaitForRenderThread」という処理がとても長くなることがあります。
これは描画が追いつかず、フレームをスキップした時のCPU Idle時間です。

### Unity Frame Debugger
<img width="400" src="https://docs.unity3d.com/ja/2019.4/uploads/Main/FrameDebugger.jpg">
https://docs.unity3d.com/ja/2019.4/Manual/FrameDebugger.html
GPUが遅そうな場合まずUnity Frame Debuggerを用いて描画内容をチェックします。
SRP Butcherがうまく動いているか、StaticBatchingの状況を確認できます。

### Render Doc
<img width="400" src="https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/80734366_450506692546515_7555338195152404480_n.png?_nc_cat=105&ccb=2&_nc_sid=ad8a9d&_nc_ohc=YMUFW6ZxWYEAX965xZl&_nc_ht=scontent-nrt1-1.xx&oh=8bccfb625e80fecbb31e0c15e540757f&oe=6019574D">
続いてRender Docを用いて描画内容をより詳しくチェックします。
開発PCからQuestに接続してフレームキャプチャができます。
Vulkanを使用した場合、APIの知識が無いと把握することが難しいですが生のドローコールやリソースバインド状況をすべてチェックできます。

### OVR GPU Profiler
https://developer.oculus.com/documentation/tools/tools-ovrgpuprofiler/
OVRメトリックツールを使用中にadbでプロファイル内容を指定するとログが出力できます。
GPUのキャッシュ使用率、ドローコールごとのラスタライザの描画範囲をチェック可能です。
GPUのハードウェアの知識と、Mobileプラットフォーム特有の仕様(タイルレンダリングなど)の知識が必要です。

テクスチャキャッシュヒット率が低い場合はテクスチャの解像度を下げたり、リピートさせてキャッシュヒット率を改善させます。

### Snapdragon Profiler
<img width="400" src="https://developer.qualcomm.com/sites/default/files/attachments/snapdragon-profiler-realtime-mode.png">
https://developer.qualcomm.com/software/snapdragon-profiler
これはGPUベンダーが提供しているプロファイルツールです。
Render Docとほぼ同じですが、ハードウェアのパフォーマンスカウンタなどより詳細な情報を入手可能です。

# そのほか
### USBケーブルを接続しながら開発を長時間行うとサーマルスロットリングが発生する
adb接続のために通常はケーブルを接続しますが、充電も同時に行われるためQuestがアツアツになってします。
温度が上がりすぎるのを防ぐため、Questが温度上昇を検知するとCPUやGPUのクロックが下がります。
対策としてはadb接続にWifiを用いてワイヤレスにするとか濡れティッシュをかぶせて放熱対策をします。
[Wifiでadb接続する](https://developer.android.com/studio/command-line/adb?hl=ja)

### 忘れがちなテンプレUnity設定
プロジェクトを作り直すたびに忘れがち。

**・テクスチャフォーマットをASTCにする**
　→ ETC2より品質が良いです。よりテクスチャサイズを削減することができます。
**・ライトマップ最大解像度を4096にする**
　→ ライトマップが分割されているとリソースの切り替えが増えます。テクスチャアトラスと同様の原理です。
**・XR設定のレンダリングモードをMultiViewにする**
 → シングルパスステレオレンダリングを有効にします。そうでないと両目の描画を別々に行いドローコールが2倍になります。
**・Player設定のGraphics APIをVulkanのみにする**
　→ OpenGL ESよりCPUオーバーヘッドが少ないです。OpenGLESにできてVulkanにできない機能はありません。
**・Player設定のGraphics JobとMulti Thread Renderingを有効にする**
　→ メニーコアの利点をより生かすために複数スレッドに描画コマンドの積み込みを分散させます。
**・カメラのFarClipを標準の1000mから可能な限り小さくする**
　→ カリング効率を上げるため。どうしても厳しい場合Fogを利用してFarClipの切れ目をごまかします。
**・アンチエイリアスにMSAAx4を設定し、OVRManagerのUse Recommended MSAA Levelを有効にする**
　→ OVRManagerでMSAAレベルを操作できるようにします。

ざっくり過ぎましたが、開発が進みましたらより詳細な情報を記事にしたいと思います。