Разрыв экрана во фрагментном шейдере на графических процессорах R9 380

8

у двух игроков возникла проблема с моей игрой, когда экран использует разрыв, когда он использует фрагментный шейдер, но, похоже, он делает это только для игроков с графическим процессором R9 380. Вот как это выглядит в игре:

введите описание изображения здесь

После работы с одним из игроков я сузил его до использования шейдера, но это может быть что-то неправильно в вызывающем коде. Вот как выглядит шейдер (обратите внимание, я все еще изучаю 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;
    }
}

Вот код бэкэнда (c ++) с использованием 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);

Здесь есть что-то очевидное, чего мне не хватает, чего я не должен делать. Кто-нибудь знает какие-либо проблемы с драйверами R9 380? Глядя на разрыв от того, что я предполагаю, это то, что мы неправильно выбираем целевую текстуру, но я не понимаю, как и почему.

jmcmorris
источник
Прямо из Википедии: «Разрыв экрана - это визуальный артефакт на видеоэкране, где устройство отображения отображает информацию из нескольких кадров за один экран». Скорее всего, это связано с тем, что у ваших друзей есть графический процессор на базе AMD, поскольку драйверы Nvidia обычно хорошо синхронизируют мониторы с частотой кадров. Извините, если это немного, но перенаправьте свои исследования на архитектуру AMD.
Java Man Tea Man
1
Вы гарантировали, что они используют последние версии драйверов? Кроме того, это хорошо составленный вопрос, но на конкретные вопросы типа отладки, такие как этот, довольно сложно ответить, так что вам может не повезти. Кроме того, просто чтобы вы знали, это нормально, чтобы ссылки на вашу игру в вашем профиле.
MichaelHouse
1
Если вы имеете в виду диагональную линию точек, идущую от середины экрана к верхнему правому углу, то это не разрыв экрана. Разрыв не то, что вы можете захватить на скриншоте.
Росс Ридж
1
Из своего расположения он выглядит как весь экран треугольной кромки.
MichaelHouse
Да, я не знал, как это назвать, и слезы были лучшим, что я мог придумать. Я говорю об отдельных линиях. Похоже, что это выборка из текстуры неправильно или что-то. Я не понимаю, как это могло быть так. Я ценю лидерство и не стесняюсь предлагать больше. Ура! (Обновленный профиль)
jmcmorris

Ответы:

8

Я вернулся к этому сегодня, и после еще нескольких исследований, проб и ошибок я обнаружил, что виновником была targetTexture. Проведя дополнительные исследования, я узнал, что чтение и запись в одну и ту же текстуру в шейдере - это плохая практика (что неудивительно) и приведет к неопределенному поведению на графических процессорах.

Решение состояло в том, чтобы скопировать целевую текстуру в новую текстуру и затем прочитать из копии, продолжая запись в исходную целевую текстуру.

jmcmorris
источник
1
Это не определено на всех графических процессорах.
Андреас