Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenGL Texture binding between glUseProgram

I am implementing an engine in OpenGL ES 2.0 on Android. I have multiple shaders, objects can take multiple textures.

My goal is to minimize texture binding calls to OpenGL, so I keep a list of currently bound textures for each shader, and only call glBindTexture(), if the texture changes.

For example I have a skybox shader, and I only draw a single object (skybox cube) with it, then this shader will only need one texture bind in its lifetime.

And when I draw multiple objects with the same texture, there could be gains as well.

My symptom is that if I do not rebind the skybox texture before drawing it, a different (previously drawn) object's texture is used on a skybox. This previously drawn object uses a different shader.

So is it wrong to assume, that texture binding are restored when I use a shader program again?

ps.: I use a single 2d texture for the skybox, not a cubemap.

like image 471
agnu17 Avatar asked Nov 27 '25 22:11

agnu17


1 Answers

Yes, assuming that texture bindings are restored when you use a given shader program would be wrong.

Texture binding state is completely independent from the current shader program. There is one currently bound texture per texture unit and target. Say if you execute the following code sequence:

glActiveTexture(GL_TEXTURE7);
glBindTexture(GL_TEXTURE_2D, myTexId);

you're binding the texture with id myTexId to the 2D target of texture unit 7. This state will remain until you bind a different texture to the 2D target of unit 7 (or delete the texture), completely independent of what shader program is active.

The relationship between textures and shader programs is established by setting the value of the sampler uniform variables of the program to the texture unit. Continuing with the example above, you specify that a given program should use this texture by:

// needed only once after linking the program
GLint texLoc = glGetUniformLocation(myProgId, "MySampler");

// use the texture bound to unit 7
glUseProgram(myProgId);
glUniform1i(texLoc, 7);

Based on this, if you want to avoid making redundant calls for texture binding, you would have to keep track of what texture is bound to which unit. This information needs to be maintained "globally", i.e. independent of specific shader programs.

Note that the uniform values are per program, so you do not have to set the value again after binding a specific program, unless you want it to sample from a texture bound to a different unit.

One thing you can potentially do to reduce the number of times you need to bind different textures is to use different texture units for each shader. As a simplified example, picture a situation where each program uses a single texture, and uses the same texture every time the program is used. You could then set a different value for the sampler uniform of each program, and bind the texture that each program uses to the corresponding texture unit. Each program will then use the corresponding texture whenever you call glUseProgram(), without any calls to glBindTexture().

Of course this gets a little more complex when programs use multiple textures, and you do want to switch textures for a specific program. But if you manage the texture units in a clever way, you might still be able to greatly reduce the number of texture bind operations. While doing that, keep in mind that the number of texture units is limited. The limit can be queried with:

glGetIntegerv(MAX_TEXTURE_IMAGE_UNITS, ...);

The limit can be as low as 8 for ES 2.0.

Or, looking at the same thing from a different angle: If you use fewer textures than the number of available texture units, you can bind each texture to a different texture unit once, and be done with texture binding. You then control which texture is used by each shader at any given time by setting their sampler uniforms to the texture units that have the desired textures bound.

In reality, you will most likely use a hybrid of these approaches if your app is somewhat complex. For example, you might keep a few frequently used textures constantly bound to a fixed texture unit, while you rebind other textures when necessary.

Since this might all sound more complicated than it really is, let me summarize the relationships:

  • Each program has its own set of uniform values.
  • glUniform1i(), called while a specific program is active, establishes a relationship between the shader program and a texture unit.
  • glBindTexture() establishes a relationship between texture unit and texture object.

So the texture units provide a level of indirection between program and texture object, which explains why texture binding state is not directly part of a specific program.

like image 52
Reto Koradi Avatar answered Dec 01 '25 14:12

Reto Koradi