opengl pass texture to program: once or at every rendering? - opengl

I've a program with two texture: one from a video, and one from an image.
For the image texture, do I have to pass it to the program at each rendering, or can I do it just once? ie can I do
glActiveTexture(GLenum(GL_TEXTURE1))
glBindTexture(GLenum(GL_TEXTURE_2D), texture.id)
glUniform1i(textureLocation, 1)
just once? I believed so, but in my experiment, this works ok if there no video texture involved, but as soon as I add the video texture that I'm attaching at every rendering pass (since it's changing) the only way to get the image is to run the above code at each rendering frame.

Let's dissect what your doing, including some unnecessary stuff, and what the GL does.
First of all, none of the C-style casts you're doing in your code are necessary. Just use GL_TEXTURE_2D and so on instead of GLenum(GL_TEXTURE_2D).
glActiveTexture(GL_TEXTURE0 + i), where i is in the range [0, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1], selects the currently active texture unit. Commands that alter texture unit state will affect unit i as long as you don't call glActiveTexture with another valid unit identifier.
As soon as you call glBindTexture(target, name) with the current active texture unit i, the state of the texture unit is changed to refer to name for the specified target when sampling it with the appropriate sampler in a shader (i.e. name might be bound to TEXTURE_2D and the corresponding sample would have to be a sampler2D). You can only bind one texture object to a specific target for the currently active texture unit - so, if you need to sample two 2D textures in your shader, you'd need to use two texture units.
From the above, it should be obvious what glUniform1i(samplerLocation, i) does.
So, if you have two 2D textures you need to sample in a shader, you need two texture units and two samplers, each referring to one specific unit:
GLuint regularTextureName = 0;
GLunit videoTextureName = 0;
GLint regularTextureSamplerLocation = ...;
GLint videoTextureSamplerLocation = ...;
GLenum regularTextureUnit = 0;
GLenum videoTextureUnit = 1;
// setup texture objects and shaders ...
// make successfully linked shader program current and query
// locations, or better yet, assign locations explicitly in
// the shader (see below) ...
glActiveTexture(GL_TEXTURE0 + regularTextureUnit);
glBindTexture(GL_TEXTURE_2D, regularTextureName);
glUniform(regularTextureSamplerLocation, regularTextureUnit);
glActiveTexture(GL_TEXTURE0 + videoTextureUnit);
glBindTexture(GL_TEXTURE_2D, videoTextureName);
glUniform(videoTextureSampleLocation, videoTextureUnit);
Your fragment shader, where I assume you'll be doing the sampling, would have to have the corresponding samplers:
layout(binding = 0) uniform sampler2D regularTextureSampler;
layout(binding = 1) uniform sampler2D videoTextureSampler;
And that's it. If both texture objects bound to the above units are setup correctly, it doesn't matter if the contents of the texture changes dynamically before each fragment shader invocation - there are numerous scenarios where this is common place, e.g. deferred rendering or any other render-to-texture algorithm so you're not exactly breaking new ground with some video texture.
As to the question on how often you need to do this: you need to do it when you need to do it - don't change state that doesn't need changing. If you never change the bindings of the corresponding texture unit, you don't need to rebind the texture at all. Set them up once correctly and leave them alone.
The same goes for the sampler bindings: if you don't sample other texture objects with your shader, you don't need to change the shader program state at all. Set it up once and leave it alone.
In short: don't change state if don't have to.
EDIT: I'm not quite sure if this is the case or not, but if you're using teh same shader with one sampler for both textures in separate shader invocations, you'd have to change something, but guess what, it's as simple as letting the sampler refer to another texture unit:
// same texture unit setup as before
// shader program is current
while (rendering)
{
glUniform(samplerLocation, regularTextureUnit);
// draw call sampling the regular texture
glUniform(samplerLocation, videoTextureUnit);
// draw call sampling teh video texture
}

You should bind the texture before every draw. You only need to set the location once. You can also do layout(binding = 1) in your shader code for that. The location uniform stays with the program. The texture binding is a global GL state. Also be careful about ActiveTexture: it is a global GL state.
Good practice would be:
On program creation, once, set texture location (uniform)
On draw: SetActive(i), Bind(i), Draw, SetActive(i) Bind(0), SetActive(0)
Then optimize later for redundant calls.

