Rasgo de tela no shader de fragmento nas GPUs R9 380

8

dois jogadores estão enfrentando um problema no meu jogo em que a tela está rasgando quando usa um shader de fragmento, mas parece que isso está acontecendo apenas para jogadores com uma GPU R9 380. Aqui está o que parece no jogo:

insira a descrição da imagem aqui

Depois de trabalhar com um dos jogadores, reduzi o uso do shader, mas poderia ser algo que não estava sendo feito corretamente no código de chamada. Aqui está a aparência do shader (observe que ainda estou aprendendo o 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;
    }
}

Aqui está o código de back-end (c ++) usando SFML.

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);

Existe alguma coisa óbvia aqui que eu sinto falta que não deveria estar fazendo. Alguém sabe de algum problema com os drivers R9 380? Olhando para o rasgo do que eu acho que é que estamos amostrando a textura do alvo incorretamente, mas não vejo como ou por quê.

jmcmorris
fonte
Direto da Wikipedia: "Rasgar a tela é um artefato visual na exibição de vídeo, em que um dispositivo de exibição mostra informações de vários quadros em um único desenho da tela". Provavelmente, isso se deve ao fato de seus amigos terem uma gpu baseada em AMD, pois os drivers da Nvidia geralmente são bons na sincronização de monitores para taxas de quadros. Desculpe se não é muito, mas redirecione sua pesquisa para a arquitetura AMD.
Java Man Tea Man
11
Você garantiu que eles usem os drivers mais recentes? Além disso, essa é uma pergunta bem elaborada, mas problemas específicos do tipo depuração como esse são bastante difíceis de responder, portanto você pode não ter a melhor sorte. Além disso, só para você saber, não há problema em ter links para o seu jogo no seu perfil.
Michaelhouse
11
Se você quer dizer a linha diagonal de pontos que vai do meio da tela para o canto superior direito, isso não é rasgar a tela. Rasgar não é algo que você pode capturar em uma captura de tela.
Ross cume
11
Desde o seu posicionamento, parece uma borda inteira do triângulo da tela.
Michaelhouse
Sim, eu não sabia como chamar isso e rasgar era o melhor que eu poderia pensar. Eu estou falando sobre as linhas individuais. Parece que está amostrando a textura incorretamente ou algo assim. Não vejo como isso poderia ser o caso. Agradeço os leads e fique à vontade para sugerir mais. Felicidades! (Perfil atualizado)
jmcmorris 03/03

Respostas:

8

Voltei a isso hoje e, depois de mais algumas investigações, tentativas e erros, descobri que o culpado era targetTexture. Com um pouco mais de investigação, aprendi que ler e escrever na mesma textura em um shader é uma prática ruim (não surpreendentemente) e causará um comportamento indefinido nas GPUs.

A solução foi copiar a textura de destino para uma nova textura e, em seguida, ler a cópia enquanto ainda escrevia na textura de destino original.

jmcmorris
fonte
11
É indefinido em todas as GPUs.
Andreas