Déchirement d'écran dans le shader de fragments sur les GPU R9 380

8

deux joueurs rencontrent un problème avec mon jeu où l'écran se déchire quand il utilise un fragment shader mais il semble que cela ne soit le cas que pour les joueurs avec un GPU R9 380. Voici à quoi cela ressemble dans le jeu:

entrez la description de l'image ici

Après avoir travaillé avec l'un des joueurs, je l'ai limité à l'utilisation du shader, mais cela pourrait ne pas être fait correctement dans le code d'appel. Voici à quoi ressemble le shader (notez que j'apprends toujours le 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;
    }
}

Voici le code backend (c ++) utilisant 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);

Y a-t-il quelque chose d'évident ici que je manque que je ne devrais pas faire. Quelqu'un connaît-il des problèmes avec les pilotes R9 380? En regardant le déchirement de ce que je suppose, c'est que nous échantillonnons incorrectement à partir de la texture cible, mais je ne vois pas comment ni pourquoi.

jmcmorris
la source
Directement à partir de Wikipedia: "Le déchirement d'écran est un artefact visuel dans l'affichage vidéo où un dispositif d'affichage affiche des informations provenant de plusieurs images dans un seul dessin d'écran." Cela est probablement dû au fait que vos amis ont un processeur basé sur AMD, car les pilotes Nvidia sont généralement bons pour synchroniser les moniteurs avec les fréquences d'images. Désolé si ce n'est pas beaucoup, mais redirigez vos recherches vers l'architecture AMD.
Java Man Tea Man
1
Vous êtes-vous assuré qu'ils utilisent les derniers pilotes? En outre, c'est une question bien posée, mais il est assez difficile de répondre à des problèmes de type de débogage spécifiques, donc vous n'aurez peut-être pas la meilleure des chances. Aussi, juste pour que vous le sachiez, il est OK d'avoir des liens vers votre jeu dans votre profil.
MichaelHouse
1
Si vous voulez dire la ligne diagonale de points allant d'environ le milieu de l'écran au coin supérieur droit, ce n'est pas un déchirement de l'écran. La déchirure n'est pas quelque chose que vous pouvez capturer dans une capture d'écran.
Ross Ridge
1
De son emplacement, il ressemble à un bord de triangle d'écran entier.
MichaelHouse
Ouais, je ne savais pas comment appeler ça et déchirer était le mieux que je pouvais trouver. Je parle des lignes individuelles. Il semble qu'il échantillonne incorrectement la texture ou quelque chose. Je ne vois pas comment cela pourrait être le cas cependant. J'apprécie les pistes et n'hésitez pas à suggérer plus. À votre santé! (Profil mis à jour)
jmcmorris

Réponses:

8

J'y suis revenu aujourd'hui et après quelques investigations et essais et erreurs, j'ai découvert que le coupable était targetTexture. Avec un peu plus d'investigation, j'ai appris que lire et écrire sur la même texture dans un shader est une mauvaise pratique (sans surprise) et provoquera un comportement indéfini sur les GPU.

La solution consistait à copier la texture cible dans une nouvelle texture, puis à lire à partir de la copie tout en écrivant sur la texture cible d'origine.

jmcmorris
la source
1
Il n'est pas défini sur tous les GPU.
Andreas