when to use glActiveTexture?

In the book OpenGL programming guide, Example 9-7 uses two texture objects and it does not call glActiveTexture before calling glBindTexture, while in Example 9-10, it calls glActiveTexture before glBindTexture. What’s the difference?

what’s the difference between glActiveTexture and glBindTexture? It seems they both can activate a texture.

Imagine that OpenGL internally looks like this:


struct TextureUnit
{
    GLuint targetTexture1D;
    GLuint targetTexture2D;
    GLuint targetTexture3D;
    GLuint targetTextureCube;
    ...
};

TextureUnit textureUnits[GL_MAX_TEXTURE_IMAGE_UNITS]
GLuint currentTextureUnit = 0;

glActiveTexture means this:


void glActiveTexture(GLenum textureUnit)
{
    currentTextureUnit = GL_TEXTURE0 - textureUnit;
}

And glBindTexture does this:


void glBindTexture(GLenum textureTarget, GLuint textureObject)
{
    TextureUnit *texUnit = &textureUnits[currentTextureUnit];
    switch(textureTarget)
    {
    case GL_TEXTURE_1D: texUnit->targetTexture1D = textureObject; break;
    case GL_TEXTURE_2D: texUnit->targetTexture2D = textureObject; break;
    case GL_TEXTURE_3D: texUnit->targetTexture3D = textureObject; break;
    case GL_TEXTURE_CUBEMAP: texUnit->targetTextureCube = textureObject; break;
    }
}

Obviously there would be error testing, but that’s the idea. All of the functions that modify the texture use the “currentTextureUnit” set by glActiveTexture. The target parameter they take tells which bound texture location within that texture unit to use.

So if you have:


glActiveTexture(GL_TEXTURE0 + 5);
glBindTexture(GL_TEXTURE_2D, object);
glTexImage2D(GL_TEXTURE_2D, ...);

The texture being uploaded to is the one stored in textureUnits[5]->targetTexture2D. Each texture that you bind has a texture target and a texture unit; this specifies its unique location in the context.

I don’t have that particular book, but one often binds a texture to the context just to upload some data or to modify it. It doesn’t matter at that point which texture unit you bind it to, so there’s no need to set the current texture unit. glTexImage2D doesn’t care if the current active texture is 0, 1, 40, or whatever.

However, texture units have special meaning to the rendering of objects. When you bind textures for the purpose of rendering with them, you need to bind them to a particular texture unit. Therefore, you need to set the current texture unit before you do the bind.

Great explanation, Alfonse!

Example 9-10 is not complete; maybe that why you are confused. Think in this way: If there is a need for several textures used simultaneously, then glActiveTexture() must be applied in order to setup each texture unit (see previous Alfonse’s post). If you need just one texture at a time, only one unit (usually 0) is used.

Be aware that the number of texture units is limited. On mobile devices there are usually only two. On desktop systems it should be at least 8.

You got some good answers already. I’ll just add one thing to that. glActiveTexture selects the active texture unit, and glBindTexture binds a texture to the active texture unit. So you see they work together hand-in-hand.

Rather than use a behind-the-scenes “active texture unit” selector to help define what BindTexture does, GL could have put the arguments to both APIs in one single stand-alone GL call. And this in-fact is what’s done in the EXT_direct_state_access function glBindMultiTextureEXT:


void BindMultiTextureEXT(enum texunit, enum target, uint texture);

which does exactly what we just discussed. You tell it which “texture” you want to bind, what its texture type is (target), and which “texture unit” you want to bind it to. It’s all right there without any behind-the-scenes selectors.

Similar APIs are defined by this extension for many other texture calls, and many other calls besides.

If you don’t call glActiveTexture, then it uses the default, which is 0 (GL_TEXTURE0).

If you need to bind a texture to another tex unit, then you need glActiveTexture.

Despite the name, glActiveTexture does not activate a texture unit. I really don’t know why they didn’t just create that glBindMultiTexture function in GL 1.2.1

There was this “let’s not modify old GL functions and just introduce another one” attitude back then. Got to live with it now.

