Strappo dello schermo in framment shader su GPU R9 380


8

due giocatori stanno riscontrando un problema con il mio gioco in cui lo schermo si strappa quando utilizza uno shader di frammenti, ma sembra farlo solo per i giocatori con una GPU R9 380. Ecco come appare nel gioco:

inserisci qui la descrizione dell'immagine

Dopo aver lavorato con uno dei giocatori, l'ho ristretto all'utilizzo dello shader, ma potrebbe essere qualcosa che non viene eseguito correttamente nel codice chiamante. Ecco come appare lo shader (nota che sto ancora imparando la 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;
    }
}

Ecco il codice di backend (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);

C'è qualcosa di ovvio qui che mi manca che non dovrei fare. Qualcuno sa di eventuali problemi con i driver R9 380? Guardando lo strappo da ciò che immagino sia che stiamo campionando in modo errato dalla trama del bersaglio ma non vedo come o perché.


Direttamente da Wikipedia: "La lacerazione dello schermo è un artefatto visivo nel display video in cui un dispositivo di visualizzazione mostra informazioni da più fotogrammi in un singolo disegno dello schermo". Questo è probabilmente basato sul fatto che i tuoi amici hanno una GPU basata su AMD, poiché i driver Nvidia sono in genere bravi a sincronizzare i monitor con i frame rate. Scusa se non è molto, ma reindirizza la tua ricerca verso l'architettura AMD.
Java Man Tea Man

1
Ti sei assicurato che stanno usando gli ultimi driver? Inoltre, questa è una domanda ben composta, ma a problemi di tipo di debug specifici come questo è piuttosto difficile rispondere, quindi potresti non avere la fortuna. Inoltre, solo per quello che sai, è OK avere collegamenti al tuo gioco nel tuo profilo.
MichaelHouse

1
Se intendi la linea diagonale di punti che va da loro intorno al centro dello schermo all'angolo in alto a destra, allora non è strappare lo schermo. Lo strappo non è qualcosa che puoi catturare in uno screenshot.
Ross Ridge

1
Dal suo posizionamento sembra un bordo del triangolo intero schermo.
MichaelHouse

Sì, non sapevo come chiamarlo e la lacrimazione era la migliore che potessi inventare. Sto parlando delle singole linee. Sembra che stia campionando la trama in modo errato o qualcosa del genere. Non vedo come potrebbe essere il caso però. Apprezzo i lead e mi sento libero di suggerire di più. Saluti! (Profilo aggiornato)
jmcmorris

Risposte:


8

Sono tornato a questo oggi e dopo alcune ulteriori indagini, prove ed errori ho scoperto che il colpevole era targetTexture. Con qualche indagine in più ho appreso che leggere e scrivere sulla stessa trama in uno shader è una cattiva pratica (non sorprendentemente) e causerà un comportamento indefinito sulle GPU.

La soluzione era copiare la trama di destinazione in una nuova trama e quindi leggere dalla copia mentre continuava a scrivere sulla trama di destinazione originale.


1
Non è definito su tutte le GPU.
Andreas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.