GLSL – Variable Qualifiers

Variable Qualifiers

Qualifiers give a special meaning to the variable. The following qualifiers are available:

  • const – The declaration is of a compile time constant.
  • attribute – Global variables that may change per vertex, that are passed from the OpenGL application to vertex shaders. This qualifier can only be used in vertex shaders. For the shader this is a read-only variable. See Attribute section.
  • uniform – Global variables that may change per primitive […], that are passed from the OpenGL application to the shaders. This qualifier can be used in both vertex and fragment shaders. For the shaders this is a read-only variable. See Uniform section.
  • varying – used for interpolated data between a vertex shader and a fragment shader. Available for writing in the vertex shader, and read-only in a fragment shader. See Varying section.
  • uniform are per-primitive parameters (constant during an entire draw call) ;
  • attribute are per-vertex parameters (typically : positions, normals, colors, UVs, …) ;
  • varying are per-fragment (or per-pixel) parameters : they vary from pixels to pixels.

Understanding the mecanism of varying is necessary to shader programming.
Imagine you define a varying parameter v for each vertex of a triangle inside the vertex shader. When the varying parameter arrives in the fragment shader, it would be interpolated through bilinear interpolation based on the pixel to draw.

In the following image, the red pixel received an interpolated value of the varying parameter v. That’s why we call them “varying”.

 

Variables shared between both examples:

GLint i;
GLint count;

GLint size; // size of the variable
GLenum type; // type of the variable (float, vec3 or mat4, etc)

const GLsizei bufSize = 16; // maximum name length
GLchar name[bufSize]; // variable name in GLSL
GLsizei length; // name length

Attributes

glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &count);
printf("Active Attributes: %d\n", count);

for (i = 0; i < count; i++)
{
    glGetActiveAttrib(program, (GLuint)i, bufSize, &length, &size, &type, name);

    printf("Attribute #%d Type: %u Name: %s\n", i, type, name);
}

Uniforms

glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &count);
printf("Active Uniforms: %d\n", count);

for (i = 0; i < count; i++)
{
    glGetActiveUniform(program, (GLuint)i, bufSize, &length, &size, &type, name);

    printf("Uniform #%d Type: %u Name: %s\n", i, type, name);
}

OpenGL Documentation / Variable Types

The various macros representing variable types can be found in the docs. Such as GL_FLOAT, GL_FLOAT_VEC3, GL_FLOAT_MAT4, etc.

 

New way

This way lets you access pretty much everything about active variables in a successfully linked program (except for regular globals). The ARB_program_interface_query extension is not widely available yet, but it’ll get there.

It starts with a call to glGetProgramInterfaceiv, to query the number of active attributes/uniforms. Or whatever else you may want.

GLint numActiveAttribs = 0;
GLint numActiveUniforms = 0;
glGetProgramInterfaceiv(prog, GL_PROGRAM_INPUT, GL_ACTIVE_RESOURCES, &numActiveAttribs);
glGetProgramInterfaceiv(prog, GL_UNIFORM, GL_ACTIVE_RESOURCES, &numActiveUniforms);

Attributes are just vertex shader inputs; GL_PROGRAM_INPUT means the inputs to the first program in the program object.

You can then loop over the number of active resources, asking for info on each one in turn, from glGetProgramResourceiv and glGetProgramResourceName:

std::vector<GLchar> nameData(256);
std::vector<GLenum> properties;
properties.push_back(GL_NAME_LENGTH​);
properties.push_back(GL_TYPE​);
properties.push_back(GL_ARRAY_SIZE​);
std::vector<GLint> values(properties.size());
for(int attrib = 0; attrib < numActiveAttribs; ++attrib)
{
  glGetProgramResourceiv(prog, GL_PROGRAM_INPUT, attrib, properties.size(),
    &properties[0], values.size(), NULL, &values[0]);

  nameData.resize(values[0]); //The length of the name.
  glGetProgramResourceName(prog, GL_PROGRAM_INPUT, attrib, nameData.size(), NULL, &nameData[0]);
  std::string name((char*)&nameData[0], nameData.size() - 1);
}

The exact same code would work for GL_UNIFORM; just swap numActiveAttribs with numActiveUniforms.