グラフィックスパフォーマンスプロファイリング超初級 RenderDoc編

テクニカルアーティストがモバイル業界もコンソール業界も人手不足と聞いて、じゃあ俺がなってやんよ！と ***[株式会社よむネコ](http://www.yomune.co)*** にてテクニカルアーティスト見習いをはじめました。

今回は、レンダリング周り興味あるけど全然分からないって方向けにグラフィックスデバッガの RenderDoc の簡単な使い方をお届けします。誤った内容等ございましたらコメントにてご指摘頂けると幸いです。


対象読者はレンダリング初心者を想定しています。

検証は UnrealEngine4 のフォワードシェーディングで行っております。

## キャプチャ方法

[RenderDoc][RenderDoc] を利用するにはプラグインとログビューワーをインストールする必要があります。
UE4.16 からプラグインは標準でインストールされていますが、ビューワーのインストールは別途必要です。

[RenderDoc][RenderDoc] プラグインを有効化するとレベルビューの右上にキャプチャボタンが表示されます。
ゲームを再生しなくてもキャプチャボタンを押下することでキャプチャすることが出来ます。また、コンソールコマンド **`renderdoc.CaptureFrame`** や **[Alt + F12]** でもキャプチャできます。
![level_view.png](https://qiita-image-store.s3.amazonaws.com/0/1083/c32becb6-f759-38bc-b497-c825103ae8a1.png)

[RenderDoc]:https://renderdoc.org

キャプチャ後、RenderDoc が起動するので、**localhost - UE4Editor** タブのスクリーンショットを選択し、キャプチャデータをロードします。
ロード後、**Event Browser** のストップウォッチボタンを押すと処理時間を取得できます。
![renderdoc_load_log.png](https://qiita-image-store.s3.amazonaws.com/0/1083/e0f27a5a-26fd-b845-4d37-79d5cefc3e38.png)



## Event Browser

**Event Browser** の **Frame/Scene** がこのシーンのレンダリングに要した総処理時間です。**Frame/Scene** 内の重要なパスを次に紹介します。

### PrePass

*BasePass* に先んじて *DepthBuffer* を生成する。
ここで生成した *DepthBuffer* は *ShadowProjection* や、*DBufferDecal*、*BasePass*
 で利用される。
**Opaque** タイプで条件に適応する[^1]マテリアルはピクセルシェーダーを無効化(null pixel shader)にすることが出来て高速に広い領域を塗りつぶす事ができます。
**Masked** タイプのマテリアル や **LOD Dither transition** 設定を使った場合軽量なピクセルシェーダーが起動します。中身はライティング計算等が省かれているので軽量です。
ここが重い場合は頂点数が多いか、ドローコール数が多いかのどちらかなので、適切にカリングしたり、メッシュをまとめたり[^2]、LOD[^3]を適切に利用すると良いらしい

[^1]: DepthBufferの情報と比較し最前面でないマテリアル
[^2]: まとめ過ぎた大きなメッシュは、カメラに入らない部分も頂点計算される
[^3]: ピクセルより小さいポリゴンは無駄

### ShadowDepth
シャドウマップを作ります。
負荷特性は *PrePass* とだいたい同じです。
**CascadedShadow** を使う場合は大きなサーフェスに *Movable Mesh* を全部突っ込みます。
**PerObjectShadow** を用いる場合はメッシュ毎に小さな領域を割り当ててレンダリングしていきます。

### ShadowProjection
*ShadowDepth* パスで生成したシャドウマップと *PrePass* で生成した *DepthBuffer* を参照して、スクリーンスペースに影になる領域を描画します。
**CascadedShadow** を用いた場合はカスケードの段数分ドローコールが走ります。
**PerObjectShadow** の場合そのメッシュの数だけドローコールが積まれるので、
ドローコール数が多くて厳しい場合は **CascadedShadow** にすることで **GPU** や **RenderingThread** の負荷を軽減できるかもしれません。

### BasePass
実際に画面に色を塗る。
大雑把に言うと、頂点負荷 + ピクセルシェーダー負荷で、(*BasePass* - *PrePass*) がピクセルシェーダー負荷。
負荷は基本的に塗る面積に比例するので、同等の面積のオブジェクトと比べて重い場合は次のような対策で軽減できるかもしれない。

- テクスチャフォーマットの見直し[^4]
- テクスチャサイズの最適化[^5]
- ピクセルシェーダーの最適化[^6]

[^4]: 圧縮テクスチャを利用することでテクスチャの読込を高速化できる
[^5]: 必要以上に大きいテクスチャは、キャッシュ効率が悪い
[^6]: [Pipeline State > Pixel Shader (PS)] タブの *View* ボタンを押すことで中間コンパイルされたシェーダーコードを表示できる。基本的に長いほど重い。

### Translucency
半透明によるオーバードロー負荷。
半透明☓ライティングはちょう重い。だいたいパーティクルが犯人なので、重いものはアーティストに直してもらう。

### PostProcessing

ポストプロセスボリュームの設定より固定負荷。

## Mesh Output

メッシュ情報を参照できます。
**Preview** タブの **VS Input**, **VS Output** で、頂点シェーダーへの入力/出力のプレビューを見ることが出来ます。
基本的には入力と出力に同形状のものが表示されると思いますが、**ShadowDepth** では、入力されたメッシュの形状と、出力された影の形状が確認できます。
![vs_output.PNG](https://qiita-image-store.s3.amazonaws.com/0/1083/66b86a45-b90a-455a-def1-440184988530.png)

![vs_output_.PNG](https://qiita-image-store.s3.amazonaws.com/0/1083/3d3509f0-0cdd-6ccb-918a-56d15d3a1dbe.png)

## Texture Viewer

**Overlay** 設定で **Highlight Drawcall** か **Wireframe Mesh** を選択することで、各ドローコールで描かれている順序、場所、面積がわかります。
![texture_viewer_1.png](https://qiita-image-store.s3.amazonaws.com/0/1083/0a6407f2-6f30-a587-069c-7503a805e957.png)
↓↓↓
![texture_viewer_2.png](https://qiita-image-store.s3.amazonaws.com/0/1083/3341a71b-5525-02b2-ff38-027f37e51047.png)

**Inputs** タブで参照しているテクスチャを見ること出来ます。
![texture_viewer_3.png](https://qiita-image-store.s3.amazonaws.com/0/1083/ebc5fbbb-1fbc-289f-6b8a-a95ba73a3a53.png)

**Overlay** 設定で **Quad Overdraw** でオーバードローしているピクセルを表示できます。
![quad_overdraw.png](https://qiita-image-store.s3.amazonaws.com/0/1083/46eddc23-68d9-215f-a0df-f52ad6b5836f.png)


## さいごに
**[よむネコ](http://www.yomune.co/)**では、世界を変えるVRコンテンツを共に作る仲間を募集しています。