opengl reuse texture unit - opengl

according to the https://www.opengl.org/wiki/Texture, "if two different GLSL samplers have different texture types, but are associated with the same texture image unit, then rendering will fail. Give each sampler a different texture image unit."
but the glactivetexture use enum to iterate texture unit. How to make sure the texture unit is associate with correct target when i want to reuse the unit. for example use unit 2 for 2D first, and then want reuse it for 3D. I have tried glBindTexture(GL_TEXTURE_1D/2D/3D, 0); but seems not work. Should i use glenable?

You have misinterpreted what this statement on the OpenGL Wiki means.
It is referring to sampler uniforms in GLSL. It is an error to have a sampler2D and samplerCube, for instance, that both reference the same texture image unit. Since this situation cannot be determined at compile- / link-time, there is no error state that will be generated. Instead, you will create undefined behavior at shader run-time if you try to use two different types of samplers that refer to the same texture image unit.
Regarding enabling GL_TEXTURE_1D, etc. That is for the fixed-function pipeline. It does nothing in shader-based OpenGL, textures are effectively "enabled" or "disabled" completely programatically. If you do not sample anything from a certain texture image unit during the execution of your shader, then you can think of it as "disabled." However, ultimately such thinking is not productive in the programmable pipeline. You should simply forget that those states ever existed.

Related

OpenGL Texture Usage

So recently I started reading through OpenGL wiki articles. This is how I picture OpenGL texturing described from here. Though, several points are not clear yet.
Will following statements be true, false or depends?
Binding two textures to same texture unit is impossible.
Binding two samplers to same texture unit is impossible.
Binding one texture to two different texture units is impossible.
Binding one sampler to two different texture units is impossible.
It is application's responsibility to be clear about what sampler type is passed to what uniform variable.
It is shader program's responsibility to make sure to take sampler as correct type of uniform variable.
number of texture units are large enough. Let each mesh loaded to application occupy as much texture unit as it please.
Some Sampler parameters are duplicate of texture parameters. They will override texture parameter setting.
Some Sampler parameters are duplicate of sampler description in shader program. Shader program's description will override samplers parameters.
I'm going through your statements in the following. Sometimes I will argue with quotes from the OpenGL 4.5 core profile specification. None of that is specific to GL 4.5, I just chose it because that is the most recent version.
1. Binding two textures to same texture unit is
impossible.
If I'd say "false", it would be probably misleading. The exact statement would be "Binding two textures to the same target of the same texture unit is impossible." Technically, you can say, bind a 2D texture and a 3D texture to the same unit. But you cannot use both in the same draw call. Note that this is a dynamic error condition which depends on what values you set the sampler uniforms to. Quote from section 7.10 "Samplers" of the GL spec:
It is not allowed to have variables of different sampler types
pointing to the same texture image unit within a program object. This
situation can only be detected at the next rendering command issued
which triggers shader invocations, and an INVALID_OPERATION error will
then be generated.
So the GL will detect this error condition as soon as you actually try to draw something (or otherwise trigger shader invocations) with that shaders while you configured it such that two sampler uniforms reference different targets of the same unit. But it is not an error before. If you temporarily set both uniforms to the same value but do not try to draw in that state, no error is ever generated.
2. Binding two samplers to same texture unit is impossible.
You probably mean Sampler Objects (as opposed to just "sampler" types in GLSL), so this is true.
3. Binding one texture to two different texture units is impossible.
False. You can bind the same texture object to as many units as there are available. However, that is quite a useless operation. Back in the days of the fixed-function pipeline, there were some corner cases where this was of limited use. For example, I've saw someone binding the same texture twice and use register combiners to multiply both together, because he needed some square operation. However, with shaders, you can sample the texture once and do anything you want with the result, so there is really no use case left for this.
4. Binding one sampler to two different texture units is impossible.
False. A single sampler object can be referenced by multiple texture units. You can just create a sampler object for each sampling state you need, no need to create redundant ones.
5. It is application's responsibility to be clear about what sampler type is passed to what uniform variable.
6. It is shader program's responsibility to make sure to take sampler as correct type of uniform variable.
I'm not really sure what exaclty you are asking here. The sampler variable in your shader selectes the texture target and must also match the internal data fromat of the texture object you want to use (i.e. for isampler or usampler, you'll need unnormalized integer texture formats otherwise results are undefined).
But I don't know what "what sampler type is passed to what uniform variable" is supposed to mean here. As far as the GL client side is concerned, the opaque sampler uniforms are just something which can be set to the index of the texture unit which is to be used, and that is done as an integer via glUniform1i or the like. There is no "sampler type" passed to a uniform variable.
7. number of texture units are large enough. Let each mesh loaded to application occupy as much texture unit as it please.
Not in the general case. The required GL_MAX_TEXTURE_IMAGE_UNITS (which defines how many different texture units a fragment shader can access) by the GL 4.5 spec is just 16. (There are separate limits per shder stage, so there is GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS and so on. They are all required to be at least 16 in the current spec.)
Usually, you have to switch textures inbetween draw calls. The usage of array textures and texture atlasses might allow one to further reduce the number of necessary state switches (and, ultimately, draw calls).
Very modern GPUs also support GL_ARB_bindless_texture, which completely bypasses the "texture unit" layer of indirection and allows the shader to directly reference a texture object by some opaque handle (which basically boils down to referencing some virtual GPU memory address under the hood). However, that feature is not yet part of the OpenGL standard.
8. Some Sampler parameters are duplicate of texture parameters. They will override texture parameter setting.
Yes. Traditionally, there were no separate sampler objects in the GL. Instead, the sampler states like filtering or wrap modes were part of the texture object itself. But modern hardware does not operate this way, so the sampler objects API has been introduced as the GL_ARB_sampler_objects extension (nowadays, a core feature of GL). If a sampler object is bound to a texture unit, its settings will override the sampler state present in the texture object.
9. Some Sampler parameters are duplicate of sampler description in shader program. Shader program's description will override samplers parameters.
I'm not sure what you mean by that. What "sampler descripitons" does a shader program define? There is only the declaration of the uniform and possibly the initialization via layout(binding=...). However, that is just the initial value. The client can update that any time by setting the uniform to another value, so that is not really "overriding" anything. But I'm not sure if you mean that.

