PDA

View Full Version : shader not working for windows



PadMad
08-09-2016, 08:20 AM
Hey,

I successfully built an opengl project on ubuntu 14.04. I wanted to move it to windows now. For some reason the fragment shader doesn't link...
It can be created, compiled and attached to the program! but for linking, I recieve lots and lots of errors... but only on windows platform.
First, the stats:

Linux Ubuntu 14.04
-------------------------
Window: 1280px * 1024px
GL Version: 3.0 Mesa 10.5.9
GLSL Version: 1.30

Windows
-------------------------
Window: 1280px * 800px
GL Version: 4.5.0 NVIDIA 347.52
GLSL Version: 4.50 NVIDIA

These are the errors:



failed to link shader program:
Fragment info
-------------
Internal error: assembly compile error for fragment shader at offset 1350:
-- error message --
line 35, column 36: error: invalid local parameter number
line 58, column 18: error: out of bounds array access
line 64, column 24: error: out of bounds array access
line 68, column 23: error: offset for relative array access outside supported range
line 73, column 23: er...


I realize the different graphic cards, but what's wrong here? How can it work on one computer perfectly and on the other not even work at the linking stage?
Here's the shader:



///////////////////////////////////////////
///////////////////////////////////////////
// Fragment Shader 3D
///////////////////////////////////////////
///////////////////////////////////////////

#version 150

///////////////////////////////////////////
///////////////////////////////////////////
// Strukturen
///////////////////////////////////////////
///////////////////////////////////////////

struct En_Material
{
sampler2D diffuse;
sampler2D specular;
float shine;
};

struct En_Light
{
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 position;
int light_kind; // 1 Directional Light, 2 Pointing Light, 3 Spotlight
int light_switcher; // 0 aus, 1 an
float constant;
float linear;
float quadratic;
};

///////////////////////////////////////////
///////////////////////////////////////////
// Globals
///////////////////////////////////////////
///////////////////////////////////////////

in vec2 _uv; // in
in vec3 _normal; // in
in vec3 _frag; // in

uniform vec3 camera; // Kameraposition
uniform En_Material material; // Material
uniform int number_lights; // Anzahl an Lichtern insgesamt
uniform En_Light light[100]; // Lichtstruktur / maximal 100 Lichtquellen!
uniform bool light_affected; // sagt aus, ob Licht bei dem Vertex eine Rolle spielt

out vec4 color;

///////////////////////////////////////////
///////////////////////////////////////////
// Funktionsprototypen
///////////////////////////////////////////
///////////////////////////////////////////

vec4 calc_dir_light(int);
vec4 calc_plight(int);

///////////////////////////////////////////
///////////////////////////////////////////
// Hauptprogramm
///////////////////////////////////////////
///////////////////////////////////////////

void main(void)
{
// output

vec4 sum_color = vec4(0.0f, 0.0f, 0.0f, 0.0f);
vec4 ret_color = vec4(0.0f, 0.0f, 0.0f, 0.0f);

if((texture(material.diffuse, _uv).a < 0.1f) || (texture(material.specular, _uv).a < 0.1f))
{discard;}
else
{
if(!light_affected)
{color = texture(material.diffuse, _uv);}
else
{
for(int i = 0 ; i < number_lights ; i++)
{
if(light[i].light_switcher == 1) // Licht an?
{
switch(light[i].light_kind)
{
case 1: // directional Light
{
ret_color = calc_dir_light(i);
sum_color += ret_color;
} break;
case 2: // pointing Light
{
ret_color = calc_plight(i);
sum_color += ret_color;
} break;
};
}
}

color = sum_color;
}
}
}

///////////////////////////////////////////
///////////////////////////////////////////
// Funktionsdefinition
///////////////////////////////////////////
///////////////////////////////////////////

vec4 calc_dir_light(int i)
{
// Ambient

vec4 ambient = vec4(light[i].ambient, 1.0f) * texture(material.diffuse, _uv);

// Diffuse

vec3 norm = normalize(_normal);
vec3 light_dir = normalize(-(light[i].direction));
float diff = max(dot(norm, light_dir), 0.0f);
vec4 diffuse = vec4(light[i].diffuse, 1.0f) * diff * texture(material.diffuse, _uv);

// Specular

vec3 view_dir = normalize(camera - _frag);
vec3 reflect_dir = reflect(-light_dir, norm);
float spec = pow(max(dot(view_dir, reflect_dir), 0.0f), material.shine);
vec4 specular = vec4(light[i].specular, 1.0f) * spec * texture(material.specular, _uv);

return (ambient + diffuse + specular);
}

