AMD's GLSL Compiler bug

There is my shader fragment program

#version 330 core
precision highp float;

struct frec {
  vec4 WorldPosition;
  vec3 LightEmissive;
  vec3 LightDiffuse;
  vec3 LightSpecular;
  vec3 Emissive;
  vec3 Diffuse;
  float DiffusePower;
  vec3 Specular;
  float SpecularPower;
  float Opacity;
  float OpacityMask;
  vec3 Normal;
  vec3 CameraVector;
};

struct lrec {
  vec4 WorldPosition;
  vec3 Ambient;
  vec3 Diffuse;
  vec3 Specular;
  vec3 SpotDirection;
  float SpotCutoff;
  float SpotExponent;
  float ConstantAtten;
  float LinearAtten;
  float QuadAtten;  
};

in vec4 fWorldPosition;
in vec3 fCameraVector;
out vec4 FragColor;

layout(std140) uniform LightsBlock {
  uniform  lrec Lights[16];
};

uniform ivec4 LightIndices[16];
uniform int LightNumber;

void GetFragment(inout frec A);
void Illuminate(inout frec A);
void PassFragmentColor(inout frec A);

void main()
{
  frec Local0;
  Local0.Opacity = 1.0;
  GetFragment(Local0);
  Illuminate(Local0);
  PassFragmentColor(Local0);
}

void GetFragment(inout frec A)
{
  A.WorldPosition = fWorldPosition;
  A.CameraVector = fCameraVector;
}

  void pointLight(inout frec A, lrec B)
  {
     float nDotVP;       // normal . light direction
     float nDotHV;       // normal . light half vector
     float attenuation;  // computed attenuation factor
     float d;            // distance from surface to light source
     vec3  VP;           // direction from surface to light position
     vec3  halfVector;   // direction of maximum highlights

     // Compute vector from surface to light position
     VP = B.WorldPosition.xyz - A.WorldPosition.xyz;

     // Compute distance between surface and light position
     d = length(VP);

     // Normalize the vector from surface to light position
     VP = normalize(VP);

     // Compute attenuation
     attenuation = 1.0 / (B.ConstantAtten + B.LinearAtten * d + B.QuadAtten * d * d);

     halfVector = normalize(VP + A.CameraVector);

     nDotVP = pow(max(0.0, dot(A.Normal, VP)), A.DiffusePower);
     nDotHV = pow(max(0.0, dot(A.Normal, halfVector)), A.SpecularPower);

     A.LightEmissive  += B.Ambient * attenuation;
     A.LightDiffuse  += B.Diffuse * nDotVP * attenuation;
     A.LightSpecular += B.Specular * nDotHV * attenuation;
  }

  void spotLight(inout frec A, lrec B)
  {
     float nDotVP;            // normal . light direction
     float nDotHV;            // normal . light half vector
     float spotDot;           // cosine of angle between spotlight
     float spotAttenuation;   // spotlight attenuation factor
     float attenuation;       // computed attenuation factor
     float d;                 // distance from surface to light source
     vec3  VP;                // direction from surface to light position
     vec3  halfVector;        // direction of maximum highlights

     // Compute vector from surface to light position
     VP = B.WorldPosition.xyz - A.WorldPosition.xyz;

     // Compute distance between surface and light position
     d = length(VP);

     // Normalize the vector from surface to light position
     VP = normalize(VP);

     // Compute attenuation
     attenuation = 1.0 / (B.ConstantAtten + B.LinearAtten * d + B.QuadAtten * d * d);

     // See if point on surface is inside cone of illumination
     spotDot = dot(-VP, normalize(B.SpotDirection));

     if (spotDot < cos(0.01745329251994*B.SpotCutoff))
     {
         spotAttenuation = 0.0; // light adds no contribution
     }
     else
     {
         spotAttenuation = pow(spotDot, B.SpotExponent);

     }
     // Combine the spotlight and distance attenuation.
     attenuation *= spotAttenuation;

     halfVector = normalize(VP + A.CameraVector);

     nDotVP = pow(max(0.0, dot(A.Normal, VP)), A.DiffusePower);
     nDotHV = pow(max(0.0, dot(A.Normal, halfVector)), A.SpecularPower);

     A.LightEmissive  += B.Ambient * attenuation;
     A.LightDiffuse  += B.Diffuse * nDotVP * attenuation;
     A.LightSpecular += B.Specular * nDotHV * attenuation;
  }

  void directionalLight(inout frec A, lrec B)
  {
     float nDotVP;         // normal . light direction
     float nDotHV;         // normal . light half vector
     vec3 VP;              // direction from surface to light position
     vec3 halfVector;      // direction of maximum highlights

     // Compute vector from surface to light position
     VP = normalize(B.WorldPosition.xyz - A.WorldPosition.xyz);

     halfVector = normalize(B.SpotDirection + A.CameraVector);

     nDotVP = pow(max(0.0, dot(A.Normal, VP)), A.DiffusePower);
     nDotHV = pow(max(0.0, dot(A.Normal, halfVector)), A.SpecularPower);

     A.LightEmissive += B.Ambient;
     A.LightDiffuse  += B.Diffuse * nDotVP;
     A.LightSpecular += B.Specular * nDotHV;
  }

  void infiniteSpotLight(inout frec A, lrec B)
  {
     float nDotVP;         // normal . light direction
     float nDotHV;         // normal . light half vector
     vec3 VP;              // direction from surface to light position
     vec3 halfVector;      // direction of maximum highlights
     float spotAttenuation;
     vec3  Ppli;
     vec3  Sdli;

     // Compute vector from surface to light position
     VP = normalize(B.WorldPosition.xyz - A.WorldPosition.xyz);

     halfVector = normalize(B.SpotDirection + A.CameraVector);

     nDotVP = pow(max(0.0, dot(A.Normal, VP)), A.DiffusePower);
     nDotHV = pow(max(0.0, dot(A.Normal, halfVector)), A.SpecularPower);

     Ppli = -VP;
     Sdli = B.SpotDirection;

     spotAttenuation = pow(dot(Ppli, Sdli), B.SpotExponent);

     A.LightEmissive  += B.Ambient * spotAttenuation;
     A.LightDiffuse  += B.Diffuse * nDotVP * spotAttenuation;
     A.LightSpecular += B.Specular * nDotHV * spotAttenuation;
  }
