11

At the moment i just do:

someuniform1 = glGetUniformLocation(MyShaderName, "someuniform1");
someattribute1 = glGetAttribLocation(MyShaderName, "someattribute1");

But this method seems annoyingly repetitive, so i thought of using std::map:

Shaders[MyShaderName].Uniforms["someuniform1"] = glGetUniformLocation(MyShaderName, "someuniform1");
Shaders[MyShaderName].Attributes["someattribute1"] = glGetAttribLocation(MyShaderName, "someattribute1");
// i could add a function to remove the repetition of the two strings at both sides.

Is there any smarter/faster way of doing this? (to reduce repetition as much as possible).

--

Edit: I was thinking more about this idea, and i thought, wouldnt it be great if i just read the glsl source files, parse the uniform/attributes and set to my map automatically, without me need to write anything else than the glsl source!? Is this how the big boys do it?

Edit2: I am now parsing the GLSL shader files successfully, and using the std::map method, i use single function call with one string param to get the address for uniforms/attributes at current enabled shader. in case i need more performance, i will cache the std::map calls to other variables. But i would like to know if i am on the right track here... so please, any comments appreciated.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Rookie
  • 1,242
  • 3
  • 17
  • 22
  • 1
    For attributes, it makes sense (and is conceptually easier too, in my opinion) to use _explicit_ locations (and not only explicit, but explicit and fixed) rather than querying them, as explained here: http://stackoverflow.com/questions/4635913/explicit-vs-automatic-attribute-location-binding-for-opengl-shaders/4638906#4638906 – Damon Apr 06 '11 at 17:24
  • @Damon, does it matter for opengl? or is this just a style preference for programmers? – Rookie Apr 07 '11 at 12:51
  • 1
    OpenGL doesn't really care, but your life will be a lot happier. Your code is easier, cleaner, and needs fewer instructions and state changes. – Damon Apr 07 '11 at 13:22
  • @Damon, i dont understand... why does my code get easier? and cleaner? i already send uniform this easily: `glUniform1f(getu("myvar"), sentval);` how can that be made any easier? also i dont understand this: `and needs fewer instructions and state changes` ? could you perhaps post the code that makes my code faster? and what does it use if not std::map? – Rookie Apr 07 '11 at 14:11
  • I was referring to attributes, as explained by Kos in his answer. Using explicit locations means that you have the same locations application-wide (could use an enum to identify each one) and different shaders with different inputs can use the same VAO. Which means you save binding a different VAO when switching shaders. This is less work and less state changes. Somewhat similarly, uniform blocks+UBOs could make your life easier. In principle, you could have a struct that has the same layout as your uniform block and do a binary copy into the buffer object (instead of figuring out each one). – Damon Apr 07 '11 at 15:10

2 Answers2

6

Enumerate shader program's uniforms by GetActiveUniform, then store them in your map.

Edit: The purpose.

  1. No repetition in code. Uniform names as constants appear only in places where you want to access them.
  2. Early-stage semantics mismatches checks. When you gather information from GL about uniforms you know exactly what type of values it expects. So when the actual value is passed, you can check whether the client supplied a correct type/size of the value. These checks may save you a lot of time of debugging in case of some edge scenario when OpenGL driver decides to be "smart".
kvark
  • 5,291
  • 2
  • 24
  • 33
  • 3
    Why? dont just tell what to use as an answer, "why should i use" should also be the answer. i have no clue how does that function differ from glGetUniformLocation() and i have never seen it before. – Rookie Apr 07 '11 at 12:05
  • @Rookie. You can see it in OpenGL ES 2.0 official specification. This function will allow you to get all information from GL about the uniform (in particular: name, size, type). Then you'll still have to use `glGetUniformLocation` to get an entry point. – kvark Apr 07 '11 at 13:10
  • 1
    why do i need that information? it works fine without it.. i dont see the point, could you explain why do i need this? – Rookie Apr 07 '11 at 14:07
1

glGetProgramiv, glGetActiveUniform and glGetActiveAttrib can be used to get information about the used uniforms in a shader program. The information can be retrieved at any time after the program has been linked, glLinkProgram:

  • glGetProgramiv( MyShaderName, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxUniformNameLen ) returns the length of the longest active uniform variable name (including the null termination character)

  • glGetProgramiv( MyShaderName, GL_ACTIVE_UNIFORMS, &noOfUniforms ) returns the number of active uniform variables.

  • glGetActiveUniform returns information about an active uniform variable inclluding the name of the uniform.

  • glGetProgramiv( MyShaderName, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttribNameLen ) returns the length of the longest vetex attribute name (including the null termination character)

  • glGetProgramiv( MyShaderName, GL_ACTIVE_ATTRIBUTES, &noOfAttributes ) returns the number of the active attributes.

  • glGetActiveAttrib returns information about an active vetrtex attribute inclluding the name of the attribute.

Use the information from the functions above to find all uniform and attribute names within a program. Ask each uniform for its location and each attribute for its index, by their names. See the code snippet below:

GLint maxUniformNameLen, noOfUniforms;
glGetProgramiv( MyShaderName, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformNameLen );
glGetProgramiv( MyShaderName, GL_ACTIVE_UNIFORMS, &noOfUniforms );

GLint maxAttribNameLen, noOfAttributes;
glGetProgramiv( MyShaderName, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttribNameLen );
glGetProgramiv( MyShaderName, GL_ACTIVE_ATTRIBUTES, &noOfAttributes );

GLint read, size;
GLenum type;

std::vector< GLchar >unifN( maxUniformNameLen, 0 );
for ( GLint i = 0; i < noOfUniforms; ++ i )
{
    glGetActiveUniform(Object(), i, maxUniformNameLen, &read, &size, &type, unifN.data());
    Shaders[ MyShaderName ].Uniforms[ unifN.data() ] =
        glGetUniformLocation( MyShaderName, unifN.data() );
}

std::vector< GLchar >attrN( maxAttribNameLen, 0 );
for ( GLint i = 0; i < noOfAttributes; ++ i )
{
    glGetActiveAttrib(Object(), i, maxAttribNameLen, &read, &size, &type, attrN.data());
    Shaders[ MyShaderName ].Attributes[ attrN.data() ] =
        glGetAttribLocation( MyShaderName, attrN.data() );
}
Rabbid76
  • 202,892
  • 27
  • 131
  • 174