//------------------------------------------------------------------------
//------------------------------------------------------------------------

vec4 calc_plight(int i)
{
// Ambient

vec4 ambient = vec4(light[i].ambient, 1.0f) * texture(material.diffuse, _uv);

// Diffuse

vec3 norm = normalize(_normal);
vec3 light_dir = normalize(light[i].position - _frag);
float diff = max(dot(norm, light_dir), 0.0f);
vec4 diffuse = vec4(light[i].diffuse, 1.0f) * diff * texture(material.diffuse, _uv);

// Specular

vec3 view_dir = normalize(camera - _frag);
vec3 reflect_dir = reflect(-light_dir, norm);
float spec = pow(max(dot(view_dir, reflect_dir), 0.0f), material.shine);
vec4 specular = vec4(light[i].specular, 1.0f) * spec * texture(material.specular, _uv);

// Pointing Light

float distance = length(light[i].position - _frag);
float attenuation = 1.0f / (light[i].constant + light[i].linear * distance + light[i].quadratic * (distance * distance));
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;

return (ambient + diffuse + specular);
}


Thanks for any help or hint in advance! :)

mhagain
08-09-2016, 11:14 AM
The OS is not relevant.

What is relevant is the graphics hardware, the driver, and the GL and GLSL versions they provide.

I haven't fully reviewed your shader code, but errors such as this are typically caused by attempting to use features that are legal with one GLSL version but illegal with the other (the "f" suffix on float literals is one example; there are others), a core profile being enabled/disabled, exceeding hardware capabilities of one device, hardware acceleration vs software emulation, some drivers being more lax than others, etc.

It should in fact be your Linux box that fails with this shader, since you say that your Linux box only has GLSL 1.30 but you're specifying #version 150 in your shader. Perhaps you're not giving us the full information?

PadMad
08-09-2016, 02:30 PM
Hey,

thanks for your reply. I changed the GLSL version for testing on windows machine, cause I also received an error telling me, that version #version 130 would be too low. It was #version 130 before on linux and everything worked fine.

I even wrote a set of functions for my application, that provides detailed information about any opengl / shader error that occurs. (The output is a html file.) So I'm close to 100% sure everything is fine on linux.

But I understand what you are saying. So is there a core set of GLSL syntax / functions that would work on most machines? starting with version 1.3 to 4.x? I don't wanna end up writing separate versions of my shaders for any opengl /glsl / driver combination that exist...

That'd would be too complex, right?
Or is there a solution I don't see?

GClements
08-09-2016, 02:53 PM
But I understand what you are saying. So is there a core set of GLSL syntax / functions that would work on most machines? starting with version 1.3 to 4.x? I don't wanna end up writing separate versions of my shaders for any opengl /glsl / driver combination that exist...

For maximum compatibility, choose the lowest GLSL version which has the features you need, and ensure that your code conforms to it. Don't rely upon the driver to point out any mistakes; most drivers have some degree of fault-tolerance. Print out the compilation and linking logs even if compilation and linking succeeds.

mhagain
08-10-2016, 04:33 AM
I changed the GLSL version for testing on windows machine, cause I also received an error telling me, that version #version 130 would be too low. It was #version 130 before on linux and everything worked fine.
This means that you're using features in your GLSL that are not available in #version 130. I suggest that you start by removing that floating point literal suffix, because that was never legal GLSL in older versions.

Again, and forgive me if I'm banging on about this, but this is nothing to do with the OS. The GL implementation you're using on your Linux machine is allowing illegal GLSL for #version 130 is what the cause of that problem is.


So is there a core set of GLSL syntax / functions that would work on most machines? starting with version 1.3 to 4.x? I don't wanna end up writing separate versions of my shaders for any opengl /glsl / driver combination that exist...
Legal #version 130 GLSL will work in compatibiliy contexts on all of those targets, assuming the absence of driver bugs, of course.

OpenGL 3.0 specification: https://www.opengl.org/registry/doc/glspec30.20080923.pdf
GLSL 1.30 specification: https://www.opengl.org/registry/doc/GLSLangSpec.Full.1.30.10.pdf

So long as you code to the specifications, a compliant implementation will always work.

PadMad
08-10-2016, 06:42 AM
Hey,

thanks for the GLSL 1.30 specification. I was able to spot (maybe) 2 mistakes (1 for sure).
These are the updated shaders:



///////////////////////////////////////////
///////////////////////////////////////////
// Vertex Shader
///////////////////////////////////////////
///////////////////////////////////////////