void Illuminate(inout frec A)
{
  A.LightEmissive = vec3(0.0,0.0,0.0);
  A.LightDiffuse = vec3(0.0,0.0,0.0);
  A.LightSpecular = vec3(0.0,0.0,0.0);

  for (int I = 0; I<LightNumber && I<16; I++)
  {
    int J = LightIndices[i].x;
    lrec LightSource = Lights[J];
    if (LightSource.WorldPosition.w == 1.0)
    {
      if (LightSource.SpotCutoff == 180.0)
      {
         pointLight(A,LightSource);
      }
      else
      {
         spotLight(A,LightSource);
      }
   }
    else
    {
      if (LightSource.SpotCutoff == 180.0)
      {
         directionalLight(A,LightSource);
      }
      else
      {
         infiniteSpotLight(A,LightSource);
      }
    } 
  }
  vec3 finalColor;
  finalColor = A.Emissive*clamp(A.LightEmissive,vec3(0.0),vec3(1.0));
  finalColor += A.Diffuse*clamp(A.LightDiffuse,vec3(0.0),vec3(1.0));
  finalColor += A.Specular*clamp(A.LightSpecular,vec3(0.0),vec3(1.0));
  A.Emissive = finalColor;
}

void PassFragmentColor(inout frec A)
{
  FragColor = vec4(A.Emissive, A.Opacity); 
}

The fragment object compile successfully, but program linking fail with error

Fragment shader(s) failed to link, vertex shader(s) failed to link.
unexpected error.
unexpected error.

I trying to test it by GPU Shader Analyze
in version 1.53 all fine,
but in version 1.55 fail with error

