Шейдер GLSL не работает на AMD / ATI, но работает на NVIDIA

У меня действительно странная проблема, я не могу pin down в течение нескольких дней. Я делаю простое освещение для каждой вершины, и оно отлично работает на Nvidia, но не делает ничего затененного светом AMD/ATI, Я обнаружил, что проблема связана с атрибутами — особенно с атрибутом цвета.
Это мой вершинный шейдер:

#version 140
uniform mat4 modelViewProjectionMatrix;
in vec3 in_Position;                 // (x,y,z)
in vec4 in_Color;                    // (r,g,b,a)
in vec2 in_TextureCoord;             // (u,v)

out vec2 v_TextureCoord;
out vec4 v_Color;

uniform bool en_ColorEnabled;
uniform bool en_LightingEnabled;

void main()
{
if (en_LightingEnabled == true){
v_Color = vec4(0.0,1.0,0.0,1.0);
}else{
if (en_ColorEnabled == true){
v_Color = in_Color;
}else{
v_Color = vec4(0.0,0.0,1.0,1.0);
}
}
gl_Position = modelViewProjectionMatrix * vec4( in_Position.xyz, 1.0);

v_TextureCoord = in_TextureCoord;
}

Это пиксельный шейдер:

#version 140
uniform sampler2D en_TexSampler;
uniform bool en_TexturingEnabled;
uniform bool en_ColorEnabled;
uniform vec4 en_bound_color;
in vec2 v_TextureCoord;
in vec4 v_Color;
out vec4 out_FragColor;

void main()
{
vec4 TexColor;
if (en_TexturingEnabled == true){
TexColor = texture2D( en_TexSampler, v_TextureCoord.st ) * v_Color;
}else if (en_ColorEnabled == true){
TexColor = v_Color;
}else{
TexColor = en_bound_color;
}
out_FragColor = TexColor;
}

Таким образом, этот шейдер допускает 3 состояния — когда я использую источники света, когда я не использую источники света, но использую цвет для каждой вершины и когда я использую один цвет для всех вершин. Я удалил весь код вычисления light, потому что отследил проблему до атрибута. Это вывод из шейдера:
Шейдер с ошибкой
Как вы можете видеть, все синее (поэтому он отображает все, что не имеет затенения или цвета (en_LightingEnabled == false and en_ColorEnabled == false)).

Когда я заменяю этот код в вершинном шейдере:

