Desgarro de pantalla en fragment shader en GPU R9 380

8

dos jugadores encuentran un problema con mi juego en el que la pantalla se rasga cuando usa un sombreador de fragmentos, pero solo parece estar haciendo esto para los jugadores con una GPU R9 380. Así es como se ve en el juego:

ingrese la descripción de la imagen aquí

Después de trabajar con uno de los jugadores, lo reduje a usar el sombreador, pero podría ser algo que no se hace correctamente en el código de llamada. Así es como se ve el sombreador (tenga en cuenta que todavía estoy aprendiendo 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;
    }
}

Aquí está el 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);

¿Hay algo obvio aquí que me falta y que no debería estar haciendo? ¿Alguien sabe de algún problema con los controladores R9 380? Mirando el desgarro de lo que supongo es que estamos tomando muestras de la textura objetivo incorrectamente, pero no veo cómo ni por qué.

jmcmorris
fuente
Directamente de Wikipedia: "El desgarro de la pantalla es un artefacto visual en la visualización de video donde un dispositivo de visualización muestra información de varios cuadros en un solo dibujo de pantalla". Esto se basa probablemente en el hecho de que sus amigos tienen una GPU basada en AMD, ya que los controladores de Nvidia suelen ser buenos para sincronizar monitores a velocidades de fotogramas. Lo siento si no es mucho, pero redirige tu investigación hacia la arquitectura AMD.
Java Man Tea Man
1
¿Se ha asegurado de que estén utilizando los últimos controladores? Además, esta es una pregunta bien formulada, pero los problemas específicos del tipo de depuración como este son bastante difíciles de responder, por lo que es posible que no tenga la mejor de las suertes. Además, para que lo sepas, está bien tener enlaces a tu juego en tu perfil.
MichaelHouse
1
Si te refieres a la línea diagonal de puntos que va desde la mitad de la pantalla hasta la esquina superior derecha, entonces eso no es un desgarro de la pantalla. Lágrimas no es algo que puedas capturar en una captura de pantalla.
Ross Ridge
1
Desde su ubicación, parece un borde triangular de pantalla completa.
MichaelHouse
Sí, no sabía cómo llamar a esto y lagrimeo fue lo mejor que se me ocurrió. Estoy hablando de las líneas individuales. Parece que está tomando muestras de la textura incorrectamente o algo así. Sin embargo, no veo cómo podría ser ese el caso. Agradezco las pistas y siéntase libre de sugerir más. ¡Salud! (Perfil actualizado)
jmcmorris

Respuestas:

8

Volví a esto hoy y después de un poco más de investigación y prueba y error descubrí que el culpable era targetTexture. Con un poco más de investigación, aprendí que leer y escribir con la misma textura en un sombreador es una mala práctica (no es sorprendente) y causará un comportamiento indefinido en las GPU.

La solución fue copiar la textura objetivo a una nueva textura y luego leer de la copia sin dejar de escribir en la textura objetivo original.

jmcmorris
fuente
1
No está definido en todas las GPU.
Andreas