How to remove unused resources from an OpenGL program

I am trying to create something like effect system for OpenGL, and I want to be able to define a number of shaders in the same file. But I discovered the following problem. Say I have two shaders: A and B. Shader A uses texA and shader B uses texB. Then despite the fact that neither shader A uses texB nor shader B uses texA, both textures will be enumerated in both programs (I am using separate programs, so every shader corresponds to one program). One consequence is that I cannot have many textures defined in one file since the shader will fail to link (it compiles successfully but the linker then complains that the number of texture samplers exceeds the HW limit). Other problem is that I am doing automatic resource binding and my shaders have lots of false resource dependencies.
So is there a way to tell the shader compiler/linker to remove all unused resources from the separate program?
Shader sampler units are not there to select textures, but to pass texture units to the shader. The textures themself are bound to the texture units. So the selection which texture to use should not be done in the shader, but in the host program.
Or you could use bindless textures if your OpenGL implementation (=GPU driver) supports these.

glTexParameter every frame or on initialization

Normally I would call glTexParameter when loading/initializing a texture. However, my current use case is that the same texture image may be used with many different parameter combinations (including GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T, GL_TEXTURE_BORDER_COLOR, etc).
Basically, I am mapping a texture to a mesh where it is clamped, and then mapping the same texture to different mesh where it is mirrored/repeated.
Is it better to call glTexParameter every frame before drawing each mesh/group (this is essentially supplying uniforms to my fragment shader), or should I load each texture multiple times for each different combination of parameters?
Keep in mind I may have a large number of textures each with several combinations of texture parameters.
I am using OpenGL 3.3 but am interested in any ideas.
Looks like you should try Sampler Object feature (core from 3.3). It separates texture image from it's parameters. So you can use just one texture with multiple parameter sets.
From spec:
Sampler objects may be bound to texture
units to supplant the bound texture's sampling state. A single
sampler may be bound to more than one texture unit simultaneously,
allowing different textures to be accessed with a single set of
shared sampling parameters.
Also, by binding different sampler
objects to texture units to which the same texture has been bound,
the same texture image data may be sampled with different sampling
parameters.
Looks like it is exactly what you need but you should definitely test it on the OpenGL implementation you are targeting and compare with other approaches - this is the only way to answer to anything related to performance in OpenGL.
You are approaching this all wrong, in GL 3.3+ Sampler Objects allow you to separate all of the states you just mentioned from Texture Objects.
OpenGL 4.4 Core Profile Specification - Table 23.18. Textures (state per sampler object) - pp. 539
As long as you have a non-zero Sampler Object bound to a Texture Image Unit, then when it comes time to sample that texture the state will be taken from the Sampler Object instead of the bound Texture Object. Note that the only thing that differs between 3.3 and 4.4 in terms of sampler state is the addition of a Debug label.
This approach allows you to change the sampling parameters for a texture simply by binding a different sampler object to the texture image unit you sample it using. Furthermore, the sampler object interface uses a much nicer design that does not require you to bind a sampler in order to change its properties.

