Objects, units and samplers

Texture units & objects

Three different things get called "the texture" and they are not the same. A texture object holds the image data. A texture unit is the piece of hardware that samples it. A sampler variable in your shader holds neither — it holds the number of a unit. Rewire the middle column and watch what follows.

The binding chain left to right: data → hardware → shader → pixels

Texture objects

The image data itself, plus its filter and wrap settings. Created once, lives in GPU memory, referenced by a name.

Texture units

The samplers in silicon. Each one has a texture object bound to it — or nothing. Pick what is bound where.

Sampler uniforms

Variables in the fragment shader. The value of a sampler2D is an integer: which unit to ask.

Result

What each sampler actually returns when the fragment shader calls texture2D.

The calls that produced this state live

    
What just happened

Try this. Point both samplers at the same unit, then change what that unit has bound. Both quads change at once — because neither sampler ever referred to a texture object, only to a unit number. That indirection is the entire design: a shader is compiled once and can be pointed at different images every frame without recompiling.

Why glUniform1i and not glUniform1p. The most common mistake with multitexturing is passing the texture object's name to the sampler uniform — glUniform1i(loc, textureName) instead of glUniform1i(loc, unitNumber). It often even appears to work, because the first texture you create tends to get name 1 and unit 1 usually has something plausible bound to it. Press Show the classic bug above to see the failure mode: the shader samples a unit nobody set up, and you get black, or worse, whatever the last draw call left behind.