Search code examples
openglglslshader

Correspondance between texture units and sampler uniforms in opengl


The correspondence between sampler uniforms and texture units used by glActiveTexture apparently can't be queried with opengl, and I can't find good documentation on how to find which texture unit is mapped to which sampler uniform. Here is what I have been able to find:

  • If there is only sampler uniform in a program, then it is mapped to gl_TEXTURE0
  • If there are multiple sampler uniforms in a single program stage, then they are mapped in the order they are declared in the shader.
  • If the vertex and fragment shaders have disjoint sets of sampler uniforms, then the samplers in the vertex shader come first and are followed by the samplers in the fragment shader.
  • This behavior appears to be defined by the specification.

So for example if the vertex shader defines:

uniform sampler2D color;

And the fragment shader defines:

uniform sampler2D tex;
uniform sampler2D norm;

Then color gets mapped to gl_TEXTURE0, tex gets mapped to gl_TEXTURE1, and norm gets mapped to gl_TEXTURE2. But if instead the vertex shader defines:

uniform sampler2D norm;

Then it is not clear how the different textures get mapped. This is additionally complicated by the possibility of having layout qualifiers or separate shader stages.

I can't seem to find documentation on this anywhere. Everything I know about it either comes from my own experimentation or answers on Stackoverflow or the OpenGL forum. Does anyone know of a comprehensive set of rules for how this works in all possible cases, or a way to query the texture unit that a sampler corresponds to?


Solution

  • Here is what I have been able to find:

    • If there is only sampler uniform in a program, then it is mapped to gl_TEXTURE0
    • If there are multiple sampler uniforms in a single program stage, then they are mapped in the order they are declared in the shader.
    • If the vertex and fragment shaders have disjoint sets of sampler uniforms, then the samplers in the vertex shader come first and are followed by the samplers in the fragment shader.
    • This behavior appears to be defined by the specification.

    None of this is true. OK, the first one is true, but only by accident.

    All uniform values which are not initialized in the shader are initialized to the value 0. The spec makes this quite clear:

    Any uniform sampler or image variable declared without a binding qualifier is initially bound to unit zero.

    A sampler uniform's value is the integer index of the texture unit it represents. So a value of 0 corresponds to GL_TEXTURE0. All uninitialized sampler uniforms should have a value of 0.

    If the behavior you describe is happening, then that implementation is in violation of the OpenGL specification.

    Unless you use the layout(binding = ) syntax to assign a uniform's texture unit, you must manually in your OpenGL code assign each sampler uniform a value for its texture unit. This is done by setting its uniform value, just like any other integer uniform: you call glUniform1i with the location corresponding to that uniform. So if you want to associate it with texture image unit index 4, you call glUniform1i(..., 4), where ... is the uniform location for that uniform.