Metal グラフィックコードを最適化するには、さまざまな方法があります。Metal フレームワーク向けにコードを最適化するための手順をご紹介します。
Apple GPUアーキテクチャ
AppleのGPUはタイルベースの遅延レンダラーです。つまり、タイリングとレンダリングという2つの主要なパスを使用します。全体的なレンダリングパイプラインを以下に示します。
これら 2 つのフェーズは、ジオメトリが計算および作成されるフェーズと、すべてのピクセル レンダリングが処理されるフェーズと考えることができます。
最新の Apple GPU ソフトウェアのほとんどでは、ジオメトリが計算され、メッシュとポリゴンに分割され、フレームごとに 1 つのイメージのピクセルベースのイメージにレンダリングされます。
最新のApple GPUは、各コア内にシェーダー、テクスチャ、ピクセルバックエンド、専用タイルメモリを処理するための専用のサブセクションを備えています。各コアはレンダリング時にこれらの4つの領域を使用します。
各フレームのレンダリングでは、複数のパスが複数のGPUコア上で実行され、各コアは複数のタスクを処理します。一般的に、コア数が多いほどパフォーマンスは向上します。
最新の Apple GPU レンダリング パイプライン。
GPUカウンター
このパフォーマンスを測定するために、GPU カウンターが使用されます。
GPUカウンターは各GPUの負荷を追跡し、各GPUの作業量が十分かどうかを測定します。また、パフォーマンスのボトルネックも検出します。
最後に、GPU カウンターはパフォーマンスを高速化するために、最も時間のかかるコマンドを最適化します。
Apple GPU パフォーマンス カウンターには 150 種類以上あり、それらすべてを網羅することはこの記事の範囲を超えています。
パフォーマンスカウンタのデータをすべて理解するという課題があります。そのためには、XcodeとInstrumentsに組み込まれているMetal System TraceとMetal Debuggerを使用します。
以前の Metal の記事では、Metal システム トレースおよびデバッガーについて説明しました。
アプリやゲームでMetalを最適化するための重要な方法を含む、4つのMetal GPUカウンターがあります。これらは次のとおりです。
- パフォーマンスリミッター
- メモリ帯域幅
- 占有率
- 隠面除去
パフォーマンス リミッター、またはリミッター カウンターは、実行中の作業を見つけ、並列実行をブロックしたり遅くしたりする可能性のある停止を見つけることで、複数の GPU サブシステムのアクティビティを測定します。
最新のGPUは、演算、メモリ、ラスタライズ処理を並列(同時に)実行します。パフォーマンスリミッターは、コードの速度を低下させるパフォーマンスのボトルネックを特定するのに役立ちます。
AppleのInstrumentsアプリを使えば、パフォーマンスリミッターを使ってコードを最適化できます。Instrumentsには6種類以上のパフォーマンスリミッターが用意されています。
Apple の Instruments アプリ。
メモリ帯域幅カウンター
メモリ帯域幅GPUカウンターは、GPUとシステムメモリ間の転送を測定します。GPUは、バッファまたはテクスチャにアクセスするたびにシステムメモリにアクセスします。
ただし、システムレベルキャッシュも起動される可能性があるので、ご注意ください。つまり、実際のDRAM転送速度よりも高いメモリスループットが一時的に発生することがあります。これは正常な動作です。
メモリ帯域幅カウンターの値が高い場合、転送によってレンダリング速度が低下している可能性があります。これらのボトルネックを軽減するには、いくつかの方法があります。
メモリ帯域幅の速度低下を軽減する方法の一つは、作業データセットのサイズを小さくすることです。これにより、システムメモリから転送されるデータ量が減少するため、処理速度が向上します。
もう一つの方法は、現在のレンダーパスに必要なデータのみを読み込み、将来のレンダーパスに必要なデータのみを保存することです。これも全体的なデータサイズを削減します。
ブロック テクスチャ圧縮 (ASTC) を使用してテクスチャ アセットのサイズを縮小したり、実行時に生成されるテクスチャをロスレス圧縮したりすることもできます。
占有率は、スレッド プール全体のうち現在実行中のスレッドの数を測定します。 占有率が 100% の場合、特定の GPU がスレッド数と処理できる全体的な作業の点で現在最大限に活用されていることを意味します。
占有率GPUカウンターは、 GPUによって使用されているスレッド総容量の割合を測定します。この合計は、コンピューティング、頂点、フラグメントの占有率の合計です。
隠しサーフェスの削除は、通常、フラグメント処理の前の各レンダリング パスの途中、つまりタイル頂点バッファーがラスタライズのために GPU に送信された直後に行われます。
深度バッファと隠面除去は、現在のシーンにおいてビューのカメラから見えない面を除去するために使用されます。これにより、それらの面を描画する必要がなくなるため、パフォーマンスが向上します。
たとえば、不透明な 3D オブジェクトの裏側の表面は、カメラ (および視聴者) から見えないため、描画する必要はありません。したがって、描画しても意味がありません。
カメラに対して前方にある他の 3D オブジェクトによって隠れているサーフェスも削除されます。
GPU カウンターは、隠面除去中にラスタライズされたピクセルの合計数、フラグメント シェーダーの数 (実際にはフラグメント シェーダーへの呼び出しの数)、および保存されたピクセル数を見つけるために使用できます。
GPU カウンターを使用してブレンディングを最小限に抑えることもできますが、これもパフォーマンス コストが発生します。
隠れた表面を削除して描画を最適化するには、可視性の状態の順序でオブジェクトを描画する必要があります。つまり、オブジェクトが不透明かどうかをテストし、半透明でテストし、不透明メッシュと不透明でないメッシュが交互に配置されないようにする必要があります。
リソース
Apple の Metal 開発者ページ (developer.apple.com/metal/tools/)、WWDC ビデオ、 Janie Clayton 著の 優れたサードパーティ書籍『Metal Programming Guide: Tutorial and Reference via Swift』など、さまざまな Metal リソースが利用可能です。
Metal の最適化を開始するには、WWDC20 の「GPU カウンターを使用して Metal アプリとゲームを最適化する」、 「同じく WWDC20 のMetal で GPU を活用する」 、 WWDC19 の「最適化された Metal アプリ + ゲームを提供する」という WWDC ビデオを必ず確認してください。
次に、Apple の開発者ドキュメント Web サイトの Metal デバッガー ページで、 「Xcode での Metal ワークロードのキャプチャ」と「Metal デバッグ タイプ」をお読みください。
Metal デバッガーのドキュメントには、 Metal ワークロードの分析に関する説明もあります。
XcodeのMetalデバッガーとトレースのドキュメントをよく読んで、様々なGPUカウンターやパフォーマンスグラフの仕組みを深く理解することが大切です。これらがなければ、Metalコード内で実際に何が起こっているのかを詳細に把握することはできません。
圧縮されたテクスチャについては、 Adaptive Scalable Texture Compression (ASTC) とそれが最新のレンダリング パイプラインでどのように機能するかについて も調べておく価値があります。
ARMは開発者向けウェブサイト community.arm.com でASTCの概要を詳しく公開しています。また、highperformancegraphics.orgもご覧ください。
Metal のパフォーマンス最適化は広範かつ複雑なテーマです。私たちはまだ始まったばかりですが、今後の記事でこのトピックをさらに探求していく予定です。