if (en_ColorEnabled == true){
v_Color = in_Color;
}else{

с этим:

if (en_ColorEnabled == true){
v_Color = vec4(1.0,0.0,0.0,1.0);
}else{

Я получаю следующее:
Без атрибута in_Color
Итак, вы можете видеть, что он рендерит все без затенения по-прежнему синим, но теперь он также рендерит все, что использует свет (en_LightingEnabled == true) зеленым цветом Так должно быть. Проблема в том, что in_Color Атрибут не должен мешать источнику света, так как он даже не будет работать, если источники света включены. Вы также можете видеть, что на изображении нет ничего красного, что означает в этой сцене en_ColorEnabled всегда false, Так in_Color здесь абсолютно бесполезно, но оно вызывает ошибки в тех местах, которые по логике не должны. На Nvidia это работает хорошо, и зеленые области рисуют с или без in_Color,

Я использую что-то AMD не поддерживает? Я использую что-то снаружи GLSL спекуляция? я знаю AMD строже GL спецификация чем Nvidiaтак что возможно я делаю что-то неопределенное. Я сделал код как можно более простым и все еще имею проблему, поэтому я не вижу его.
Кроме того, я заметил, что он не будет рисовать НИЧЕГО (даже синие области) на экране, если in_Color атрибут вершины отключен (нет glEnableVertexAttribArray), но почему? Я даже не использую цвет. Отключенные атрибуты нужно вернуть (0,0,0,1) по спецификации верно? Я пытался с помощью glVertexAttrib4f изменить этот цвет, но все равно стал черным. Компилятор и компоновщик не возвращает никаких ошибок или предупреждений. Атрибут in_Color найден просто отлично с glGetAttribLocation, Но, как я уже сказал, ничего из этого не должно иметь значения, так как эта ветвь никогда не выполняется в моем коде. Есть идеи?

Проверено на Nvidia660Ti и работает отлично, проверено на ATI mobility radeon HD 5000 Ноутбук и есть эта ошибка. Моя единственная идея состояла в том, что, может быть, я превосхожу возможности GPU (слишком много атрибутов и т. д.), но когда я сократил свой код до этого, я перестал в это верить. Я использую только 3 атрибута здесь.
Кроме того, некоторые из моих друзей тестировались на гораздо более новых AMD карты и получил ту же проблему.

ОБНОВЛЕНИЕ 1

Атрибуты вершины связаны так:

if (useColors){
glUniform1i(uni_colorEnable,1);
glEnableVertexAttribArray(att_color);
glVertexAttribPointer(att_color, 4, GL_UNSIGNED_BYTE, GL_TRUE, STRIDE, OFFSET(offset));
}else{
glUniform1i(uni_colorEnable,0);
}

Кроме того, я нашел, как показать странность еще проще — возьмите этот вершинный шейдер:

void main()
{
v_Color = clamp(vec4(1.,1.,1.,1.) * vec4(0.5,0.5,0.25,1.),0.0,1.0) + in_Color;

gl_Position = modelViewProjectionMatrix * vec4( in_Position.xyz, 1.0);

v_TextureCoord = in_TextureCoord;
}

Так что нет ветвления. И я получаю это:
Без ветвления есть еще тот баг
Если я изменю этот код, удалив in_Color вот так:

void main()
{
v_Color = clamp(vec4(1.,1.,1.,1.) * vec4(0.5,0.5,0.25,1.),0.0,1.0);

gl_Position = modelViewProjectionMatrix * vec4( in_Position.xyz, 1.0);

v_TextureCoord = in_TextureCoord;
}

Я получаю это:
Без разветвления, как ожидалось

Последний — то, что я ожидаю, но предыдущий ничего не рисует, хотя я делаю дополнение (+) вместо всего остального. Так что если attrib не связан и (0,0,0,0) или же (0,0,0,1), то это не должно было ничего делать. И все же это все еще не удается.

Кроме того, все журналы пусты — компиляция, компоновка и проверка. Нет ошибок или предупреждений. Хотя я заметил, что информация отладки шейдера AMD/ATI дает значительно уступает тому, что Nvidia дает.

ОБНОВЛЕНИЕ 2

Единственное исправление, которое я нашел, было включить attribarray во всех случаях (так что в основном отправляет мусор GPU когда цвет не включен), но поскольку я использую униформу для проверки цвета, то я просто не использую ее. Итак, это так:

if (useColors){
glUniform1i(uni_colorEnable,1);
}else{
glUniform1i(uni_colorEnable,0);
}
glEnableVertexAttribArray(att_color);
glVertexAttribPointer(att_color, 4, GL_UNSIGNED_BYTE, GL_TRUE, STRIDE, OFFSET(offset));

Я понятия не имею, почему это происходит или почему мне нужно это использовать. Мне это не нужно Nvidia, Итак, я думаю, что это медленнее, и я трачу трафик? Но, по крайней мере, это работает … Справка о том, как сделать это лучше, была бы полезна.

5

Решение

Вероятно, это происходит потому, что вы указываете 3 входных значения для шейдера (in_Position, in_Color и in_TextureCoord), но ваши данные вершин не всегда содержат все 3. Когда атрибуты вершин не соответствуют этому формату точно, вы попадаете в неопределенное поведение территория и каждая реализация может делать то, что хочет.

Похоже, что драйвер Nvidia связывает то, что он имеет, с соответствующими атрибутами вершин и визуализирует с этим.

То есть ваши данные выглядят как расположение ниже для шейдера:

in_Position      = Position.xyz
in_Color         = ???
in_TextureCoords = TextureCoords.xy

Драйвер AMD, вероятно, пытается интерпретировать данные вершин как все 3 атрибута, даже если цвет не включен. После первой вершины позиция не синхронизирована с позицией в массиве данных, что может привести к тому, что она будет визуализироваться практически везде. Я подозреваю, что причина того, что он работает на AMD при удалении использования атрибута in_Color, заключается в том, что шейдерный компилятор видит, что он не используется, и оптимизирует тот факт, что вы его указали.

in_Position      = Position[0].xyz
in_Color         = TextureCoords[0].xy,Position[1].xy
in_TextureCoords = Position[1].z,TextureCoords[1].x

Возможные решения — сделать то, что вы уже сделали, и указать данные цвета мусора, когда вам это не нужно, или вы можете разбить ваш вершинный шейдер на 2 отдельных с разными атрибутами вершин и связать соответствующий в зависимости от того, есть ли у вас вершина. данные о цвете.

1

Другие решения


По вопросам рекламы [email protected]