#version 130
#extension GL_ARB_gpu_shader5 : enable

in vec3 in_vpos; // in
in vec2 in_uv; // in
in vec3 in_normal; // in

out vec2 _uv; // out Texturkoordinaten
out vec3 _normal; // out Normalenvektor
out vec3 _frag; // out Fragmentposition

uniform mat4 mvp;
uniform mat4 model;

void main(void)
{
// gl_Position legt die Position für einen Vertex fest

gl_Position = mvp * model * vec4(in_vpos, 1.0);

// übergibt die Texturkoordinaten

_uv = in_uv;
_normal = mat3(transpose(model)) * in_normal;
_frag = vec3(model * vec4(in_vpos, 1.0));
}


and:



///////////////////////////////////////////
///////////////////////////////////////////
// Fragment Shader 3D
///////////////////////////////////////////
///////////////////////////////////////////

#version 130
#extension GL_ARB_gpu_shader5 : enable

///////////////////////////////////////////
///////////////////////////////////////////
// Strukturen
///////////////////////////////////////////
///////////////////////////////////////////

struct En_Material
{
sampler2D diffuse;
sampler2D specular;
float shine;
};

struct En_Light
{
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 position;
int light_kind; // 1 Directional Light, 2 Pointing Light, 3 Spotlight
int light_switcher; // 0 aus, 1 an
float constant;
float linear;
float quadratic;
};

///////////////////////////////////////////
///////////////////////////////////////////
// Globals
///////////////////////////////////////////
///////////////////////////////////////////

in vec2 _uv; // in
in vec3 _normal; // in
in vec3 _frag; // in

uniform vec3 camera; // Kameraposition
uniform En_Material material; // Material
uniform int number_lights; // Anzahl an Lichtern insgesamt
uniform En_Light light[100]; // Lichtstruktur / maximal 100 Lichtquellen!
uniform bool light_affected; // sagt aus, ob Licht bei dem Vertex eine Rolle spielt

out vec4 color;

///////////////////////////////////////////
///////////////////////////////////////////
// Funktionsprototypen
///////////////////////////////////////////
///////////////////////////////////////////

vec4 calc_dir_light(int);
vec4 calc_plight(int);

///////////////////////////////////////////
///////////////////////////////////////////
// Hauptprogramm
///////////////////////////////////////////
///////////////////////////////////////////

void main(void)
{
// output

vec4 sum_color = vec4(0.0, 0.0, 0.0, 0.0);
vec4 ret_color = vec4(0.0, 0.0, 0.0, 0.0);

if((texture(material.diffuse, _uv).a < 0.1) || (texture(material.specular, _uv).a < 0.1))
{discard;}
else
{
if(!light_affected)
{color = texture(material.diffuse, _uv);}
else
{
for(int i = 0 ; i < number_lights ; i++)
{
if(light[i].light_switcher == 1) // Licht an?
{
switch(light[i].light_kind)
{
case 1: // directional Light
{
ret_color = calc_dir_light(i);
sum_color += ret_color;
} break;
case 2: // pointing Light
{
ret_color = calc_plight(i);
sum_color += ret_color;
} break;
};
}
}

color = sum_color;
}
}
}

///////////////////////////////////////////
///////////////////////////////////////////
// Funktionsdefinition
///////////////////////////////////////////
///////////////////////////////////////////

vec4 calc_dir_light(int i)
{
// Ambient

vec4 ambient = vec4(light[i].ambient, 1.0) * texture(material.diffuse, _uv);

// Diffuse

vec3 norm = normalize(_normal);
vec3 light_dir = normalize(-(light[i].direction));
float diff = max(dot(norm, light_dir), 0.0);
vec4 diffuse = vec4(light[i].diffuse, 1.0) * diff * texture(material.diffuse, _uv);

// Specular

vec3 view_dir = normalize(camera - _frag);
vec3 reflect_dir = reflect(-light_dir, norm);
float spec = pow(max(dot(view_dir, reflect_dir), 0.0), material.shine);
vec4 specular = vec4(light[i].specular, 1.0) * spec * texture(material.specular, _uv);

return (ambient + diffuse + specular);
}

//------------------------------------------------------------------------
//------------------------------------------------------------------------

