GLSL着色器不适用于AMD / ATI,但适用于NVIDIA

时间:2014-06-18 12:51:40

标签: c++ opengl glsl ati

我有一个非常奇怪的问题我现在不能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种状态 - 当我使用灯光时,当我不使用灯光时,但是使用每顶点颜色,当我对所有顶点使用单一颜色时。我删除了所有的光计算代码,因为我将问题追溯到属性。这是着色器的输出:
Shader with bug 正如您所看到的,一切都是蓝色的(因此它会呈现没有阴影或颜色的所有内容(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{

我得到以下内容:
Without in_Color attribute
所以你可以看到它呈现的所有内容都没有着色仍为蓝色,但现在它也呈现了使用绿色的灯光(en_LightingEnabled == true)的所有内容。应该是这样的。问题是in_Color属性不应该干扰灯光,因为如果启用了灯光,它甚至都不会运行。您还可以看到图片中没有任何内容为红色,这意味着此场景en_ColorEnabled始终为false。所以in_Color在这里完全没用,但它在逻辑上不应该引起错误。在Nvidia上,它可以正常工作,绿色区域可以使用或不使用in_Color

我使用的是AMD不支持的内容吗?我使用的是GLSL规格以外的东西吗?我知道AMDGL规范比Nvidia更严格,所以我可以做一些未定义的事情。我让代码尽可能简单并且仍然存在问题,所以我没有看到它 另外,我注意到如果in_Color顶点属性被禁用(无glEnableVertexAttribArray),它将不会在屏幕上绘制任何内容(甚至是蓝色区域),但为什么呢?我甚至不使用这种颜色。禁用的属性需要按规范返回(0,0,0,1)吗?我尝试使用glVertexAttrib4f来改变颜色,但仍然是黑色的。编译器和链接器不会返回任何错误或警告。使用glGetAttribLocation可以很好地找到属性in_Color。但正如我所说,这一点都不重要,因为该分支永远不会在我的代码中执行。有什么想法吗?

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;
}

所以没有分支。我得到了这个: Without branching there is still that bug 如果我通过删除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;
}

我明白了: Without branching as expected

这最后一个是我所期望的,但前一个没有绘制任何东西,即使我做了添加(+)而不是其他任何东西。因此,如果未绑定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上不需要那个。所以我想这会慢一点我浪费带宽?但至少它是有效的......但是如何更好地做到这一点的帮助会很有用。

1 个答案:

答案 0 :(得分:1)

这可能是因为您为着色器指定了3个输入值(in_Position,in_Color和in_TextureCoord),但您的顶点数据并不总是包含全部3.当顶点属性与此格式不完全匹配时,您可以“#”;重新进入未定义的行为领域,每个实现都可以做到它想要的。

似乎Nvidia驱动程序将它所具有的功能绑定到适当的顶点属性并使用它进行渲染。

也就是说,您的数据看起来像下面的着色器:

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

AMD驱动程序可能试图将顶点数据解释为所有3个属性,即使颜色不包括在内也是如此。在第一个顶点之后,该位置与数据数组中的位置不同步,这将导致它几乎在任何地方呈现。我怀疑当你删除in_Color属性的使用时它在AMD上工作的原因是因为着色器编译器发现它没有被使用并且优化了你指定它的事实。

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

可能的解决方案是执行您已经完成的操作并在您不需要时指定垃圾颜色数据,或者您可以将顶点着色器拆分为具有不同顶点属性的2个独立的着色器,并根据是否绑定相应的顶点着色器或不是你有顶点颜色数据。