Related

OpenGL confused about multiple textures

I'm developing a 3d program with OpenGL 3.3. So far I managed to render many cubes and some spheres. I need to texture all the faces of all the cubes with a common texture except one face which should have a different texture. I tried with a single texture and everything worked fine but when I try to add another one the program seems to behave randomly.
My questions:
is there a suitable way of passing multiple textures to the shaders?
how am I supposed to keep track of faces in order to render the right texture?
Googling I found out that it could be useful to define vertices twice, but I don't really get why.
Is there a suitable way of passing multiple textures to the shaders?
You'd use glUniform1i() along with glActiveTexture(). Thus given your fragment shader has multiple uniform sampler2D:
uniform sampler2D tex1;
uniform sampler2D tex2;
Then as you're setting up your shader, you set the sampler uniforms to the texture units you want them associated with:
glUniform1i(glGetUniformLocation(program, "tex1"), 0)
glUniform1i(glGetUniformLocation(program, "tex2"), 1)
You then set the active texture to either GL_TEXTURE0 or GL_TEXTURE1 and bind a texture.
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, texture1)
glActiveTexture(GL_TEXTURE1)
glBindTexture(GL_TEXTURE_2D, texture2)
How am I supposed to keep track of faces in order to render the right texture?
It depends on what you want.
You could decide which texture to use based the normal (usually done with tri-planar texture mapping).
You could also have another attribute that decides how much to crossfade between the two textures.
color = mix(texture(tex1, texCoord), texture(tex2, texCoord), 0.2)
Like before, you can equally have a uniform float transition. This would allow you to fade between textures, making it possible to fade between slides like in PowerPoint, so to speak.
Try reading LearnOpenGL's Textures tutorial.
Lastly there's a minimum of 80 texture units. You can check specifically how many you have available using GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS.
You can use index buffers. Define the vertices once, and then use one index buffer to draw the portion of the mesh with the first texture, then use the second index buffer to draw the portion that needs the second texture.
Here's the general formula:
Setup the vertex buffer
Setup the shader
Setup the first texture
Setup and draw the index buffer for the part of the mesh that should use the first texture
Setup the second texture
Setup and draw the index buffer for the part of the mesh that should use the second texture.

Read from one texture and write to a separate texture with in the same frame buffer