vec4 calc_plight(int i)
{
// Ambient

vec4 ambient = vec4(light[i].ambient, 1.0) * texture(material.diffuse, _uv);

// Diffuse

vec3 norm = normalize(_normal);
vec3 light_dir = normalize(light[i].position - _frag);
float diff = max(dot(norm, light_dir), 0.0);
vec4 diffuse = vec4(light[i].diffuse, 1.0) * diff * texture(material.diffuse, _uv);

// Specular

vec3 view_dir = normalize(camera - _frag);
vec3 reflect_dir = reflect(-light_dir, norm);
float spec = pow(max(dot(view_dir, reflect_dir), 0.0), material.shine);
vec4 specular = vec4(light[i].specular, 1.0) * spec * texture(material.specular, _uv);

// Pointing Light

float dist = length(light[i].position - _frag);
float attenuation = 1.0 / (light[i].constant + light[i].linear * dist + light[i].quadratic * (dist * dist));
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;

return (ambient + diffuse + specular);
}


And here is the code snippit, where I'm tryin to build that first shader program:



int CApp::dycon_init_shader()
{
int exit_code = ERR_EN_NO_ERROR;
int param = 0;
int length_log = 0;
const unsigned short int SIZE_LOG = 400 + 1;
char compile_log[SIZE_LOG];

#if EMODE == EDEBUG_MODE
char * pBuffer = NULL;
pBuffer = new char[2048];
#endif

////////////////////////////////////////
// erstelle Shader 3D Programm
////////////////////////////////////////

#if EMODE == EDEBUG_MODE
this->dycon_write_log("<b>ENGINE:</b> --------------- Shader 3D ---------------", DB_MSG_OK);
#endif

this->pShader[SHADER_3D].prog_id = glCreateProgram();

if(this->pShader[SHADER_3D].prog_id)
{
#if EMODE == EDEBUG_MODE
this->dycon_write_log("<b>ENGINE:</b> glCreateProgram: OK", DB_MSG_OK);
#endif

// Anzahl an Shader Schritte

this->pShader[SHADER_3D].shader_steps = 2;
this->pShader[SHADER_3D].pID = new int [this->pShader[SHADER_3D].shader_steps];

// Lade Shader

this->dycon_set_shader_id(SHADER_3D, 0, this->dycon_load_shader(SHADER_3D, "shader/vert_3d.glsl", GL_VERTEX_SHADER));
this->dycon_set_shader_id(SHADER_3D, 1, this->dycon_load_shader(SHADER_3D, "shader/frag_3d.glsl", GL_FRAGMENT_SHADER));

// an die GPU senden und auf use schalten

glLinkProgram(this->pShader[SHADER_3D].prog_id);

if((this->gl_err = glGetError()) == GL_NO_ERROR)
{
glGetProgramiv(this->pShader[SHADER_3D].prog_id, GL_LINK_STATUS, &param);

if((this->gl_err = glGetError()) == GL_NO_ERROR)
{
if(param == GL_TRUE)
{
#if EMODE == EDEBUG_MODE
this->dycon_write_log("<b>ENGINE:</b> glLinkProgram: OK", DB_MSG_OK);
#endif

glUseProgram(this->pShader[SHADER_3D].prog_id);

if((this->gl_err = glGetError()) == GL_NO_ERROR)
{
#if EMODE == EDEBUG_MODE
this->dycon_write_log("<b>ENGINE:</b> glUseProgram: OK", DB_MSG_OK);
#endif
}
else
{
exit_code = ERR_EN_USE_PROG;

#if EMODE == EDEBUG_MODE
sprintf(pBuffer, "<b>ENGINE:</b> glUseProgram() failed --end GL Flag: %d --end OpenGL Error: %s --end", this->gl_err, glewGetErrorString(this->gl_err));
this->dycon_write_log(pBuffer, DB_MSG_ERR);
#endif
}
}
else
{
exit_code = ERR_EN_LINK_PROG;

#if EMODE == EDEBUG_MODE
glGetProgramInfoLog(this->pShader[SHADER_3D].prog_id, SIZE_LOG, &length_log, compile_log);
sprintf(pBuffer, "<b>ENGINE:</b> failed to link shader program: %s --end", compile_log);
this->dycon_write_log(pBuffer, DB_MSG_ERR);
#endif
}
}
else
{
exit_code = ERR_EN_CHECKLINK_PROG;

#if EMODE == EDEBUG_MODE
sprintf(pBuffer, "<b>ENGINE:</b> glGetProgramiv() failed --end GL Flag: %d --end OpenGL Error: %s --end", this->gl_err, glewGetErrorString(this->gl_err));
this->dycon_write_log(pBuffer, DB_MSG_ERR);
#endif
}
}
else
{
exit_code = ERR_EN_LINK_PROG;

#if EMODE == EDEBUG_MODE
sprintf(pBuffer, "<b>ENGINE:</b> glLinkProgram() failed --end OpenGL Error: %s --end", glewGetErrorString(this->gl_err));
this->dycon_write_log(pBuffer, DB_MSG_ERR);
#endif
}
}
else
{
exit_code = ERR_EN_SHADER_PROG;

#if EMODE == EDEBUG_MODE
sprintf(pBuffer, "<b>ENGINE:</b> glCreateProgram() failed --end OpenGL Error: %s --end", glewGetErrorString(glGetError()));
this->dycon_write_log(pBuffer, DB_MSG_ERR);
#endif
}

// MORE SHADER PROGRAMS TO BUILD ...
}


