R9 380 GPUのフラグメントシェーダーで画面がちらつく


8

私のゲームで2人のプレーヤーがフラグメントシェーダーを使用すると画面がちらつくという問題が発生していますが、これはR9 380 GPUを使用するプレーヤーでのみ発生しているようです。これは、ゲームでは次のようになります。

ここに画像の説明を入力してください

プレーヤーの1つを操作した後、シェーダーを使用するように絞り込みましたが、呼び出し元のコードで適切に行われていない可能性があります。シェーダーは次のようになります(まだGLSLを学習しています)。

uniform sampler2D lightTexture;
uniform sampler2D targetTexture;
uniform sampler2D backgroundTexture;
uniform vec2 tileSize;

vec3 SaturationBrightness(vec3 color, float brt, float sat)
{
    // Increase or decrease theese values to adjust r, g and b color channels seperately
    const float AvgLumR = 0.5;
    const float AvgLumG = 0.5;
    const float AvgLumB = 0.5;

    const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721);

    vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB);
    vec3 brtColor = color * brt;
    vec3 intensity = vec3(dot(brtColor, LumCoeff));
    vec3 satColor = mix(intensity, brtColor, sat);
    return satColor;
}

void main(void)
{
    vec2 position;
    position.s = gl_TexCoord[0].s;
    position.t = gl_TexCoord[0].t;
    vec4 lightColor = texture2D(lightTexture, position);

    //Return the lighting if the light is pure dark since the tile behind it was not rendered
    if (lightColor.r == 0.0 && lightColor.g == 0.0 && lightColor.b == 0.0) {
        gl_FragColor = lightColor;
        return;
    }

    //Get the average of the the nearby light
    position.t -= tileSize.t;
    vec4 lightColorUp = texture2D(lightTexture, position);
    position.t += tileSize.t*2.0;
    vec4 lightColorDown = texture2D(lightTexture, position);
    position -= tileSize;
    vec4 lightColorLeft = texture2D(lightTexture, position);
    position.s += tileSize.s*2.0;
    vec4 lightColorRight = texture2D(lightTexture, position);
    position.s += tileSize.s;
    vec4 lightColorFarRight = texture2D(lightTexture, position);
    position.s -= tileSize.s*4.0;
    vec4 lightColorFarLeft = texture2D(lightTexture, position);
    position.s += tileSize.s*2.0;
    position.t -= tileSize.t*2.0;
    vec4 lightColorFarUp = texture2D(lightTexture, position);
    position.t += tileSize.t*4.0;
    vec4 lightColorFarDown = texture2D(lightTexture, position);
    lightColor = lightColorRight + lightColorUp + lightColorDown + lightColorLeft + lightColorFarRight + lightColorFarUp + lightColorFarDown + lightColorFarLeft;
    lightColor.r /= 8.0;
    lightColor.g /= 8.0;
    lightColor.b /= 8.0;
    lightColor.a /= 8.0;

    //Get the target (foreground) that we apply the light to
    vec4 targetColor = texture2D(targetTexture, gl_TexCoord[0].st);
    if (targetColor.a == 0.0) {
        //Foreground is transparent meaning that we never rendered to it so instead render the background without light
        gl_FragColor = texture2D(backgroundTexture, gl_TexCoord[0].st);
    } else {
        //Apply averaged light to target
        gl_FragColor = vec4(SaturationBrightness(lightColor.rgb, 1.15, 1.1), lightColor.a) * targetColor;
    }
}

SFMLを使用したバックエンドコード(c ++)を以下に示します。

SpecialRenderTexturePtr targetTexture = boost::static_pointer_cast<SpecialRenderTexture>(target);
targetTexture->display();

m_texture->setView(m_view);
m_texture->clear(Color(0, 0, 0, 255));
m_texture->draw(m_vertices);
m_texture->display();

m_shader.setParameter("lightTexture", m_texture->getTexture());
m_shader.setParameter("targetTexture", targetTexture->getTexture());
m_shader.setParameter("backgroundTexture", m_render->getBackgroundTexture()->getTexture());
Vector tileSize(Sizes::SUBTILE / 2.0 / m_texture->getSize().x, Sizes::SUBTILE / 2.0 / m_texture->getSize().y);
m_shader.setParameter("tileSize", tileSize.toSfml());
sf::Sprite lightSprite(m_texture->getTexture());
Vector viewPosition = m_view.getCenter();
const Vector& viewSize = m_view.getSize();
viewPosition.x = ceil(viewPosition.x - (viewSize.x / 2.0f));
viewPosition.y = ceil(viewPosition.y - (viewSize.y / 2.0f));
lightSprite.setPosition(viewPosition.toSfml());

target->draw(lightSprite, &m_shader);

私が行方不明であることを私が見逃していることは明らかです。R9 380ドライバーの問題を知っている人はいますか?私が推測することからの裂け目を見ると、ターゲットテクスチャから誤ってサンプリングしているが、その方法や理由がわかりません。


ウィキペディアから直接:「画面のティアリングは、ビデオディスプレイにおける視覚的なアーティファクトであり、ディスプレイデバイスは単一の画面描画で複数のフレームからの情報を表示します。」Nvidiaドライバーは通常モニターをフレームレートに同期するのに優れているため、これはおそらく友人がAMDベースのgpuを使用しているという事実に基づいています。それほど多くない場合は申し訳ありませんが、AMDアーキテクチャに向けて調査をリダイレクトしてください。
Java Man Tea Man

1
彼らが最新のドライバーを使用していることを確認しましたか?また、これはうまくまとめられた質問ですが、このような特定のデバッグタイプの問題に答えるのはかなり難しいため、運が悪い場合があります。また、ご存知のように、プロファイルにゲームへのリンクを含めることもできます。
MichaelHouse

1
ドットの対角線が画面の中央から右上隅に向かっていることを意味している場合、それは画面のちぎれではありません。ティアリングは、スクリーンショットでキャプチャできるものではありません。
ロス・リッジ

1
その配置から、それは画面全体の三角形のエッジのように見えます。
MichaelHouse

ええ、私はこれを何と呼べばいいかわからなかったし、引き裂くことは思いつくことができる最高のものでした。個々のラインについて話している。テクスチャから正しくサンプリングされていないようです。どうしてそうなるのかわかりません。私はリードに感謝し、もっと提案してください。乾杯!(更新されたプロファイル)
jmcmorris 2016

回答:


8

私は今日これに戻ってきて、さらに調査と試行錯誤の末、犯人がtargetTextureであることがわかりました。さらに調査したところ、シェーダーで同じテクスチャを読み書きすることは(当然のことながら)悪い習慣であり、GPUで未定義の動作が発生することがわかりました。

解決策は、ターゲットテクスチャを新しいテクスチャにコピーし、元のターゲットテクスチャに書き込みながら、コピーから読み取ることでした。


1
すべてのGPUで未定義です。
Andreas
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.