Internal compilation failure. Possibly caused by GSA not supporting a GLSL feature used in shader.
ERROR: 0:7: error(#132) Syntax error: ‘;’ parse error
ERROR: error(#273) 1 compilation errors. No code generated

Also I trying to simplify the shader, to leave only a one pointLight for first light source, to replace the uniform block to one structured uniform - does not help.

My system
Catalist 10.10 or 10.9
Radeon HD5450
WinXP SP2

I find workaround - exchange varyings and structure declaration.
I can not understand why this happens.
In GLSL specification do not specify a strong order.

The shader works for me with Cat10.10 driver. I’m using HD5700, but I don’t think there will be much difference.

Did you install 10.10c hotfix. I’m not because XP. Perhaps this is reason.

I can’t find the 10.10c hotfix for winxp. I retry the shader on winxp+Cat10.10+HD5450. It works.

If it’s not resolved on your side, you could try to narrow down your project and send it to me by frank.li@amd.com.

Ok. I sent project to test.

People, don’t look at shader, it vector algebra is wrong :o

Tested on
Radeon HD 4800, WinXP sp3, Catalist 10.9

same error (GL debug callback):
glLinkProgram failed to link a GLSL program with the following program info log: 'Fragment shader(s) failed to link, vertex shader(s) failed to link.
unexpected error.
unexpected error.

It’s a known issue and is fixed recently. Thanks for providing the demo to reproduce it.

hi frank,
can we have access to a beta driver with the fix included?

i am working on a tessellation shader on an AMD platform and my shaders compile without errors or warnings, but when linking them i get the same error message:

Fragment shader(s) failed to link,  vertex shader(s) failed to link.
unexpected error.
unexpected error.

i tried swapping some declarations around in all shaders, but i can not get rid of the error.

another problem i found is the following when using gl_InvocationID to index the control vertex in the tessellation control shader:


#version 400 core

layout(vertices = 4) out;

// tessellation control shader
in per_vertex {
    vec2 texcoord;
} vertex_in[];

out per_vertex {
    vec2 texcoord;
} vertex_out[];

...

    // not working
    gl_out[gl_InvocationID].gl_Position  = gl_in[gl_InvocationID].gl_Position;
    // working
    gl_out[0].gl_Position  = gl_in[0].gl_Position;
    gl_out[1].gl_Position  = gl_in[1].gl_Position;
    gl_out[2].gl_Position  = gl_in[2].gl_Position;
    gl_out[3].gl_Position  = gl_in[3].gl_Position;
    // not working
    vertex_out[gl_InvocationID].texcoord = vertex_in[gl_InvocationID].texcoord;
    // working
    vertex_out[0].texcoord = vertex_in[0].texcoord;
    vertex_out[1].texcoord = vertex_in[1].texcoord;
    vertex_out[2].texcoord = vertex_in[2].texcoord;
    vertex_out[3].texcoord = vertex_in[3].texcoord;

I am using a OpenGL 4.0 core profile context on Windows 7 x64.

The gl_InvocationID is also fixed recently.

Usually I’m not clear when the fix will be included in the beta driver. If you want to get access to a beta driver on windows, you have to get in touch with the workstation ISV engineering team.

Here’s an idea: have you tried declaring vertex_in[] and vertex_out[] with constants (presumably 4) rather than leaving their size implicit/undefined? Give that a try and see what happens.

Yesterday I installed Catalist 10.11 and find other problem.
There is shader object to fetch light source properties

#version 400 core
precision highp float;

struct lrec 
{
vec4 WorldPosition;
vec3 Ambient; 
vec3 Diffuse; 
vec3 Specular; 
vec3 SpotDirection; 
float SpotCutoff; 
float SpotExponent; 
float ConstantAtten; 
float LinearAtten; 
float QuadAtten;
float SpotCosCutoff;
};
		
layout(std140) uniform LightsBlock { lrec Lights[16]; }; 
uniform int LightIndices[16];
  
lrec GetLight(int A) 

{
  int J = LightIndices[A];
  return Lights[J];  
}

It compile fine.

But when program linking - error will happen
error(#278) Uniform block layout qualifiers can only be applied to the keyword uniform(layout qualifier should not apply to a specific declaration)

I try to remove layout(std140) qualifier - same error.

PS: a previous shader from first post now compile but data gets rightly only for first array element, in another is trash.
In general, both shaders are the same, but the functions are placed on different objects, however, the compiler interprets them differently. I’m stuck with it and can not continue to develop :frowning:

I think your problem is that you incorrectly declared your uniform block. Try this way:

layout(std140) uniform lightsblock {
  lrec Lights[16];
} LightsBlock;

Notice that the block variable name is at the end.

Yes, I tried that too, but same error.
According to spec instance-name is optional and
if is not used, the names declared inside the block are scoped at the global level and accessed as if they were declared outside the block.

Ahh, didn’t know that btw. I always used explicit instance name.
However, I wonder how’s that possible that the same error is raised also when you removed the layout(std140) qualifier. It should not complain about layout qualifiers if no such thing is used in the shader.
Are you sure that the link error comes from this shader? Maybe another shader part of the program is the guilty one.

I can’t reproduce your problem with Cat10.11. Could you please paste the whole shader?

Yes, I’m sure.

There is test project http://glscene.svn.sourceforge.net/viewvc/glscene/branches/TestForAMD/3xMaterialT4.rar?revision=5325
It is same as I send Frank Li previously, but has minimal different in shader objects. Please try it.

It fails at my side also with Cat10.10e.
However, it is pretty difficult to figure out what is what in the log file.
Maybe you should write a much simpler app to be sure that the error does not come from incorrect shader source code loading, or whatever.

Off-topic: You are the developer of GLScene? I was really amazed when I tried it a few years ago. Since that, I abandoned Delphi and moved to C++ as unfortunately Delphi is not a well accepted programming language for games and graphics, besides, it lacks of good libraries, but I also like the language better than C++.

Okey, I’ll try to write more simple program. But log is simple too, in ShaderCompilation.log message marked with (EE) is error.
MatTest4.log contain message from callback of GL_AMD_debug_output
like

glLinkProgram failed to link a GLSL program with the following program info log: 'Fragment shader(s) failed to link, vertex shader(s) failed to link.
unexpected error.
unexpected error.

PS: try it run on NVidia. I know NV is has more softer demand, but work fine as need for me :slight_smile:

Off-topic:
Yep, I one of current GLScene’s developer.
I try to lay foundations for future, when new hardware is more common, and drivers are more stable to work with the present version of OpenGL :slight_smile:
Currently working on node based material editor (Shader graph) build-in IDE

I’ve already learned Delphi, and have no desire to switch to another language just because they are more popular or have more libraries, whereas there are many other tasks, rather than spending time on mastering other languages. And Pascal for me is more human-friendly language :slight_smile: especially as it progresses, both from the Embarcadero, and from the FreePascal