Drawing multiple objects with different textures

Do I understand correctly that the typical way to draw multiple objects that each have a different texture in OpenGL is to simply bind one texture at a time using glBindTexture and draw the objects that use it, then bind a different texture and do the same?
In other words, only one texture can be "active" for drawing at any particular time, and that is the last texture that was bound using glBindTexture. Is this correct?
bind one texture at a time using glBindTexture and draw the objects that use it, then bind a different texture and do the same?
In other words, only one texture can be "active" for drawing at any particular time
These two statements are not the same thing.
A single rendering operation can only use a single set of textures at any time. This set is defined by the textures currently bound to the various texture image units. The number of texture image units available is queryable through GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS.
So multiple textures can be "active" for a single rendering command.
However, that's not the same thing as binding a bunch of textures and then rendering several objects, where each object only uses some (or one, in your case) of the bound textures. You could do that, but really, there's not much point.
The association between a GLSL sampler and a texture image unit is part of the program object state. It's the value you set on the sampler uniform. Therefore, in order to do what you suggest, you would have to bind a bunch of textures, set the uniform to one of them, render, then set the uniform to the next, render, etc.
You are still incurring all of the cost of binding those textures. You're still incurring all of the overhead of changing uniforms. Indeed, it might be less efficient, since the normal way (bind, render, bind, render) doesn't involve changing uniform state.
Plus, it's just weird. Generally, you shouldn't be changing uniform sampler state dynamically. You define a simple convention (diffuse texture comes from unit 0, specular from unit 1, etc), and you stick to that convention. Any GL 3.x-class hardware is required to provide no less than 48 texture image units (16 per stage), so it's not like you're going to run out.
There are mechanisms to do things not entirely unlike what you're talking about. For example, array textures can be leveraged, though this requires explicit shader logic and support. That would almost certainly be faster than the "bind a bunch of textures" method, since you're only binding one. Also, the uniform you'd be changing is a regular data uniform rather than a sampler uniform, which is likely to be faster.
With the array texture mechanism, you can also leverage instancing, assuming you're rendering the same object with slightly different parameters.

How to write a class or function automatically allocate the texture unit in OpenGL

I have seen many samples to hard code the number of texture unit in the program. For example:
glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_2D, object1BaseImage);
glActiveTexture(GL_TEXTURE0 + 2);
glBindTexture(GL_TEXTURE_2D, object1NormalMap);
glActiveTexture(GL_TEXTURE0 + 4);
glBindTexture(GL_TEXTURE_2D, shadowMap);
The problem is that two simultaneously used textures may conflict with each other by using the same texture unit when rendering a scene. my question is how to automatically allocate the texture unit in OpenGL by implementing a class or function? since there are many different constants that define how many sampler object I 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.
I am confused by the constants, isn't there should be a constant like GL_MAX_FRAGMENT_TEXTURE_IMAGE_UNITS? I think I need to get the max number of texture unit when allocating it.
So there are two questions:
How to understand the six constant mentioned above, why there isn't a constant named GL_MAX_FRAGMENT_TEXTURE_IMAGE_UNITS.
How to write a class or function automatically allocate the texture unit using the constants.
Any ideas? code snippet would be very appreciated.
How to write a class or function automatically allocate the texture unit using the constants.
This is easy: don't.
The "allocation" of texture image units is typically done by a convention set down by the program(s) you intend to use. You decide that unit 0 is where the diffuse texture goes; if a particular mesh&shader don't have a diffuse texture, you don't put something in unit 0. Unit 12 could be where shadow maps go.
This is why shading_language_420pack allows you to set the texture unit directly within the shader. Even without that, you should generally set the sampler's texture unit after compiling the shader and don't move it.
No point in changing program state when you don't have to.
On 3.3+ hardware, you have no less than 48+ texture units available. You're not likely to run out.
since there are many different constants that define how many sampler object I can use:
No, there is one constant that defines how many "sampler object" you can use: GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS. That is the hard limit on the total number of texture image units that OpenGL provides. glActiveTexture takes a number between GL_TEXTURE0 and GL_TEXTURE0+GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS.
The individual ones are the maximum number of GLSL sampler types that can be active in a single shader stage. As for which one you use for fragment shaders, it's GL_MAX_TEXTURE_IMAGE_UNITS. This is for legacy reasons, since initially only fragment shaders could access textures.