This would be the html output:



init_engine()
ENGINE: SDL2 initialisiert...
ENGINE: set_ogl_attr(): OK
ENGINE: SDL2 Fenster initialisiert...
ENGINE: OpenGL initialisiert...
ENGINE: --------------- Shader 3D ---------------
ENGINE: glCreateProgram: OK
ENGINE: read_file: "shader/vert_3d.glsl" OK
ENGINE: glCreateShader: OK
ENGINE: glShaderSource: OK
ENGINE: glCompileShader: OK
ENGINE: glAttachShader: OK
ENGINE: read_file: "shader/frag_3d.glsl" OK
ENGINE: glCreateShader: OK
ENGINE: glShaderSource: OK
ENGINE: glCompileShader: OK
ENGINE: glAttachShader: OK
ENGINE: failed to link shader program:
Fragment info -------------
Internal error: assembly compile error for fragment shader at offset 1350:
-- error message --
line 35, column 36: error: invalid local parameter number
line 58, column 18: error: out of bounds array access
line 64, column 24: error: out of bounds array access
line 68, column 23: error: offset for relative array access outside supported range
line 73, column 23: error: offset for relative array access outside supported range
line 77, column 38: error: out of bounds array access
line 95, column 25: error: offset for relative array access outside supported range
line 99, column 25: error: offset for relative array access outside supported range
line 103, column 25: error: offset for relative array access outside supported range
line 105, column 21: error: out of bounds array access
line 116, column 46: error: offset for relative array access outside supported range
line 127, column 25: error: offset for relative array access outside supported range
line 131, column 25: error: offset for relative array access outside supported range
line 136, col --end
...


error ouput stops after 900 chars, so there would even be more errors to handle...
the weird thing: at some lines / columns mentioned there isn't even code at all. There is nothing there, that could have an error in this code. (guessing it's the fragment shader)

So what I did find out after reading GLSL 1.3 specification:

- I used "inverse" function in the vertex shader, which doesn't exist in v1.3, so removed it
- f suffix for floating point numbers would be legal! but i removed them anyway
- I had a float typed variable called "distance". But "distance" is also a function name. So I changed it to "dist"
- still not sure: specification doesn't mention a "must have" of a default section in the switch instruction
- still not sure: specification doesn't mention a "must have" of an else section when using an if instruction
- not sure: there is a "must have" for vertex shaders to use gl_Position, but nothing is mentioned for the fragment shader, so I guess having an out color variable would do it?

All the other functions used in vertex and fragment shader do exist! I couldn't spot any invalid use of datatypes, function calls or struct definitions. But it's good to hear, that it should work, if I would manage to use legal GLSL code.

As mentioned: error output doesn't make any sense to me.
And ignoring error output in the linking stage, can't be the right thing (even assuming, drivers may be bugged). Well I tried it anyway. Linking would work then, but (of course) glUseProgram wouldn't.
So any further guesses? Thanks for your time.

GClements
08-10-2016, 11:41 AM
uniform En_Light light[100]; // Lichtstruktur / maximal 100 Lichtquellen!


The En_Light structure has at least 20 components (assuming no padding), so light[] has at least 2000 components. But GL_MAX_FRAGMENT_UNIFORM_COMPONENTS isn't required to be any higher than 1024 in OpenGL 4 (or any higher than 64 in OpenGL 2.1).

Either make the light[] array significantly smaller or use a named uniform block backed by a UBO (the latter option requires OpenGL 3 or later or the ARB_uniform_buffer_object extension). Either way, you aren't going to get away with OpenGL 2.1 (the limit of 64 components would limit you to at most 2 lights, and UBOs aren't available) unless you use a texture for the light data.



As mentioned: error output doesn't make any sense to me.

The fact that it says


Internal error: assembly compile error for fragment shader at offset 1350:

suggests that the line numbers may correspond to GPU assembler rather than GLSL.

The remaining error messages look plausible if the error is indeed caused by having too many uniforms in the default uniform block.