6

Apple はシェーダーのベスト プラクティスで、可能であれば分岐を避けるようにと述べています。特に、シェーダー内で計算された値での分岐は避けてください。そこで、いくつかのifステートメントを組み込みclamp()関数に置き換えました。私の質問は、clamp()min()、およびの方が効率的である可能性が高いですか、それとも単にブロックmax()に展開するだけの便利な (つまり、マクロ) 関数ですか?if

答えは実装に依存する可能性があることを認識しています。いずれにせよ、関数は明らかにクリーンであり、コンパイラー何かを行うことができる意図を明確にします。

4

1 に答える 1

10

歴史的に言えば、GPU は などのフラグメントごとの命令をサポートしてMINおりMAX、任意の条件付き分岐をサポートするよりもはるかに長い間サポートされてきました。デスクトップ OpenGL でのこの例の 1 つは、GL_ARB_fragment_program拡張機能 (現在は GLSL に取って代わられている) であり、分岐をサポートしないことを明示的に示していますが、その他の条件付き命令と同様に命令も提供していMINますMAX

min()がどれほど一般的でmax()ありclamp()、シェーダーにあるかを考えると、すべての GPU にこれらの操作専用のハードウェアがまだあると確信しています。これは仕様で保証されているわけではありません。実装によってコードを最適化できるためです。ただし、現実の世界では、独自の関数をロールバックするのではなく、GLSL の組み込み関数を使用する必要があります。

唯一の例外は、大量の追加フラグメント処理を避けるために条件が使用されていた場合です。ある時点で、ブランチのコストはブランチ内のすべてのコードを実行するコストよりも少なくなりますが、ここでのバランスはハードウェアに大きく依存するため、ベンチマークを実行して、アプリケーションで実際に役立つかどうかを確認する必要があります。ターゲット ハードウェア。これが私が意味する種類のものです:

void main() {
    vec3 N = ...;
    vec3 L = ...;
    float NDotL = dot(N, L);
    if (NDotL > 0.0)
    {
        // Lots of very intensive code for an awesome shadowing algorithm that we
        // want to avoid wasting time on if the fragment is facing away from the light
    }
}

0-1 にクランプNDotLし、すべてのフラグメントのシャドウ コードを常に処理して、最終的なシャドウ項を乗算するだけでNDotLは、元が <= 0 の場合、多くの無駄な労力がかかりNDotLます。理論的には、ブランチを使用してこのオーバーヘッドを回避できます。この種のことが必ずしもパフォーマンスの向上につながるとは限らない理由は、ハードウェアがシェーダー分岐を実装する方法に大きく依存するためです。

于 2013-07-26T04:31:45.040 に答える