I have a Framebuffer with 2 textures attached is it possible to read from texture A and write to texture B, in the same fragment shader function ?
Thanks.
This is trickier than I expected. I thought that as long as you don't sample from and render to the same texture you would be fine, no matter if the texture is attached to an FBO. But while trying to find some conclusive spec quotes to back this up, things became much less clear.
The 4.5 spec does contain a phrase that seems to confirm my initial instinct (emphasis added):
Specifically, the values of rendered fragments are undefined if any shader stage fetches texels and the same texels are written via fragment shader outputs, even if the reads and writes are not in the same draw call
The interesting aspect is that the "written via fragment shader outputs" does not appear in spec versions up to and including 4.4. I don't know if adding this in 4.5 was intended as just a clarification, or if the rules for feedback loops were relaxed in 4.5. I couldn't find anything in the change log that would provide more background on the change.
Up to 4.4, the spec says that if a texture is attached to the current draw framebuffer, and is sampled, you have a feedback loop. Since nothing says otherwise, this would include the situation where the texture is attached to the FBO, but not used as a draw buffer.
I wouldn't be surprised if things mostly work fine as long as you don't render to and sample from the same texture. But to be completely safe, particularly if you don't rely on having OpenGL 4.5, you should un-attach the sampled texture from the FBO. Not including it in the list of draw buffers would be insufficient.
Extending Reto's answer.
You can read from texture A and write to texture B, BUT you cannot do this:
uniform sampler2D B; // Sampler for texture B.
layout (location = 0) out vec3 A; // Write to texture
A = texture(B,Texcoord);
This is invalid, and you must use a tertiary variable.
You cannot read and write to the texture on the same draw call, but you can read from one texture and write to another texture that both reside on the same framebuffer in the same draw call. You have to make sure when you bind the frame buffer you bind it like this.
glbindframebuffer(GL_FRAMEBUFFER, fboHandle)
This is because the framebuffer will be written to and read from and the `GL_FRAMEBUFFER, will allow you to do this.

OpenGL reading from unbound texture unit

Does the OpenGL standard mandate what the result of a texture2d operation should be given a uniform sampler2D that the program hasn't bound to a texture unit?
For example in the pixel shader:
layout(binding=0) uniform sampler2D Map_Diffuse;
...
texture2D(Map_Diffuse, attrib_Fragment_Texture)
Where in the program:
::glActiveTexture(GL_TEXTURE0);
::glBindTexture(GL_TEXTURE_2D, 0);
For context I'm wondering whether I can use the same shader for textured and non-textured entities, where (hopefully) I only need to make sure nothing is bound to GL_TEXTURE_2D for texture2d() to return 0, 0, 0, 1. Otherwise I'll need one shader for each permutation.
The way I read the spec, it's guaranteed to return black. The following quotes are copied from the 3.3 spec.
In section 2.11.7 "Shader Execution" under "Vertex Shaders", on page 81:
Using a sampler in a vertex or geometry shader will return (R,G,B,A) = (0,0,0,1) if the sampler’s associated texture is not complete, as defined in section 3.8.14.
and equivalent in section 3.9.2 "Shader Execution" under "Fragment Shaders", on page 188:
Using a sampler in a fragment shader will return (R,G,B,A) = (0,0,0,1) if the sampler’s associated texture is not complete, as defined in section 3.8.14.
In section 3.8.14 "Texture Completeness", it says:
A texture is said to be complete if all the image arrays and texture parameters required to utilize the texture for texture application are consistently defined.
Now, it doesn't explicitly say anything about texture objects that don't even exist. But since texture names that don't reference a texture object (which includes 0) certainly don't have "all the image arrays and texture parameters consistently defined", I would argue that they fall under "not complete" in the definitions above.
Does the OpenGL standard mandate what the result of a texture2d
operation should be given a uniform sampler2D that the program hasn't
bound to a texture unit?
When a texture sampler is unbound to a texture object, it is by default bound to texture object 0/null, this is like null in C/C++. When accessing object null, from my experience you get zero values For example:
vec2 Data = texture(unboundSampler, textureCoords);
Data will often be zoroes, but my assumption is this implementation dependent, some drivers may crash.
For context I'm wondering whether I can use the same shader for
textured and non-textured entities
In my engine I solved this by creating a default white texture that is 4 white pixels. Generated by code when the engine is initialized. When I want to use a shader that has a texture sampler and the corresponding material doesn't have a texture I assign the default white texture. This way I can reuse the same shader. If you care so much about performance you might want to use a shader without textures for non textured objects.
The standard doesn't talk about the implementation but it encourages you to think about the zero object as non-functional object. https://www.opengl.org/wiki/OpenGL_Object#Object_zero

OpenGL ES 3 (iOS) texturing oddness - want to know why

I have a functioning OpenGL ES 3 program (iOS), but I've having a difficult time understanding OpenGL textures. I'm trying to render several quads to the screen, all with different textures. The textures are all 256 color images with a sperate palette.
This is C++ code that sends the textures to the shaders
// THIS CODE WORKS, BUT I'M NOT SURE WHY
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _renderQueue[idx]->TextureId);
glUniform1i(_glShaderTexture, 1); // what does the 1 mean here
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, _renderQueue[idx]->PaletteId);
glUniform1i(_glShaderPalette, 2); // what does the 2 mean here?
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
This is the fragment shader
uniform sampler2D texture; // New
uniform sampler2D palette; // A palette of 256 colors
varying highp vec2 texCoordOut;
void main()
{
highp vec4 palIndex = texture2D(texture, texCoordOut);
gl_FragColor = texture2D(palette, palIndex.xy);
}
As I said, the code works, but I'm unsure WHY it works. Several seemingly minor changes break it. For example, using GL_TEXTURE0, and GL_TEXTURE1 in the C++ code breaks it. Changing the numbers in glUniform1i to 0, and 1 break it. I'm guessing I do not understand something about texturing in OpenGL 3+ (maybe Texture Units???), but need some guidance to figure out what.
Since it's often confusing to newer OpenGL programmers, I'll try to explain the concept of texture units on a very basic level. It's not a complex concept once you pick up on the terminology.
The whole thing is motivated by offering the possibility of sampling multiple textures in shaders. Since OpenGL traditionally operates on objects that are bound with glBind*() calls, this means that an option to bind multiple textures is needed. Therefore, the concept of having one bound texture was extended to having a table of bound textures. What OpenGL calls a texture unit is an entry in this table, designated by an index.
If you wanted to describe this state in a C/C++ style notation, you could define the table of bound texture as an array of texture ids, where the size is the maximum number of bound textures supported by the implementation (queried with glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, ...)):
GLuint BoundTextureIds[MAX_TEXTURE_UNITS];
If you bind a texture, it gets bound to the currently active texture unit. This means that the last call to glActiveTexture() determines which entry in the table of bound textures is modified. In a typical call sequence, which binds a texture to texture unit i:
glActiveTexture(GL_TEXTUREi);
glBindTexture(GL_TEXTURE_2D, texId);
this would correspond to modifying our imaginary data structure by:
BoundTextureIds[i] = texId;
That covers the setup. Now, the shaders can access all the textures in this table. Variables of type sampler2D are used to access textures in the GLSL code. To determine which texture each sampler2D variable accesses, we need to specify which table entry each one uses. This is done by setting the uniform value to the table index:
glUniform1i(samplerLoc, i);
specifies that the sampler uniform at location samplerLoc reads from table entry i, meaning that it samples the texture with id BoundTextureIds[i].
In the specific case of the question, the first texture was bound to texture unit 1 because glActiveTexture(GL_TEXTURE1) was called before glBindTexture(). To access this texture from the shader, the shader uniform needs to be set to 1 as well. Same thing for the second texture, with texture unit 2.
(The description above was slightly simplified because it did not take into account different texture targets. In reality, textures with different targets, e.g. GL_TEXTURE_2D and GL_TEXTURE_3D, can be bound to the same texture unit.)
GL_TEXTURE1 and GL_TEXTURE2 refer to texture units. glUniform1i takes a texture unit id for the second argument for samplers. This is why they are 1 and 2.
From the OpenGL website:
The value of a sampler uniform in a program is not a texture object,
but a texture image unit index. So you set the texture unit index for
each sampler in a program.

Differences and relationship between glActiveTexture and glBindTexture

From what I gather, glActiveTexture sets the active "texture unit". Each texture unit can have multiple texture targets (usually GL_TEXTURE_1D, 2D, 3D or CUBE_MAP).
If I understand correctly, you have to call glActiveTexture to set the texture unit first (initialized to GL_TEXTURE0), and then you bind (one or more) "texture targets" to that texture unit?
The number of texture units available is system dependent. I see enums for up to 32 in my library. I guess this essentially means I can have the lesser of my GPU's limit (which I think is 16 8) and 32 textures in GPU memory at any one time? I guess there's an additional limit that I don't exceed my GPU's maximum memory (supposedly 1 GB).
Am I understanding the relationship between texture targets and texture units correctly? Let's say I'm allowed 16 units and 4 targets each, does that mean there's room for 16*4=64 targets, or does it not work like that?
Next you typically want to load a texture. You can do this via glTexImage2D. The first argument of which is a texture target. If this works like glBufferData, then we essentially bind the "handle"/"texture name" to the texture target, and then load the texture data into that target, and thus indirectly associate it with that handle.
What about glTexParameter? We have to bind a texture target, and then choose that same target again as the first argument? Or does the texture target not need to be bound as long as we have the correct active texture unit?
glGenerateMipmap operates on a target too...that target has to still be bound to the texture name for it to succeed?
Then when we want to draw our object with a texture on it, do we have to both choose an active texture unit, and then a texture target? Or do we choose a texture unit, and then we can grab data from any of the 4 targets associated with that unit? This is the part that's really confusing me.
All About OpenGL Objects
The standard model for OpenGL objects is as follows.
Objects have state. Think of them as a struct. So you might have an object defined like this:
struct Object
{
int count;
float opacity;
char *name;
};
The object has certain values stored in it and it has state. OpenGL objects have state too.
Changing State
In C/C++, if you have an instance of type Object, you would change its state as follows: obj.count = 5; You would directly reference an instance of the object, get the particular piece of state you want to change, and shove a value into it.
In OpenGL, you don't do this.
For legacy reasons better left unexplained, to change the state of an OpenGL object, you must first bind it to the context. This is done with some from of glBind* call.
The C/C++ equivalent to this is as follows:
Object *g_objs[MAX_LOCATIONS] = {NULL};
void BindObject(int loc, Object *obj)
{
g_objs[loc] = obj;
}
Textures are interesting; they represent a special case of binding. Many glBind* calls have a "target" parameter. This represents different locations in the OpenGL context where objects of that type can be bound. For example, you can bind a framebuffer object for reading (GL_READ_FRAMEBUFFER) or for writing (GL_DRAW_FRAMEBUFFER). This affects how OpenGL uses the buffer. This is what the loc parameter above represents.
Textures are special because when you first bind them to a target, they get special information. When you first bind a texture as a GL_TEXTURE_2D, you are actually setting special state in the texture. You are saying that this texture is a 2D texture. And it will always be a 2D texture; this state cannot be changed ever. If you have a texture that was first bound as a GL_TEXTURE_2D, you must always bind it as a GL_TEXTURE_2D; attempting to bind it as GL_TEXTURE_1D will give rise to an error (while run-time).
Once the object is bound, its state can be changed. This is done via generic functions specific to that object. They too take a location that represents which object to modify.
In C/C++, this looks like:
void ObjectParameteri(int loc, ObjectParameters eParam, int value)
{
if(g_objs[loc] == NULL)
return;
switch(eParam)
{
case OBJECT_COUNT:
g_objs[loc]->count = value;
break;
case OBJECT_OPACITY:
g_objs[loc]->opacity = (float)value;
break;
default:
//INVALID_ENUM error
break;
}
}
Notice how this function sets whatever happens to be in currently bound loc value.
For texture objects, the main texture state changing functions are glTexParameter. The only other functions that change texture state are the glTexImage functions and their variations (glCompressedTexImage, glCopyTexImage, the recent glTexStorage). The various SubImage versions change the contents of the texture, but they do not technically change its state. The Image functions allocate texture storage and set the texture's format; the SubImage functions just copy pixels around. That is not considered the texture's state.
Allow me to repeat: these are the only functions that modify texture state. glTexEnv modifies environment state; it doesn't affect anything stored in texture objects.
Active Texture
The situation for textures is more complex, again for legacy reasons best left undisclosed. This is where glActiveTexture comes in.
For textures, there aren't just targets (GL_TEXTURE_1D, GL_TEXTURE_CUBE_MAP, etc). There are also texture units. In terms of our C/C++ example, what we have is this:
Object *g_objs[MAX_OBJECTS][MAX_LOCATIONS] = {NULL};
int g_currObject = 0;
void BindObject(int loc, Object *obj)
{
g_objs[g_currObject][loc] = obj;
}
void ActiveObject(int currObject)
{
g_currObject = currObject;
}
Notice that now, we not only have a 2D list of Objects, but we also have the concept of a current object. We have a function to set the current object, we have the concept of a maximum number of current objects, and all of our object manipulation functions are adjusted to select from the current object.
When you change the currently active object, you change the entire set of target locations. So you can bind something that goes into current object 0, switch to current object 4, and will be modifying a completely different object.
This analogy with texture objects is perfect... almost.
See, glActiveTexture does not take an integer; it takes an enumerator. Which in theory means that it can take anything from GL_TEXTURE0 to GL_TEXTURE31. But there's one thing you must understand:
THIS IS FALSE!
The actual range that glActiveTexture can take is governed by GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS. That is the maximum number of simultaneous multitextures that an implementation allows. These are each divided up into different groupings for different shader stages. For example, on GL 3.x class hardware, you get 16 vertex shader textures, 16 fragment shader textures, and 16 geometry shader textures. Therefore, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS will be 48.
But there aren't 48 enumerators. Which is why glActiveTexture doesn't really take enumerators. The correct way to call glActiveTexture is as follows:
glActiveTexture(GL_TEXTURE0 + i);
where i is a number between 0 and GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS.
Rendering
So what does all of this have to do with rendering?
When using shaders, you set your sampler uniforms to a texture image unit (glUniform1i(samplerLoc, i), where i is the image unit). That represents the number you used with glActiveTexture. The sampler will pick the target based on the sampler type. So a sampler2D will pick from the GL_TEXTURE_2D target. This is one reason why samplers have different types.
Now this sounds suspiciously like you can have two GLSL samplers, with different types that use the same texture image unit. But you can't; OpenGL forbids this and will give you an error when you attempt to render.
I'll give it a try ! All this is not that complicated, just a question of terms, hope I'll make myself clear.
You can create roughly as many Texture Objects as there is available memory in your system. These objects hold the actual data (texels) of your textures, along with parameters, provided by glTexParameter (see FAQ).
When being created, you have to assign one Texture Target to one texture object, which represents the type of the texture (GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE, ...).
These two items, texture object and texture target represent the texture data. We'll come back to them later.
Texture units
Now, OpenGL provides an array of texture units, that can be used simultaneously while drawing. The size of the array depends of the OpenGL system, yours has 8.
You can bind a texture object to a texture unit to use the given texture while drawing.
In a simple and easy world, to draw with a given texture, you'd bind a texture object to the texture unit, and you'd do (pseudocode):
glTextureUnit[0] = textureObject
As GL is a state machine, it, alas, does not work this way. Supposing that our textureObject has data for the GL_TEXTURE_2D texture target, we'll express the previous assignment as :
glActiveTexture(GL_TEXTURE0); // select slot 0 of the texture units array
glBindTexture(GL_TEXTURE_2D, textureObject); // do the binding
Note that GL_TEXTURE_2D really depends on the type of the texture you want to bind.
Texture objects
In pseudo code, to set texture data or texture parameters, you'd do for example :
setTexData(textureObject, ...)
setTexParameter(textureObject, TEXTURE_MIN_FILTER, LINEAR)
OpenGL can't directly manipulate texture objects, to update/set their content, or change their parameters, you have to first bind them to the active texture unit (whichever it is). The equivalent code becomes :
glBindTexture(GL_TEXTURE_2D, textureObject) // this 'installs' textureObject in texture unit
glTexImage2D(GL_TEXTURE_2D, ...)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
Shaders
Shaders have access to all the texture units, they don't care about the active texture.
Sampler uniforms are int values representing the index of the texture unit to use for the sampler (and not the texture object to use).
So you have to bind your texture objects to the units you want to use.
The type of the sampler will do the match with the texture target that is used in the texture unit : Sampler2D for GL_TEXTURE_2D, and so on...
Imagine the GPU like some paint processing plant.
There are a number of tanks, which delivers dye to some painting machine. In the painting machine the dye is then applied to the object. Those tanks are the texture units
Those tanks can be equipped with different kinds of dye. Each kind of dye requires some other kind of solvent. The "solvent" is the texture target. For convenience each tank is connected to some solvent supply, and but only one kind of solvent can be used at a time in each tank. So there's a valve/switch TEXTURE_CUBE_MAP, TEXTURE_3D, TEXTURE_2D, TEXTURE_1D. You can fill all the dye types into the tank at the same time, but since only one kind of solvent goes in, it will "dilute" only the kind of dye matching. So you can have each kind of texture being bound, but the binding with the "most important" solvent will actually go into the tank and mix with the kind of dye it belongs to.
And then there's the dye itself, which comes from a warehouse and is filled into the tank by "binding" it. That's your texture.