GPUに三角形を送信する手法選択のメモ
結論: indexed triangle list を使え
この結論自体はDirectX9 (2004) 世代くらいからずっと変わっていないが、この方式は一番メモリ帯域を消費するため疑われることもある。
ポリゴンを描画するとは何か
"面" を持てる最小の図形は3角形なので、3つの 頂点 をGPUに送信する必要がある。さらに、通常のポリゴンはテクスチャマップされるので、テクスチャ上に頂点が置かれる座標も頂点の 属性 として必要になる。
結果的に、 頂点1つは数個(3〜)の float
や他の型の値の集合となる。近年の一般的なGPUでは、頂点が画面上のどこに表示されるか等の演算はGPU側で行ってくれるため、CPUからはアセットのデータをほぼそのまま送信してやれば良いようになっている。
プリミティブ
通常GPUは3角形を描画する方法として以下の3つを備える:
- TriangleStrip -- 直前の三角形の辺を共有して描画する (= 1頂点kickで1面)
- TriangleFan -- 最初の頂点を共有し、他の頂点のみ送信する (= 1頂点kickで1面)
- Triangle -- 各三角形を独立して描画する (= 常に3頂点kickで1面)
Triangleは常に1面につき3頂点必要なのでメモリ量や操作量で不利に見えるが、現状では推奨されている。
頂点インデックス
多くの頂点は再利用されるため、頂点を配列に格納してGPU側のメモリに置き、配列のオフセットだけを指定することでメモリ帯域をある程度節約できる。
TODO: Hardware T&L以前に存在したか?
近年の常識的なGPUは大抵 頂点キャッシュ を持っており、この頂点キャッシュのタグとしてもインデックスを使用するため、頂点インデックスは常に使用され存在しない場合は自動生成される。 FIXME: AMD以外でも真なの?
オプティマイザの見解
Meshoptimizer
Meshoptimizeは現RobloxのArseny Kapoulkineによって書かれたライブラリで、GPUで効率的にレンダリングできるようにいくつかのテクニックをライブラリの形で提供している。
On most hardware, indexed triangle lists are the most efficient way to drive the GPU. However, in some cases triangle strips might prove beneficial:
- On some older GPUs, triangle strips may be a bit more efficient to render
- On extremely memory constrained systems, index buffers for triangle strips could save a bit of memory
... この記述は triangle strip の方が効率的なGPUが存在することを示唆する。
(this is close to the heuristic from the SGI algorithm from 1996)
96年か〜 ... たぶんこの記述は古いiPhoneを指しているのではないかと思う(後述)。
Strips, lists, fans, indexed or not?
- http://tomsdxfaq.blogspot.com/ -- DX9時代のアドバイスでちょっと古い
- https://tomforsyth1000.github.io/papers/fast_vert_cache_opt.html
IntelのTom Forsythは、"Strips, lists, fans, indexed or not?" の項で以下のようにアドバイスしている:
Once you've optimised your triangle ordering for good vertex-cache coherency, whether you then choose to use indexed lists, strips or fans is a fairly minor point. Some hardware prefers one type of primitive slightly over another, but in general you can use whatever method you like.
つまり(indexは必須として、)listとstripでは大差が無いとしている。
実際、後のパラグラフで述べられているプリミティブリスタートはOpenGL ES3やWebGL2で使用できるようになっていて、 WebGL2ではそもそもOFFにできない 。
Apple
Appleは少くとも昔は 明示的にtriangle stripを推奨している (FIXME: PowerVR由来?)。
Metal世代ではそもそも言う程の違いが出ないからかBest practiceガイドには言及がない。
ARM
Index付きのdraw callを推奨している。つまり非indexな場合は頂点キャッシュを使えない。。?