6

I am using OpenGL 4.5 in C++ and GLSL 410.

I came across a problem recently where I was attempting to set a shader program's uniform variable without first using the shader program with glUseProgram. I had a fragment shader with a uniform variable called input_color (a vec4 which I would set the output color to) attached to my shader_program. Please note I do call glUseProgram(shader_program) in my main draw loop before drawing anything that should use it.

// set uniforms
GLint input_color = glGetUniformLocation(shader_program, "input_color");
glUniform4f(input_color, 0.5f, 0.3f, 0.2f, 1.0f);

A triangle drawn with this program was all black, not the result I was expecting. After some experimenting, I realized I needed to use the program before setting its uniforms.

// set uniforms
glUseProgram(shader_program); // my change
GLint input_color = glGetUniformLocation(shader_program, "input_color");
glUniform4f(input_color, 0.5f, 0.3f, 0.2f, 1.0f);

Drawing results in a triangle of the correct color.

My question is why did I need to start using the program first? I understand that OpenGL works as a state machine, but in this instance why is the current shader program state necessary? After all, I explicitly pass the shader_program index as a parameter to glGetUniformLocation in order to get input_color's memory index.

I'm hoping the answer to this will help me understand states in OpenGL better, and how blocks of memory representing shader programs on the GPU are utilized or managed.

Rob
  • 110
  • 2
  • 7
  • "*OpenGL 4.5 in C++ and GLSL 410.*" Why are you using 4.5 with GLSL 4.10? Can't you use GLSL 4.50? – Nicol Bolas Feb 21 '17 at 02:17
  • The guides I have been using are a little dated, so they specified 4.10. I will start using 4.50. – Rob Feb 21 '17 at 04:43

1 Answers1

8

You don't have to. GL 4.1 and above gives you glProgramUniform(), which takes the program object you want to modify.

genpfault
  • 51,148
  • 11
  • 85
  • 139
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 1
    Thanks - I did not know this option existed. Would it be correct to say then that `glUniform` only knows how to locate a program in memory by looking at the "in use" one, whereas `glProgramUniform` has the parameter for different program indices? – Rob Feb 21 '17 at 04:50
  • 2
    Yes, that's the whole point of "bind to use" or "bind to modify" approach that OpenGL has always (historically) had. Luckily OpenGL started to move away from it, in favor of functions which take which directly take the object to modify. This has been fully realized in OpenGL 4.5 with the adoption of the `ARB_direct_state_access` extension. See also https://www.khronos.org/opengl/wiki/Direct_State_Access – peppe Feb 21 '17 at 10:35
  • 1
    I am 3 years late but I'd still like to know the answer to the author's question, I understand that starting GL 4.1 and above to we don't have to use glUseProgram() before modifying a uniform, but the question still stands, why is it a required step for versions before GL 4.1? – A. Khaled Sep 27 '20 at 13:56
  • @A.Khaled: Because that's how the API was written. – Nicol Bolas Sep 27 '20 at 15:18
  • 2
    @A.Khaled 'use program' is like 'bind texture' here, it simply needs to be done before working on that opengl object – LegendLength Jun 12 '21 at 19:45