5
\$\begingroup\$

I'm just starting out with OpenGL on Linux. In order to write future-proof code, I explicitly wrote code for OpenGL 4.0 Core Profile in the first place, thus the shaders are GLSL 4.0.

That worked fine on a recent notebook with an AMD graphics card using the fglrx driver, which supports OpenGL 4.0. I then tried to run this code on another box with an Intel card, whose driver only supports OpenGL 2.1. That failed, obviously.

I then rewrote the shaders in GLSL 1.20, without changing the C++ code at all. Now it works on the Intel box, but on the AMD notebook, it displays nothing (except for glClearColor).

That confuses me. The code checks glGetError() periodically, so an error in the shader compilation would have been caught.

My only idea would have been that I accidentally created a GL 4 core context (instead of a compatibility context) on the AMD box, but the context is created by SDL 1.2, which (says the documentation) can create compatiblity contexts only.

Can anyone see what the problem is, or give hints on how to debug this? For reference, I'm attaching all shaders. (They're pretty trivial; as I said, I'm just starting.)

#version 120 (vertex shader)
uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;
attribute vec4 in_Color;
attribute vec4 in_Position;
varying vec4 pass_Color;
void main(void) {
    gl_Position = (ProjectionMatrix * ViewMatrix * ModelMatrix) * in_Position;
    pass_Color = in_Color;
}

#version 400 (vertex shader)
layout(location=0) in vec4 in_Position;
layout(location=1) in vec4 in_Color;
out vec4 ex_Color;
uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;
void main(void) {
    gl_Position = (ProjectionMatrix * ViewMatrix * ModelMatrix) * in_Position;
    ex_Color = in_Color;
}

#version 120 (fragment shader)
varying vec4 pass_Color;
void main(void) {
    gl_FragColor = pass_Color;
}

#version 400 (fragment shader)
in vec4 ex_Color;
out vec4 out_Color;
void main(void) {
    out_Color = ex_Color;
}
\$\endgroup\$
2
  • \$\begingroup\$ I just recall that, for some reason, I had to swap the in arguments in the 1.20 vertex shader (in_Color before in_Position instead of after it). I'm not near the AMD box at the moment, so I can't test what happens if I revert the swap, though. \$\endgroup\$ Jan 26, 2012 at 15:59
  • 1
    \$\begingroup\$ Shader compilation errors are not caught via glGetError. The OpenGL wiki has information on how to properly catch compilation errors. There's even a bit of example code for you to follow. \$\endgroup\$ Jan 26, 2012 at 16:20

1 Answer 1

5
\$\begingroup\$

You might need to bind your vertex attribute id's to your shader, look at glGetAttribLocation. In your 4.0.0 version you have the layout statement telling it what will be in what id's. The program needs to know that "in_Position" is for attribute 0. It's possible that your implementation will default to using the first attribute as vertex coordinates and the 2nd as color. But it might not either. I'm not sure what the standards say about the default states, it might be up to the implementation or vary depending on what version your context is.

Here's the code I use to get a log of the shaders/programs.

// For shaders
int length = 0;
glGetShaderiv(shader_id_, GL_INFO_LOG_LENGTH, &length);
std::vector<GLchar> shader_log(length);
glGetShaderInfoLog(shader_id_, length, &length, &shader_log.front());

// For programs
int length = 0;
glGetProgramiv(program_id_, GL_INFO_LOG_LENGTH, &length);
std::vector<GLchar> program_log(length);
glGetProgramInfoLog(program_id_, length, &length, &program_log.front());

If your trying to make stuff run on multiple OpenGL versions. I recommend that you make a class that deals with all your shaders in one place. That way you can just call shaders.usePhong(), shaders.setPrimaryColor(glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));

That will allow you to take advantage of things like:

  • Subroutine uniforms (there basically function pointers for GLSL so you can have 1 big shader that does everything without having to put a bunch of if statements that slow things down).

  • Uniform Buffer Objects (share data between all your shaders).

Having the central control object will allow you to fall back to the old ways of doing things. usePhong could either change which uniform subroutine is set or change which shader is in use depending on what is supported.

Setting variables could either update the shared buffer object for all shaders or set the uniform variable on the shader (although you have to keep track of which shader will need that variable and if you need to resend that stuff when you swap to a different shader.).

You can also look at using #include in your GLSL sharers. It's not in core yet but is an ARB extension so it works on at least nvidia (not sure about AMD). If you don't have it on the platform you can have your shader loading code do a quick search and insert the code manually, if you do have it then you need to load the files into OpenGL's "named strings" in advance. That way you can write 1 bit of shader code and #include it either inside a routine function or a separate shader.

You might even want to go further and write some code that will generate the correct shaders wrapping code for your supported extensions.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ glGetAttribLocation was the culprit. (Although the infolog is also useful and already included in my new ShaderProgram class.) \$\endgroup\$ Jan 27, 2012 at 22:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .