Bizarre GLSL link error

Started by
9 comments, last by dpadam450 12 years, 4 months ago
Hi guys, this is driving my crazy. I have 1 vertex shader and 1 fragment shader linked into 1 program (so far, so good :)

However, on the linking stage, my shader crashes, *but only if I make a very specific code alteration*. Here's what *works*:

fragment:


#version 410

in vec3 vnormal;
in vec3 vlight[10];

out vec4 color;
uniform vec4 fill_color;

void main(void) {
color = fill_color;
}



vertex:


#version 410

layout(location = 0) in vec4 position;
layout(location = 1) in vec3 normal;

layout(std140) uniform matrices_block {
mat4 projection;
mat4 modelview;
mat3 normal;
} mat;

out vec3 vnormal;
out vec3 vlight[10];

uniform int num_lights;

void main(void) {
vnormal = mat.normal * normal;
vec4 vertex_eye = mat.modelview * position;

int j = 0;
for (int i=0; i<num_lights; i++) {
j = 0;
vlight[j] = vec3(0.0);
}

gl_Position = mat.projection * mat.modelview * position;
}



This works fine. Compiles, runs, etc. I know it looks a little crazy that I'm using "j" to index vlight, and setting j=0 every time in the loop, but hear me out for a second. Here's what doesn't work in the vertex shader:

If i move this:


j = 0;
vlight[j] = vec3(0.0);



To this:


vlight[j] = vec3(0.0);
j = 0;



The shader programs refuse to link. What's worse is, there's no output log from glGetShaderInfoLog, so I can't tell what's going wrong. This is really weird behavior, and it's starting to make me question my drivers. If it's any help, my graphics card is an Nvidia GeForce GTX 485M with driver 280.13.

Anyone have any insight on what I can poke at next? Thanks!
Advertisement
Update:

I've managed to narrow it down to the uniform "num_lights". From my client code, I'm setting num_lights to 1. However, if I comment out "uniform int num_lights" and add an "int num_lights = 1;" to my main(), the code works again.

So there's some weirdness with setting the uniform, which is creating even more weirdness in the code. I'm using glProgramUniform1i, and the uniform location is non-negative (it's 34), and the value is an integer. So there doesn't seem to be any error with that.

Any insight? Thanks
Try getting rid of the useless line "j=0" and just use vlight[0] instead for the time being. Sometimes compilers optimize things. You already said that line changed things. Or just do vlight anyway since that is what your loop seems to need anyway.

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

What may be going on is that I have had (and others) where shaders do not work if you dont explicitly use a uniform. Sometimes shaders unroll your loops and since your loop never uses the index "i", it again is probably optimizing it. So STOP IT!

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal


What may be going on is that I have had (and others) where shaders do not work if you dont explicitly use a uniform. Sometimes shaders unroll your loops and since your loop never uses the index "i", it again is probably optimizing it. So STOP IT!


I probably should've clarified why I wasn't using "i" to index vlight. I was using "i" first, which is where the error first surfaced. So instead, I created "j" just to see if I could get the same bad behavior with a variable that wasn't being compared to num_lights, which it did.

I'll keep poking at it more. I'm clearly messing around with some very undefined behavior, so this is turning out to not be easy.
What I mean is that your loop regardless of what variable you use, is technically at the core it is not a loop, so the compiler might be smart enough to fiddle with your code. So whoever rated me down should understand that and help people out instead of just browsing and rating people down. So many losers on here. As I said, even things like sending uniforms I have had several Nvidia cards that return a -1 index on uniforms variables that I only declare and never use. So it could be something like this. Obviously everything looks pretty much fine, just that your loop is the only suspicious piece of code. So make that loop actually do something and see what happens. If it fixes it then don't waste 3 hours debugging code that isn't really "correct".

int j = 0;
for (int i=0; i<num_lights; i++)
{
j = 0;
vlight[j] = vec3(0.0);
}

might just compile to:
int j = 0;
vlight[j] = vec3(0.0)
hence no num_lights variable anymore.

Sometimes compilers will go further and se that j is not really a variable either and it might just go to:
vlight[0] = vec3(0.0)

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

Yeah, I think I see what you're saying about unrolling the loops. I googled "glsl uniform loop" and it seems that there have been a lot of people with issues of using a uniform in the expression part of a loop. This could be my problem. If I set the expression to a constant value, either through a #define, or with some fixed value in the code, it works fine.

I double-checked my glGetUniformLocation and it's not returning -1, so I think that's fine. It must be the uniform in the loop creating undefined behavior. Might be a bug in the driver. I'm going to upgrade my driver right now actually and see if that solves it.
After a lot of poking at the shader code (and updating my drivers), I've come to the conclusion that I can't do the following things together:

I can't have a loop based on a uniform expression AND have that loop alter an "out" array.

For example, this works:



#version 420

layout(location = 0) in vec4 position;
out int derp[10];

uniform int num_lights;

void main(void) {
for (int i=0; i<10; i++) {
derp = i;
}

gl_Position = position;
}



And this works:

#version 420

layout(location = 0) in vec4 position;
out int derp[10];

uniform int num_lights;

void main(void) {
int j = 0;
for (int i=0; i<num_lights; i++) {
j += i;
}

gl_Position = position;
}


But this doesn't:


#version 420

layout(location = 0) in vec4 position;
out int derp[10];

uniform int num_lights;

void main(void) {
for (int i=0; i<num_lights; i++) {
derp = i;
}

gl_Position = position;
}





Really bizarre behavior.
So the last one just doesnt link still? Or does it give you an invalid uniform location?

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal


So the last one just doesnt link still? Or does it give you an invalid uniform location?


Well, it never actually gets to the point where I get the uniform location. The code fails on linking the compiled shaders, so I can't even assign a uniform yet.

That's a weird limitation if I can only use a uniform for loops that don't modify an "out" variable, but I'll have to accept it I guess if it's true.

This topic is closed to new replies.

Advertisement