7

私は、oculus Rift 歪みシェーダーの OpenGL 実装に取り​​組んでいます。シェーダーは、(以前にレンダリングされたシーンを含むテクスチャの) 入力テクスチャ座標を取得し、歪み係数を使用してそれを変換し、変換されたテクスチャを使用してフラグメントの色を決定することによって機能します。

歪みを事前に計算して 2 番目のテクスチャに保存することでパフォーマンスを向上させたいと思っていましたが、実際には直接計算 よりも遅くなります。

直接計算バージョンは、基本的に次のようになります。

float distortionFactor(vec2 point) {
    float rSq = lengthSquared(point);
    float factor =  (K[0] + K[1] * rSq + K[2] * rSq * rSq + K[3] * rSq * rSq * rSq);
    return factor;
}

void main()
{
    vec2 distorted = vRiftTexCoord * distortionFactor(vRiftTexCoord);
    vec2 screenCentered = lensToScreen(distorted);
    vec2 texCoord = screenToTexture(screenCentered);
    vec2 clamped = clamp(texCoord, ZERO, ONE);
    if (!all(equal(texCoord, clamped))) {
        vFragColor = vec4(0.5, 0.0, 0.0, 1.0);
        return;
    }
    vFragColor = texture(Scene, texCoord);
}

ここで、K はユニフォームとして渡される vec4 です。

一方、ディスプレイスメント マップのルックアップは次のようになります。

void main() {
    vec2 texCoord = vTexCoord;
    if (Mirror) {
        texCoord.x = 1.0 - texCoord.x;
    }
    texCoord = texture(OffsetMap, texCoord).rg;
    vec2 clamped = clamp(texCoord, ZERO, ONE);
    if (!all(equal(texCoord, clamped))) {
        discard;
    }
    if (Mirror) {
        texCoord.x = 1.0 - texCoord.x;
    }
    FragColor =  texture(Scene, texCoord);
}

縦横比を修正し、レンズ オフセットを考慮する操作は他にもいくつかありますが、それらは非常に単純です。これが単純なテクスチャ ルックアップよりも優れていると期待するのは本当に合理的ですか?

4

3 に答える 3

12

GDDR メモリのレイテンシはかなり高く、最新の GPU アーキテクチャには多数の処理能力があります。以前は逆で、GPU は計算を行うには非常に不十分であったため、正規化はキューブ マップからフェッチする方が低コストでした。

ここで通常のテクスチャ ルックアップを行っているのではなく、従属ルックアップを行っているという事実を入れても、驚くことではありません。フェッチ元の場所は別のフェッチの結果に依存するため、シェーダーが必要とするメモリをプリフェッチ/効率的にキャッシュする (効果的なレイテンシ隠蔽戦略) ことは不可能です。それは「単純なテクスチャ ルックアップ」ではありません。

さらに、依存テクスチャ ルックアップを実行するだけでなく、2 番目のシェーダーにもdiscardキーワードが含まれます。これにより、多くのハードウェアでの初期の深度テストの可能性が効果的に排除されます。

distortionFactor (...)正直なところ、関数をルックアップに「最適化」する理由がわかりません。それは二乗の長さsqrtを使用するので、あなたはただの掛け算と足し算だけを扱っているわけではありません。

于 2013-12-15T08:49:18.437 に答える
6

Andon M. Coleman は、何が起こっているのかを既に説明しています。本質的にメモリ帯域幅と、さらに重要なメモリ レイテンシが、最新の GPU の主なボトルネックであるため、2007 年頃から今日までの間に構築されたものはすべて、単純な計算は、多くの場合、テクスチャ ルックアップよりもはるかに高速です。

実際、メモリアクセスパターンは効率に大きな影響を与えるため、アクセスパターンを少し再配置し、適切な配置を確保するだけで、1000 倍のパフォーマンス向上を簡単に実現できます (BT;DT ですが、CUDA プログラミングでした)。ただし、依存ルックアップは必ずしもパフォーマンス キラーではありません。依存テクスチャ座標ルックアップがコントローラー テクスチャに対して単調である場合、通常はそれほど悪くはありません。


そうは言っても、ホーナーの方法について聞いたことがありませんか? あなたは書き直すことができます

float factor =  (K[0] + K[1] * rSq + K[2] * rSq * rSq + K[3] * rSq * rSq * rSq);

些細なことで

float factor =  K[0]  + rSq * (K[1] + rSq * (K[2] + rSq * K[3]) );

いくつかの操作を節約できます。

于 2013-12-15T10:45:06.920 に答える
0

GPU は超並列であり、1 クロック サイクルで最大 1000 の結果を計算できます。メモリの読み取りは常にシーケンシャルです。乗算の計算にfe 5クロックかかる場合、5クロックサイクルで1000の結果を計算できます。データを 1 クロック サイクルあたり fe 10 データセットでシーケンシャルに読み取る必要がある場合、データを取得するのに 5 クロック サイクルではなく 100 クロック サイクルかかります。あなたが理解できるようにランダムに番号を付けます:)

于 2014-03-31T04:24:50.020 に答える