Android PowerVR GPU上的着色器执行流问题

Android PowerVR GPU上的着色器执行流问题,android,opengl-es,opengl-es-2.0,glsl,Android,Opengl Es,Opengl Es 2.0,Glsl,我遇到了一个问题,我相信这与优化PowerVR GPU的GLSL编译有关。在Adreno和Tegra上,GPU片段着色器工作正常,但在PowerVR(Motorola Droid)上,它在条件语句中产生不正确的结果。 我已经通过更改片段着色器代码中的条件语句修复了这个问题。我添加了elseblock并在PowerVR上正常工作,而不是在block中为if语句调用return 两个着色器的逻辑完全相同,gl\u FragColor在这两种情况下都被设置。 请解释PowerVR OpenGL驱动程序

我遇到了一个问题,我相信这与优化PowerVR GPU的GLSL编译有关。在Adreno和Tegra上,GPU片段着色器工作正常,但在PowerVR(Motorola Droid)上,它在条件语句中产生不正确的结果。 我已经通过更改片段着色器代码中的条件语句修复了这个问题。我添加了
else
block并在PowerVR上正常工作,而不是在block中为
if
语句调用
return

两个着色器的逻辑完全相同,
gl\u FragColor
在这两种情况下都被设置。 请解释PowerVR OpenGL驱动程序的这种行为,以便我将来可以避免出现问题。为什么它以这种方式处理条件语句

这是旧的片段着色器,它在PowerVR GPU上工作不正确:

precision mediump float;

varying vec3 vNormal;
varying vec3 vViewVec;
varying vec2 vTextureCoord;

uniform sampler2D sTexturePumpkin;

void main(void)
{
const float sheen = 0.68;
const float noiseScale = 0.05;
const float furriness = 10.0;
const vec4 lightDir = vec4(0.267260, 0.267260, -0.925820, 0.0);

  vec4 color = texture2D(sTexturePumpkin, vTextureCoord/*vec2(0.0,0.0)*/);
  if(vTextureCoord.y > 0.7) { // in this case PowerVR displays incorrect color
     gl_FragColor = color;
     return;
  }

  float diffuse = 0.5 * (1.0 + dot(vNormal, vec3(lightDir.x, lightDir.y, -lightDir.z)));
  float cosView = clamp(dot(normalize(vViewVec), vNormal), 0.0, 1.0);
  float shine = pow(1.0 - cosView * cosView, furriness);

  gl_FragColor = (color + sheen * shine) * diffuse; // in this case PowerVR works correctly
}
新的片段着色器代码在Adreno和PowerVR GPU上都能正常工作:

precision mediump float;

varying vec3 vNormal;
varying vec3 vViewVec;
varying vec2 vTextureCoord;

uniform sampler2D sTexturePumpkin;

void main(void)
{
const float sheen = 0.68;
const float noiseScale = 0.05;
const float furriness = 10.0;
const vec4 lightDir = vec4(0.267260, 0.267260, -0.925820, 0.0);

  vec4 color = texture2D(sTexturePumpkin, vTextureCoord/*vec2(0.0,0.0)*/);
  if(vTextureCoord.y > 0.7) {
     gl_FragColor = color;
  }
  else {
    float diffuse = 0.5 * (1.0 + dot(vNormal, vec3(lightDir.x, lightDir.y, -lightDir.z)));
    float cosView = clamp(dot(normalize(vViewVec), vNormal), 0.0, 1.0);
    float shine = pow(1.0 - cosView * cosView, furriness);
    gl_FragColor = (color + sheen * shine) * diffuse;
  }
}

好的,在深入调查之后,我发现这不是着色器编译器的bug,而是处理片段着色器执行的一种特定方式。把一个简单的
丢弃通常是个坏主意
返回语句,后面有一些代码。它仍然可以执行,并导致不可预测的结果

有一些文章解释了这种行为适用于
discard语句,正如我看到的,
return也会出现类似的行为也是。
请在此阅读:
正如这里所说的,在某些情况下,您甚至可以通过错误地使用
discard来实现无限循环

片段着色器由GPU执行,一次不针对单个texel,通常以2x2像素为一批。片段着色器的并行运行会导致
返回后的代码


因此,要使片段着色器正确处理
if
语句,必须始终在
if
运算符中使用
else
,而不是简单地通过
return退出函数
丢弃。这正是我所做的。

它看起来像一个驱动程序错误。驱动程序bug,作为bug,并不是真正可以“解释”的东西。你可以使用vec3(lightDir.xy,-lightDir.z)。@Nicolas我相信这不是GLSL编译器中的错误,而是基于PowerVR GPU分片渲染和片段着色器执行的特殊性。我想在下面的回答中得到一些批评。@keaukraine:不。OpenGL规范非常清楚在
放弃
返回
之后发生的行为。如果PowerVR的编译器没有/不能生成符合规范要求的PowerVR着色器代码,则这是一个驱动程序错误。@keaukraine:它不会停止执行,但会阻止这些执行的任何结果可见。它的行为必须像执行已经停止一样。如果这没有发生,那就是一个bug。