Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GLSL: How should i store and keep track of uniform/attribute locations?

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.

like image 660
Rookie Avatar asked Apr 06 '11 12:04

Rookie


2 Answers

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".
like image 91
kvark Avatar answered Sep 30 '22 15:09

kvark


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() );
}
like image 45
Rabbid76 Avatar answered Sep 30 '22 16:09

Rabbid76