AGI Frame Profiler を使用すると、いずれかのレンダリング パスから描画呼び出しを選択し、[Pipeline] ペインの [Vertex Shader] セクションまたは [Fragment Shader] セクションを確認することで、シェーダーを調査できます。
ここでは、シェーダー コードの静的解析や、GLSL のコンパイルにまとめた Standard Portable Intermediate Representation(SPIR-V)アセンブリの有用な統計情報を確認できます。また、SPIR-V Cross で逆コンパイルされた、元の GLSL の表現(変数や関数などのコンパイラが生成した名前)を表示するタブもあり、SPIR-V の追加のコンテキストを確認できます。
静的分析
![説明文](https://developer.android.com/static/images/agi/shader-performance-images/image1.png?authuser=8&hl=ja)
静的分析カウンタを使用すると、シェーダー内の低レベルの操作を表示できます。
ALU 命令: この数は、シェーダー内で実行されている ALU 演算(加算、乗算、除算など)の数を示します。これは、シェーダーの複雑さを表す適切な指標です。この値を最小限に抑えるようにしてください。
一般的な計算をリファクタリングしたり、シェーダーで行われる計算を単純化したりすることで、必要な命令数を削減できます。
Texture Instructions: この数は、シェーダーでテクスチャ サンプリングが行われる回数を示します。
- テクスチャのサンプリングは、サンプリングされるテクスチャのタイプによっては高コストになることがあるため、シェーダー コードを記述子セットのセクションにあるバインドされたテクスチャと相互参照すると、使用されているテクスチャのタイプについて詳しい情報を確認できます。
- テクスチャのサンプリング時にはランダム アクセスを避けてください。この動作はテクスチャのキャッシュには理想的ではないため、
Branch Instructions: この数は、シェーダー内の分岐操作の数を示します。分岐を最小限に抑えることは、GPU などの並列プロセッサでは理想的であり、コンパイラが追加の最適化を見つけるのにも役立ちます。
min
、max
、clamp
などの関数を使用して、数値で分岐する必要がなくなります。- 分岐でのコンピューティング費用をテストする。ブランチの両方のパスは多くのアーキテクチャで実行されるため、ブランチによる計算をスキップするよりも、常に計算を実行する方が高速になるシナリオは多数あります。
一時レジスタ: GPU での計算に必要な中間演算の結果を保持するために使用される、高速なコア上のレジスタです。計算に使用できるレジスタの数には上限があり、これを超えると GPU が他のオフコア メモリにスピルオーバーして中間値を格納し、全体的なパフォーマンスが低下します。(この上限は GPU モデルによって異なります)。
シェーダー コンパイラがループの展開などの操作を行う場合、使用される一時レジスタの数が想定よりも多くなることがあります。そのため、この値を SPIR-V または逆コンパイルされた GLSL と相互参照して、コードの動作を確認することをおすすめします。
シェーダー コード分析
逆コンパイルされたシェーダー コード自体を調査して、改善の余地があるかどうかを判断します。
![説明文](https://developer.android.com/static/images/agi/shader-performance-images/image2.png?authuser=8&hl=ja)
- 精度: シェーダー変数の精度は、アプリの GPU パフォーマンスに影響する可能性があります。
- 通常、中精度(
mediump
)の 16 ビット変数は完全精度(highp
)の 32 ビット変数よりも高速で電力効率が高いため、可能な限り、変数にmediump
精度修飾子を使用してください。 - 変数宣言のシェーダーに精度修飾子が表示されない場合、または
precision precision-qualifier type
のあるシェーダーの上部には、デフォルトで完全精度(highp
)に設定されます。変数宣言も確認してください。 - 上記と同じ理由から、頂点シェーダーの出力に
mediump
を使用することも推奨されます。また、補間に必要なメモリ帯域幅を削減し、場合によっては一時的なレジスタ使用量も削減できるという利点もあります。
- 通常、中精度(
- 均一バッファ: アライメント ルールを維持しながら、均一バッファのサイズをできるだけ小さくします。これにより、キャッシュ保存との互換性が向上し、均一なデータをより高速なコア レジスタに昇格できるようになる可能性があります。
未使用の Vertex Shader 出力を削除する: フラグメント シェーダーで使用されていない頂点シェーダー出力が見つかった場合は、シェーダーから削除して、メモリ帯域幅と一時レジスタを解放します。
Fragment Shader から Vertex Shader に計算を移動する: フラグメント シェーダーのコードが、シェーディングされているフラグメントに固有の状態に依存しない(または適切に補間できる)計算を実行する場合は、頂点シェーダーに移動することをおすすめします。これは、ほとんどのアプリで、頂点シェーダーの実行頻度がフラグメント シェーダーと比べて大幅に少ないためです。