7

頂点シェーダーの頂点の半分を移動したいシェーダーがあります。パフォーマンスの観点からこれを行うための最良の方法を決定しようとしています。これは、100,000をはるかに超える頂点を処理しているため、速度が重要です。私は3つの異なるメソッドを見てきました:(擬似コードですが、あなたにアイデアを与えるのに十分です。<complex formula>私は与えることはできませんが、それはsin()関数と関数呼び出しを含むと言うことができます(ただ数値ですが、それでも関数呼び出し)、および浮動小数点数の基本的な算術の束)。

if (y < 0.5)
{
    x += <complex formula>;
}

<complex formula>これには、が半分の時間しか実行されないという利点がありますが、欠点は、分岐が確実に発生することです。これは、実際には数式よりも遅くなる可能性があります。これは最も読みやすいですが、このコンテキストでは読みやすさよりも速度を重視しています。

x += step(y, 0.5) * <complex formula>;

HLSLのstep()関数(最初のパラメーターが大きい場合は0を返し、小さい場合は1を返す)を使用すると、ブランチを削除できますが、今で<complex formula>は毎回呼び出され、その結果は0で乗算されます(したがって、無駄な労力)半分の時間。

x += (y < 0.5) ? <complex formula> : 0;

これは私にはわかりません。?:原因は分岐しますか?そうでない場合は、方程式の両側が評価されますか、それとも関連する側だけが評価されますか?

最後の可能性は、<complex formula>がGPUではなくCPUにオフロードされる可能性があることですが、sin()やその他の操作の計算が遅くなり、正味の損失が発生する可能性があるのではないかと心配しています。また、もう1つの数値をシェーダーに渡す必要があり、オーバーヘッドも発生する可能性があります。誰が最善の行動方針であるかについて何か洞察を持っていますか?


補遺:

http://msdn.microsoft.com/en-us/library/windows/desktop/bb509665%28v=vs.85%29.aspxによると

step()関数は内部的に使用するので?:、おそらく私の3番目のソリューションよりも優れているわけで<complex formula>はなく、毎回確実に呼び出されるため、潜在的に悪化しますが、ストレートでは半分の時間しか呼び出されない可能性?:があります。(まだ誰も質問のその部分に答えていません。)両方を避けて使用していますが:

x += (1.0 - y) * <complex formula>;

どこにも比較が行われていないので、それらのどれよりも優れている可能性があります。(そしてy、常に0または1のいずれかです。)それでも<complex formula>不必要に半分の時間で実行されますが、分岐を完全に回避する価値があるかもしれません。

4

2 に答える 2

8

おそらくこの答えを見てください。

私の推測(これはパフォーマンスの質問です:それを測定してください!if )は、ステートメントを保持するのが最善であるということです。

理由1:シェーダーコンパイラは、理論的には(正しく呼び出された場合)、ステートメントstepをコンパイルするときに、分岐命令と関数に似たものの間で最良の選択を行うのに十分賢いはずです。ifそれを改善する唯一の方法は、プロファイルを作成することです[1]。このレベルの粒度では、おそらくハードウェアに依存することに注意してください。

[1]または、データのレイアウトについて特定の知識がある場合は、以下をお読みください...

理由2は、シェーダーユニットの動作方法です。ユニット内の1つのフラグメントまたは頂点でさえ、他のフラグメントとは異なる分岐をとる場合、シェーダーユニットは両方の分岐をとる必要があります。しかし、それらがすべて同じブランチを取る場合、他のブランチは無視されます。したがって、頂点ごとではなくユニットごとですが、高価なブランチをスキップすることは可能です。

フラグメントの場合、シェーダーユニットには画面上の局所性があります。つまり、近くのピクセルのグループがすべて同じブランチをとることで最高のパフォーマンスが得られます(リンクされた回答の図を参照)。正直なところ、頂点がどのようにユニットにグループ化されているかはわかりませんが、データが適切にグループ化されている場合は、目的のパフォーマンス上の利点が得られるはずです。

最後に、指摘する価値が<complex formula>あります-HLSLから手動で持ち上げることができると言っている場合は、とにかくCPUベースのプレシェーダーに持ち上げられる可能性があります(少なくともPCでは、Xbox360はメモリからこれをサポートしていません、PS3についてはわかりません)。これは、シェーダーを逆コンパイルすることで確認できます。(頂点/フラグメントごとではなく)描画ごとに1回だけ計算する必要がある場合は、CPUで実行するのがパフォーマンスにとっておそらく最善です

于 2012-09-18T11:38:30.913 に答える
0

条件が無視されることにうんざりしたので、別のカーネルを作成して、cの実行でオーバーライドを実行しました。常に正確である必要がある場合は、この修正をお勧めします。

于 2015-08-14T17:05:15.550 に答える