shader compilation error on const value - opengl

Hi I'm having a bug on a fragment shader that doesn't compile on certain computers. The program using this shader is running on my computer (Quadro K1000M, OpenGl 4.2) but crashes at launch on my friend's computer (AMD Firepro M4100 FireGL V, OpenGl 4.2).
The error is:
Failed to compile fragment shader:
Fragment shader failed to compile with the following errors:
ERROR: 0:2: error(#207) Non-matching types for const initializer: const
ERROR: error(#273) 1 compilation errors. No code generated
The shader code is as follows:
uniform sampler2D source;
const float Threshold = 0.75;
const float Factor = 4.0;
#define saturate(x) clamp(x, 0.f, 1.f)
void main()
{
vec4 sourceFragment = texture2D(source, gl_TexCoord[0].xy);
float luminance = sourceFragment.r * 0.2126 + sourceFragment.g * 0.7152 + sourceFragment.b * 0.0722;
sourceFragment *= saturate(luminance - Threshold) * Factor;
gl_FragColor = sourceFragment;
}
I didn't find any info about this error. I asked my friend to edit the shaders to remove the const keyword, the program then worked. But I don't understand why this keyword generates compilation error on his computer since he seems to have the same OpenGL version as I have. I tried to search for known issues between const and shaders but I didn't find anything.
Do you have any idea what's happening ?

Related

What is the syntax for 'pixel_interlock_ordered' in GLSL?

I'm trying out the ARB_fragment_shader_interlock extension in OpenGL 4.5 and am failing to get the shader to compile when trying to use pixel_interlock_ordered.
#version 430
#extension GL_ARB_shading_language_420pack : require
#extension GL_ARB_shader_image_load_store : require
#extension GL_ARB_fragment_shader_interlock : require
layout(location = 0, rg8, pixel_interlock_ordered) uniform image2D image1;
void main()
{
beginInvocationInterlockARB();
ivec2 coords = ivec2(gl_FragCoord.xy);
vec4 pixel = imageLoad(image1, coords);
pixel.g = pixel.g + 0.01;
if (pixel.g > 0.5)
pixel.r = pixel.r + 0.01;
else
pixel.r = pixel.r + 0.02;
imageStore(image1, coords, pixel);
endInvocationInterlockARB();
}
The following shader fails compilation with:
0(6) : error C7600: no value specified for layout qualifier 'pixel_interlock_ordered'
Which is the same error you would get for any random name instead of pixel_interlock_ordered. I guess the syntax is different somehow, but the spec (https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_fragment_shader_interlock.txt) refer to it as a "layout qualifier".
Googling "pixel_interlock_ordered" comes up short with just links to the official specs, so I can't find an example. What is the correct syntax?
Layout qualifiers in GLSL are a bit weird. They usually apply to declarations, but some of them effectively apply to the shader as a whole. Such qualifiers are basically shader-specific options you set from within the shader.
The interlock qualifiers are those kinds of qualifiers. You're not saying that this variable will be accessed via interlocking, because that's not what interlocking means. It means that the execution of the interlock-bound code will have a certain property, relative to executing interlock-bound code on other invocations of the same shader. The qualifier specifies the details of the execution restriction.
Qualifiers that apply to the shader as a whole are grammatically specified as qualifiers on in or out (most such qualifiers use in, but a few use out):
layout(pixel_interlock_ordered) in;

Uniform registers requirement on Nvidia with a sampler in vertex shader

The issue I'm going to write about can only be reproduced with some hardware and drivers.
I managed to reproduce it on GeForce GTX 760 with 399.24 driver and GeForce 950M with 416.34. The issue does not show up on GTX650 with 390.87 driver. All these GPUs return 1024 for GL_MAX_VERTEX_UNIFORM_VECTORS, so I hardcoded 1000 as vec4 array size in vertex shader.
I try to compile and link the following shader program.
Vertex shader:
#version 330
uniform vec4 vs[1000];
uniform sampler2D tex;
void main()
{
gl_Position = vs[42];
//gl_Position += texture(tex, vs[0].xy); // (1)
}
Fragment shader:
#version 330
out vec4 outFragColor;
void main()
{
outFragColor = vec4(0.0);
}
Everything is OK while line (1) is commented and thus tex sampler is optimized out. But if we uncomment it, link fails with the following log:
-----------
Internal error: assembly compile error for vertex shader at offset 427:
-- error message --
line 16, column 9: error: invalid parameter array size
line 20, column 16: error: out of bounds array access
line 22, column 30: error: out of bounds array access
-- internal assembly text --
!!NVvp5.0
OPTION NV_internal;
OPTION NV_gpu_program_fp64;
OPTION NV_bindless_texture;
Error: could not link.
# cgc version 3.4.0001, build date Oct 10 2018
# command line args:
#vendor NVIDIA Corporation
#version 3.4.0.1 COP Build Date Oct 10 2018
#profile gp5vp
#program main
#semantic vs
#semantic tex
#var float4 gl_Position : $vout.POSITION : HPOS : -1 : 1
#var float4 vs[0] : : c[0], 1000 : -1 : 1
#var ulong tex : : c[1000] : -1 : 1
PARAM c[2002] = { program.local[0..2001] };
TEMP R0;
LONG TEMP D0;
TEMP T;
PK64.U D0.x, c[1000];
TEX.F R0, c[0], handle(D0.x), 2D;
ADD.F result.position, R0, c[42];
END
# 3 instructions, 1 R-regs, 1 D-regs
Here we see that the array takes registers 0..999, and the sampler takes register 1000. Elements above 1000 are not referenced anywhere except line PARAM c[2002] = { program.local[0..2001] };.
Further experiments with array size showed that 2002 is not a constant, but a doubled amount of registers required.
I remember that
OpenGL implementations are allowed to reject shaders for
implementation-dependent reasons.
So is there a workaround to use all available registers along with a sampler in a vertex shader?
If not, what might be the rationale behind this behavior? Obviously, this shader does not use any registers for temporary computation results.
Is it a misoptimization in shader compiler?
UPD: a quick-n-diry reproduction example is here.
UPD2: Webgl repro with workaround description.

"Variable is not available in the current GLSL version"

I am attempting to create a tessellation shader:
#version 410 core
// define the number of CPs in the output patch
layout (vertices = 3) out;
uniform vec3 gEyeWorldPos;
// attributes of the input CPs
in vec3 WorldPos_CS_in[];
in vec2 TexCoord_CS_in[];
in vec3 Normal_CS_in[];
// attributes of the output CPs
out vec3 WorldPos_ES_in[];
out vec2 TexCoord_ES_in[];
out vec3 Normal_ES_in[];
float GetTessLevel(float Distance0, float Distance1)
{
float AvgDistance = (Distance0 + Distance1) / 2.0;
if (AvgDistance <= 2.0) {
return 10.0;
}
else if (AvgDistance <= 5.0) {
return 7.0;
}
else {
return 3.0;
}
}
void main()
{
// Set the control points of the output patch
TexCoord_ES_in[gl_InvocationID] = TexCoord_CS_in[gl_InvocationID];
Normal_ES_in[gl_InvocationID] = Normal_CS_in[gl_InvocationID];
WorldPos_ES_in[gl_InvocationID] = WorldPos_CS_in[gl_InvocationID];
// Calculate the distance from the camera to the three control points
float EyeToVertexDistance0 = distance(gEyeWorldPos, WorldPos_ES_in[0]);
float EyeToVertexDistance1 = distance(gEyeWorldPos, WorldPos_ES_in[1]);
float EyeToVertexDistance2 = distance(gEyeWorldPos, WorldPos_ES_in[2]);
// Calculate the tessellation levels
gl_TessLevelOuter[0] = GetTessLevel(EyeToVertexDistance1, EyeToVertexDistance2);
gl_TessLevelOuter[1] = GetTessLevel(EyeToVertexDistance2, EyeToVertexDistance0);
gl_TessLevelOuter[2] = GetTessLevel(EyeToVertexDistance0, EyeToVertexDistance1);
gl_TessLevelInner[0] = gl_TessLevelOuter[2];
}
However, when I run my game, I get the following error:
Error: 1281
Tessellation shader wasn't able to be compiled correctly. Error log:
ERROR: 0:? : '' : Incorrect GLSL version: 410
WARNING: -1:65535: 'GL_ARB_explicit_attrib_location' : extension is not available in current GLSL version
WARNING: 0:4: 'vertices' : symbol not available in current GLSL version
WARNING: 0:? : 'gl_InvocationID' : variable is not available in current GLSL version
WARNING: 0:? : 'gl_InvocationID' : variable is not available in current GLSL version
WARNING: 0:? : 'gl_InvocationID' : variable is not available in current GLSL version
WARNING: 0:? : 'gl_InvocationID' : variable is not available in current GLSL version
WARNING: 0:? : 'gl_InvocationID' : variable is not available in current GLSL version
WARNING: 0:? : 'gl_InvocationID' : variable is not available in current GLSL version
WARNING: 0:? : 'gl_TessLevelOuter' : variable is not available in current GLSL version
WARNING: 0:? : 'gl_TessLevelOuter' : variable is not available in current GLSL version
WARNING: 0:? : 'gl_TessLevelOuter' : variable is not available in current GLSL version
WARNING: 0:? : '
My game appears to be ignoring the shaders, but I guess that is expected with so many errors?
I have already tried googling the error, however I am unable to find any solution or even information on why this is happening.
How can I fix the above errors so my shader can run correctly?
Well, you probably don't have a OpenGL-4.1 core context to begin with, and thus your shaders won't compile. Instead of debugging the shaders, I suggest you look at your context creation code and double check your system is cabable of giving you a 4.1 version context.

Invalid value GLSL?

After letting my opengl program run for a while and viewing the scene from different angles I am getting an OpenGL "invalid value" error in my shader program. This is literally my program:
Vertex
#version 420
in vec4 Position;
uniform mat4 modelViewProjection;
void main()
{
in vec4 Position;
uniform mat4 modelViewProjection;
}
Fragment
#version 420
out vec4 fragment;
void main()
{
fragment = vec4(1,0,0,1);
}
This error occurs right after the function call to tell OpenGL to use my shader program. What could the cause of this be? It happens regardless of the object I call it on. How can I get more information on what is going on? The error occurs almost randomly for a series of frames, but then works again after a while, fails again after a bit, ect.
If it helps, here is what my program linking looks like:
...
myShader = glCreateProgram();
CreateShader(myShader,GL_VERTEX_SHADER, "shaders/prog.vert");
CreateShader(myShader,GL_FRAGMENT_SHADER, "shaders/prog.frag");
glLinkProgram(myShader);
PrintProgramLog(myShader);
...
void CreateShader(int prog, const GLenum type, const char* file)
{
int shad = glCreateShader(type);
char* source = ReadText(file);
glShaderSource(shad,1,(const char**)&source,NULL);
free(source);
glCompileShader(shad);
PrintShaderLog(shad,file);
glAttachShader(prog,shad);
}
This is what I'm using to get the error:
void ErrCheck(const char* where)
{
int err = glGetError();
if (err) fprintf(stderr,"ERROR: %s [%s]\n",gluErrorString(err),where);
}
And here is what is being printed out at me:
ERROR: invalid value [drawThing]
It happens after I call to use the program:
glUseProgram(_knightShaders[0]);
ErrCheck("drawThing");
or glGetUniformLocation:
glGetUniformLocation(myShader, "modelViewProjection");
ErrCheck("drawThing2");
So I fixed the problem. What I had above wasn't the whole truth, what I actually had was
myShader[0] = glCreateProgram();
myShader was an array of 4 GLuint(s), each int being a different shader program (although at this point they were all copies of the shader program I posted above). The problem was fixed when I stopped using an array and instead used:
GLuint myShader0;
GLuint myShader1;
GLuint myShader2;
GLuint myShader3;
Why this fixed the problem makes no sense to me, it's also pretty annyoing because rather than being able to index the shader mode I want, such as:
int mode = ... (code the determine what shader to use here)
glUseProgram(myShader[mode]);
I have to instead use conditionals:
int mode = ... (code the determine what shader to use here)
if (mode == 0) glUseProgram(myShader0);
else if (mode == 1) glUseProgram(myShader1);
else if (mode == 2) glUseProgram(myShader2);
else glUseProgram(myShader3);
If anyone of you know why this fixes the problem, I would very much appreciate the knowledge!

GLSL shaders and WebGL problem

I have created a shader that works perfectly in Firefox, but in Chrome the fragment and vertex shader cannot be linked. They compile just fine, but at the linking part something goes wrong. I have localized the problem at the fallowing bit of code :
else if (uLightType[i] == 1) { //point light
NdotL = dot(n, normalize(lightDir[i]));
if (NdotL > 0.0) {
distance = length(lightDir[i]);
att = (1.0 / (uLightAttenuation[i] * distance * distance));
color += vec3(uLightColor[i] * NdotL * uLightIntensity[i] * att);
}
}
This small piece of code calculates the diffuse color reflected from a point light. It's part of a larger for loop. As it is shown here it won't link at all, but if I remove uLightAttenuation from calculating att, like so :
att = (1.0 / (distance * distance));
it works just fine. If I replace it with any other uniform, say uLightIntensity,
att = (1.0 / (uLightIntensity[i] * distance * distance));
again it won't work. If I replace it with a simple constant value / float variabile, strangely enough it compiles. And what is even more strange is, if I remove att from calculating color, but keep the uniform at it's current position, it runs just fine:
att = (1.0 / (uLightAttenuation[i] * distance * distance));
color += vec3(uLightColor[i] * NdotL * uLightIntensity[i]);
The uniform is a float value, and even if it were a problem with type casting it should fail at compilation, not linking.
Here are the complete shaders, maybe I missed something elsewhere in the code.
Fragment Shader
Vertex Shader
I have managed to make it to work, it turns out I had 2 problems. One is with division by 0 when calculating att. It would let me divide something over a float uniform, so I combined uLightAttenuation and uLightIntensity into a single vec2 uniform, after that that part worked. Secondly, when calculating color I had to reference every component individually (color[0], color[1] etc...) and work only with float variables and not vectors. After that it worked correctly in chrome to.