【UIToolkit】ドローコールのバッチ最適化

https://www.youtube.com/watch?v=n2sN28VWkBs&t=615s

UIToolkitのパフォーマンスについての公演が日本語翻訳されていました
その内容からの抜粋です

# 概要
ドローコールとは「グラフィックスAPIを通して、画面への描画内容を指示すること」を指します

https://docs.unity3d.com/ja/2022.3/Manual/optimizing-draw-calls.html#:~:text=%E3%83%89%E3%83%AD%E3%83%BC%E3%82%B3%E3%83%BC%E3%83%AB%E3%81%AF%E3%82%B0%E3%83%A9%E3%83%95%E3%82%A3%E3%83%83%E3%82%AF%E3%82%B9,%E3%81%8C%E5%90%AB%E3%81%BE%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82
>ドローコールはグラフィックス API に対して、何をどのように描画するかを指示します。各ドローコールには、テクスチャ、シェーダー、バッファに関する情報など、グラフィックス API が画面に描画するために必要なすべての情報が含まれています。

また、ドローコールの数がパフォーマンスに直結します

https://tech.drecom.co.jp/what-is-drawcall/

> 描画コマンドの処理は、DrawCall を一つの基準としてドライバが処理するため、DrawCall の増加が > CPU の負荷となります。
> 
> - コマンドバッファの蓄積
> - コマンドバッファ(レンダーステート)の正当性のチェック
> - ネイティブな描画命令への変換
> - GPU への転送

そのため、ドローコールを減らすことはゲーム全体で意識することが必要です

Unityでは<b>Frame Debugger</b>というツールで、各ドローコールの詳細を確認することができます
複数の描画要素を一つのドローコールにまとめるバッチ処理がどのように行われているかも確認できます

Unity6ではGameパネルに虫さんマークが追加されており、これを押すことで簡単にFrame Debuggerを開くことができます

![スクリーンショット 2024-12-22 21.07.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/96c0db20-7d8e-0336-61f5-2eb2c4267748.png)


この記事では、UIToolkitにおけるドローコール削減テクニックについて解説します

# 頂点バッファによるBatching
UIToolkitでは、内部で頂点バッファを持っています
頂点バッファはパネルが作られる際にメモリが確保され、そればいっぱいになると新しい頂点バッファが作られます

頂点バッファごとにドローコールが作成されるため、頂点バッファを大きくすることでドローコールを抑えられることができます

<br>

こんなUIを用意してみました
![スクリーンショット 2024-12-22 21.34.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/72ab8219-f6b4-57cd-5858-d6ec0dd7d69a.png)

8この要素が並んでいます
![スクリーンショット 2024-12-22 21.38.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/0010a48e-1694-aa23-4b1c-b99be3de3b83.png)
全て同じテクスチャを使っており、１つのドローコールにまとめられています

ここで男の子をいっぱい増やしてみます
![スクリーンショット 2024-12-22 21.33.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/dafde7ff-b7c4-06ed-39f3-4d91d8f905b9.png)

なんとドローコールが2つに分かれています
![7GkfclLXHCyxZPM8NT2i1734871613-1734871620.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/fb816f49-9a86-4877-eb0c-aafe84164d4f.gif)

これは大量の画像によって頂点バッファが2つに分けられてしまったために、ドローコールがわけれられてしまっているのです

ここで頂点バッファの大きさを大きくしてみます

![スクリーンショット 2024-12-22 21.51.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/672473ad-d468-0723-5a8e-c178fd9696d7.png)

頂点数を15000まで増やしてみました

![スクリーンショット 2024-12-22 21.52.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/ebd89b42-fddd-5ec9-cc88-76a16e925d34.png)
すると1つのドローコールにまとまります

頂点バッファが溢れなくなったことで、バッチングされるようになりました

このサンプルでは746個の要素が配置されており、ちょうど分けられなくなる頂点バッファサイズは8952でした
1要素ごとの正確な頂点はドキュメントを見つけられませんでしたが、ちょうど12倍なことから、矩形でも12頂点を使ってしまうようです

バッファサイズはメモリ確保量と直結するため、プロジェクト全体で確保しないよう気をつけてください

# テクスチャ周りのBatching
UIToolkitではテスクチャの違いによってドローコールが分かれないよう、様々な工夫がされています

こんなUIを用意しました
8種類のスプライトが順番に配置されています
![スクリーンショット 2024-12-22 22.19.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/cabf20bb-6729-f7ea-e0bd-36f91a0ea274.png)

これはドローコールが１つにまとめられます![Z7z4WWrnImyeYLLKE8Iy1734873831-1734873878.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/1a600f5b-5831-58bc-f968-3631f435dfb3.gif)

![スクリーンショット 2024-12-22 22.20.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/dc7748d7-6fd0-6b37-8813-5471d87b3e14.png)

UIToolkit使われているシェーダーでは8個までのテクスチャを受け付けていて、その範囲内であればドローコールがまとめられるようになっています
![スクリーンショット 2024-12-22 22.21.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/7616d64a-6700-3bed-5d62-1e727fea4bca.png)

そのため、9種類以上になると...
![スクリーンショット 2024-12-22 22.22.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/89e3383c-b8db-94dc-254b-490171c8b806.png)

大量のドローコールに分けられてしまいます

![Z7z4WWrnImyeYLLKE8Iy1734873831-1734873878.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/1a8fae7d-674c-9a15-9584-cd6f8398258a.gif)

これは9種類目に追加されたテクスチャによって、1ドローコールで処理できなくなったことにより分けられてしまっています

ここでPanesSettingsでDynamic Atlasの設定をします
![スクリーンショット 2024-12-22 22.27.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/91f395d6-ce79-d3d1-0a05-682a532b2403.png)

すると1つのドローコールにまとめられます
![スクリーンショット 2024-12-22 22.28.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/0c2a5507-be1a-0662-9ac1-311f72d397d2.png)

ダイナミックアトラスによって、複数のテクスチャが1つのテクスチャにまとめられることで、テクスチャ枠を節約できているんですね
![スクリーンショット 2024-12-22 22.28.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/0eaf2b1d-8278-9a29-3cd5-76df4718c0c5.png)


このように大量のテクスチャが設定される場面では、適切にアトラスを設定する必要があります
ここでは動的アトラスを使いましたが、通常のアトラスも対応しているのでそちらも検討してみてください