3
votes

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?

2

2 Answers

7
votes

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.

4
votes

You have to set the index of the texture unit to sampler uniform (similar as setting the value of a uniform variable of type int). e.g. value 1 for GL_TEXTURE1.

See OpenGL 4.6 API Compatibility Profile Specification; 7.10 Samplers; page 154:

Samplers are special uniforms used in the OpenGL Shading Language to identify the texture object used for each texture lookup. The value of a sampler indicates the texture image unit being accessed. Setting a sampler’s value to i selects texture image unit number i.

e.g.

layout (location = 11) uniform sampler2D color;
layout (location = 12) uniform sampler2D tex;
layout (location = 13) uniform sampler2D norm;
glUniform1i(11, 0); // 0: GL_TEXTURE0
glUniform1i(12, 1); // 1: GL_TEXTURE1
glUniform1i(13, 2); // 2: GL_TEXTURE2

Since GLSL version 4.2 this can be done in the fragment shader by specifying binding points - See OpenGL Shading Language 4.20 Specification - 4.4.4 Opaque-Uniform Layout Qualifiers; page 60:

#version 420

layout (binding = 0) uniform sampler2D color;
layout (binding = 1) uniform sampler2D tex;
layout (binding = 2) uniform sampler2D norm;