シェーダーで `mix()`+`step()` を使った条件付き移動の最適化を禁止すべき方針
(iquilezles.org)紹介
- この記事では、GPUにおける分岐に関する誤った通念を正したい。
- いくつかの教育系Webサイトが誤った情報を広めているため、それを修正したい。
問題
- GPUコードで条件付き実行を実装する三項演算子を使うコード例を示す。
- 一部の人はこれを算術演算に置き換える「最適化」を提案するが、これは誤解に基づいている。
- 三項演算子は条件付き移動を行い、これは単純なビット演算で実装される。
- 実際の分岐はGPUコードで発生するが、小さなレジスタ移動には使われない。
誤った最適化の問題点
- 提案された最適化は、実際には元のコードより遅く実行される。
step()関数は三項演算子で実装されており、不要な乗算と加算を追加で実行する。- 元のコードでは、値が条件に応じて直接移動される。
機械語コードの分析
- AMDおよびMicrosoftコンパイラの機械語コードを通じて、GPUが分岐を行っていないことを確認できる。
- 比較演算とビットマスクを使って条件付き移動を実行する。
結論
-
step()関数を使った最適化の提案は誤情報であり、これを正す必要がある。 -
誤情報は20年以上広まっており、修正する必要がある。
-
Inigo Quilez - 1994年からコンピュータグラフィックスを学習中。
1件のコメント
Hacker Newsの意見
TFAの結論が正しいことは確信しているが、より良い版だけでなく両方の版のコード生成が示されれば、主張はさらに強まるはず
どのような場合に
ifが本当に分岐を強制するのかを知る良い方法があればいいのにと思うmix/lerpを使う理由は、わずかなオーバーヘッドがあるかもしれなくても、分岐を作ることを恐れているからだv = x > y ? a : b;が実際にうまく機能するのはよいが、ifが時には分岐で時にはそうでない構文であることが気がかりだこの記事も関連している: GPUでの分岐の書き方に関する誤った助言を正す
コンパイラが「最適化された」版が同一であることをなぜ認識できないのか不思議だ
step()を理解し、step() = 0.0とstep() == 1.0の場合を別々に最適化できるはずだこの問題には引っかかったことがある。Claude / ChatGPT もこれを最適化として提案するが、性能低下を招く
OpenGL 関数が GPU の基本機能を呼び出すのではなく、エミュレーションされているかどうかをどうやって知ればよいのか気になる
コードを書く際、条件分岐が発生しないという確信を持つには経験が必要だ
mix関数のバリアントがベクトルに対してどのように動作するかを説明している