Be aware that the number of texture units is limited. On mobile devices there are usually only two. On desktop systems it should be at least 8.

The GLES2 standard requires atleast 8 texture units, not too sure what GLES1 requires though. As a side note, the N900 which uses a PowerVR SGX supports just that: 8 texture units. The SGX in the N900 is by today’s standards pretty low on the totem pole, and newer devices are typically faster than the SGX in the N900 (bit often enough SGX’s as well, but higher clock and higher “model number”).

Be aware that the number of texture units is limited. On mobile devices there are usually only two. On desktop systems it should be at least 8.

I have a NVIDIA GeForce GTS 450 graphics card. I use glGetIntegerv(GL_MAX_TEXTURE_UNITS, …) in my c++ program and only get 4 texture units. It is really strange.

There is an app for that
http://www.opengl.org/wiki/Common_Mistakes#Texture_Unit

Thank you very much.

The OpenGL Programming Guide is a little misleading.

The Red book is excellent for the fixed functionality, but gives little to no clues about what is going on in the programmable pipeline. On the other hand, Wiki is oversimplified.

You have six different constants that define how many sampler object you can use:

  • GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
  • GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS,
  • GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS,
  • GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS,
  • GL_MAX_TEXTURE_IMAGE_UNITS and
  • GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS.

Each of the first 5 defines the maximal number of texture image units in particular programmable pipeline stage. The last one defines the total number of texture image units that can be used simultaneously in all stages. Theoretically MAX_COMBINED can be the sum of all others, but in practice that number could be smaller since texture units might be shared.

On the other hand, Wiki is oversimplified.

Then fix the Wiki. It’s a wiki for a reason.

See? It’s better now.

Yes, it’s better now. :wink:

Isn’t it still oversimplified?

Should i use GL_MAX_TEXTURE_IMAGE_UNITS or GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS?

What if my name is mr joe the programmer and my Intel supports GL 2.0. Will GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS works or will I get INVALID_ENUM?

I wouldn’t even dare to use OpenGL 2.0+ on Intel’s graphics cards. :smiley:
(Although Intel HD Graphics 2000/3000 should be GL 3.0 compliant, I haven’t tried it yet.)

If something is not supported in the drivers you will certainly get invalid enumeration error if you call it. The problem is that drivers shouldn’t return such severe error if enumeration is not supported, and furthermore debug output indicates error in totally wrong location (R266.58 for Win7/Vista 32-bit notebook version).

Hint: Try to get GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS on SM4 card.

Isn’t it still oversimplified?

It’s not a dissertation; it’s a “Common Mistakes” question. Hence the linking to other pages where more detailed information can be found.

In his awesome answer by @Alfonse_Reinheart has given code for glBindTexture() and has mentioned that functions like glTexImage() don’t care what the active texture unit is. But, when we use multiple textures, and use glGenTexture(…); glBindTexture(…);glTextureParameter(…);//some more code glBindTexture(…);glTextureParameter(…); won’t binding two different texture units override what they have written? Since the default texture unit is provided, they all would upload data to the same texture unit, isn’t it?

Texture parameters are stored in the texture object, not the texture unit. So when you call glBindTexture followed by glTexParameter, the glTexParameter call modifies the state of the texture which you’ve just bound to that texture unit. If you then bind a different texture to that texture unit and call glTexParameter, it will modify the state of the second texture; the first texture will retain the state it had when it was unbound.

A texture unit is nothing more than a collection of references to actual textures. Its state consists entirely of the textures which are bound to each target plus (since 3.3) any sampler bound to the texture unit (sampler objects allow sampling state to be stored separately from a texture). With OpenGL 4.5 or the ARB_direct_state_access extension, textures can be created and modified without binding them to a texture unit (via glTextureStorage*, glTextureSubImage*, glTextureParameter*). With the ARB_bindless_texture extension (not in any core version), textures can be used without binding them to a texture unit.

1 Like

They do use the current texture unit. However, they shouldn’t be called in a place where the current texture unit should be changing.

1 Like