Equinox2000
Equinox2000

Reputation: 576

GLSL rendering more textures than texture units available

Say if you have loaded a 3d model which has 25 textures, but you have a limit of 8 texture units. What is the most simplest / quickest way to render all the textures. I assume would be something like...

1) Load textures 2) bind texture texture to shader texture unit 3) render 4) loop to 2) until all textures rendered

I understand bind is a costly process so unsure if there is a better way or if my theory is correct...

Upvotes: 0

Views: 840

Answers (3)

Andon M. Coleman
Andon M. Coleman

Reputation: 43319

Since you are discussing glsl, I think it is worth pointing out that the number of Texture Image Units is actually separate from the number of discrete textures you can apply in a pass.

GL 3.3, for example, guarantees 48 TIUs (16 for each stage in the pipeline)... those 48 units allow you enough places to bind textures so that you can use a set of 16 different textures in your Vertex, Geometry and Fragment shaders. This does not, however, mean that you can sample 48 different textures in your fragment shader.

There is a per-stage limit to the number of textures you can sample in a shader invocation (16 minimum, and it may not be the same limit for each stage). There is also an aggregate limit that applies across every stage (48 minimum in GL 3.3). So, while you may be able to bind 48 different textures at any given time, you would still have to split your draw into 3 passes to actually apply all 48.

Upvotes: 1

derhass
derhass

Reputation: 45322

This answer is meant as a side note to Reto Koradi's answer, and I think his answer is more relevant. However, I want to add that with really modern GPUs, there is GL_ARB_bindless_texture which allows you to use as much textures as you can fit into the memory, completelly bypassing any of the GL "texture units".

Currently, this extension is not part of core OpenGL, and it is supported only on NVidia GPUs since the "Kepler" architceture and on AMD GPUs since the "Graphics Core Next" architecture.

Upvotes: 1

Reto Koradi
Reto Koradi

Reputation: 54572

If all (or at least some) of your textures have the same size, you can use array textures. You create them with:

glTexImage3D(GL_TEXTURE_2D_ARRAY, ...);

Where the depth argument would go for a 3D texture, you pass in the number of textures in your array (aka "layers"), and as always NULL for the last argument if you only want to allocate the memory. If you use OpenGL 4.2 or newer, you can also use glTexStorage3D() to allocate the texture memory.

You can then use glTexSubImage3D(GL_TEXTURE_2D_ARRAY, ...) to store the data for each of your textures in the array.

In your shader, you use variables of type sampler2DArray for array textures, and sample them with 3 texture coordinates, where the 3rd "coordinate" determines which layer is sampled, corresponding to the index into your array.

An entirely different approach that is sometimes employed is to use larger 2D textures, and store each of your actual textures as part of this larger texture. You can then control which of your textures is sampled by using the corresponding range of texture coordinates. Say if you had stored 4 textures of the same size in a single texture with twice the width and height, you would sample your first texture with texture coordinates in the range (0 .. 0.5, 0.0 .. 0.5), the second texture with (0.0 .. 0.5, 0.5 .. 1.0), the third with (0.5 .. 1.0, 0.0 .. 0.5), and the forth with (0.5 .. 1.0, 0.5 .. 1.0). This method is often called a "texture atlas".

Upvotes: 4

Related Questions