43

I've read a texture example in OpenGL 2.1. The fragment shader looks like this:

#version 120

uniform sampler2D texture;
varying vec2 texcoord;

void main(void)
{
    gl_FragColor = texture2D(texture, texcoord);
}

The texcoord is passed from vertex shader.

The following C++ rendering code is used:

void render()
{
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture_id);
    glUniform1i(unf_texture, 0);
}

I am confused about some things. I have some question:

  1. In the fragment shader, the texture is passed a zero value (by glUniform1i()). Is the value really zero? Is the value something else?

  2. Is glActiveTexture() call really need?

  3. Why do we pass a zero value in glUniform1i()?

0xCursor
  • 2,242
  • 4
  • 15
  • 33
Bình Nguyên
  • 2,252
  • 6
  • 32
  • 47

1 Answers1

43

The sampler2D is bound to a texture unit. The glUniform call binds it to texture unit zero. The glActiveTexture() call is only needed if you are going to use multiple texture units (because GL_TEXTURE0 is the default anyway).

0xCursor
  • 2,242
  • 4
  • 15
  • 33
Ville Krumlinde
  • 7,021
  • 1
  • 33
  • 41
  • 30
    You should make it a habit to always call `glActiveTexture`. That way, when you suddenly need to use more than one texture, you won't break the world. – Nicol Bolas Jun 03 '12 at 15:43
  • to clarify - is it therefore correct that every texture (1D,2D,3D) that could be bound under the same "GL_TEXTURE0", will have to have the same value (0) passed to sampler1D/2D/3D ? and a texture assigned under "GL_TEXTURE1" would require the value 1 passed to the uniform inside the shader ? – Chris Aug 21 '13 at 15:23
  • 1
    So (correct me if I'm wrong) the way docs explain it is `glActiveTexture()` is used to prompt the OpenGL state machine that the texture state functions you call after (such as `glBindTexture()`) apply to the specified texture index, and you use the `GL_TEXTURE0` thru e.g. `GL_TEXTURE8` preprocessor constants here to do that (assign the HW's TIU's to the textures you specify). As for setting the uniforms (I'm still hunting down the docs for this), you set it to an integer corresponding to the TIU number that you want the shader variable of the uniform sampler to sample. – Steven Lu Aug 01 '14 at 17:48
  • @NicolBolas Lacking such a habit and not "breaking the world" when more than one texture is needed are not mutually exclusive. – Kröw Aug 03 '22 at 21:33
  • @Kröw: No, but one way will always definitely work, while the other way, you may make a mistake. I prefer code that cannot break to code based on assumptions. – Nicol Bolas Aug 03 '22 at 21:38
  • @NicolBolas It is wrong to say that one will "always definitely work." Mistakes can show up anywhere in code. As a matter of fact, introducing more code that does not contribute to a program is introducing more opportunity for mistakes. Additionally, unnecessary statements are likely to confuse other developers reading the code, misleading them into thinking the statement does something or otherwise changes the program's behavior. I believe we would agree that it is good to maintain healthy habits, but I believe such a habit would be calling `glActiveTexture` only when it is necessary. – Kröw Aug 04 '22 at 03:27
  • @Kröw: And that's exactly why when OpenGL introduced indexed binding points for buffer objects, they did it in exactly the same way as textures, with two separate calls to bind to an index. Oh right, they *didn't*; they did it with *one call* that takes both the index and the buffer, like a reasonable API would. Which is also why they introduced `glBindTextureUnit` that binds the texture to the given texture unit, rather than needing two calls. It's a bad API; there's no use trying to defend it. It only works that way because of legacy nonsense. – Nicol Bolas Aug 04 '22 at 03:43
  • @NicolBolas I do not know what relevance the of OpenGL being bad is to the topic of making it a habit to unnecessarily call a function, I'm sorry. I don't know what you mean when you say you are trying to defend the API. Could you elaborate on what you mean by this? My point is just to say that making habits of writing unnecessary function calls is not something a developer should do. – Kröw Aug 04 '22 at 04:15
  • @Kröw: My point is that it isn't "unnecessary", as evidenced by all of the other functions that *combine* the effects of `glActiveTexture` and `glBindTexture`, as well as similar indexed binding APIs that don't separate them. These are not two distinct operations; they are *one operation* artificially forced into being two function calls. To call one without calling the other is not eliminating something "unnecessary"; it is removing vital information about what you are actually doing, as you are now relying on non-local information about the behavior of the function. – Nicol Bolas Aug 04 '22 at 06:28
  • @NicolBolas I believe you are missing that it does nothing. – Kröw Aug 04 '22 at 08:47
  • @Kröw: What "it" are you talking about? `glActiveTexture` definitely does something: it changes the current texture unit index which all texture binding functions refer. – Nicol Bolas Aug 04 '22 at 13:22
  • @NicolBolas The behavior of that function is very clear to me. To answer your question, please re-read this answer we're commenting on. Hopefully that will shed light on your misunderstanding. – Kröw Aug 04 '22 at 22:02
  • @Kröw: I know what the function does. There is no misunderstanding. It is a bad API, as it separates the setting of the current texture unit from the binding of a texture to that unit. My point is that you shouldn't treat them as two separate operations; they are one function. And all of the rest of OpenGL supports that idea. You have nothing on your side to show that the API is good besides the fact that the function *exists*. – Nicol Bolas Aug 04 '22 at 23:49
  • @Kröw: If it's such a good idea to separate the changing of the texture unit from the binding of a texture to that unit, then explain why `glBindTextures` (note the "s") and `glBindTextureUnit` exists. Explain why `glBindBufferRange` takes an index to bind the buffer to instead of having a `glActiveBuffer`. – Nicol Bolas Aug 04 '22 at 23:51
  • @NicolBolas Why did you bring up the irrelevant idea that OpenGL is a bad API? I recommend you reread the prior discussion. – Kröw Aug 07 '22 at 05:33
  • @Kröw: My suggestion, the one you're responding to, is to basically always pretend that `glActiveTexture` and `glBindTexture` are one function and to call them at the same time, to ensure that your code does what you think it does. I suggested this to compensate for OpenGL's bad API design. You are defending the use of these functions as separate. Which only makes sense if you think that the API is OK, so you're saying that my suggestion to compensate for it is wrong. So you implicitly opened the door. – Nicol Bolas Aug 07 '22 at 13:34
  • @Kröw: And again, my point is that my suggestion is backed up by *evidence*. Nothing else in OpenGL works like this, even when they could have. So effectively writing your own `glBindTextureUnit` function (if you don't have access to that one) is not merely personal opinion; it's based on actual evidence. – Nicol Bolas Aug 07 '22 at 13:38
  • @NicolBolas I suggest that you please reread the comments before to have a better understanding of my argument. I believe you have also misconstrued my argument; there is nothing for me to “defend,” rather I am noting that your suggestion of ignoring that they are different is not a good habit. I do not make any claims about if the API is “okay” or not, and I frankly think that such is irrelevant to this discussion. – Kröw Aug 27 '22 at 16:24
  • @Kröw: "*rather I am noting that your suggestion of ignoring that they are different is not a good habit.*" If you treat them as one function, as `glBindTextureUnit`, you eliminate an *entire class* of mistake. You cannot bind a texture to the wrong unit because some other code changed the active texture. My point is that there are only benefits and no downsides. The fact that there is no downside is why `glBindTextureUnit` *exists*. This API was not a choice made by clever designers for a useful purpose. It was a bug-prone API whose bugs should be minimized. – Nicol Bolas Aug 27 '22 at 16:37
  • @Kröw: My point is that your suggestion of "calling glActiveTexture only when it is necessary" opens the user up to an entire category of mistakes. You cannot eliminate all mistakes, but you can eliminate *that one.* So there's no reason not to. – Nicol Bolas Aug 27 '22 at 16:39
  • @NicolBolas "*you eliminate an entire class of mistake*" please note that you have already stated this, and I have already noted why implementing your suggestion opens the door to a plethora of potential mistakes. Again, I please, please ask that you refer to the previous comments. It seems you have missed the one that responds directly to what you have restated... – Kröw Aug 27 '22 at 18:59
  • @Kröw: I saw your response. I did not find your argument to be reasonable or even coherent. Less code does not mean less bugs. A function which is dependent on global state set by another function is inherently more brittle than a function that takes responsibility for its own state. External code cannot break it; only its own internal code can. Mutable global state is broadly discouraged and is often considered a sign of bad code. All things being equal, a function that takes care of itself will be less brittle than one that relies on global state. – Nicol Bolas Aug 27 '22 at 21:35
  • @NicolBolas If you did not find my argument coherent, then my suggestion for you to reread it is only more justified. I believe you are still misreading it anyway. I have not said that simply less code means less bugs, but rather that less unnecessary code means less potential for bugs. I think it would be wise for you to pay attention to the subtle nuances in these things. – Kröw Aug 28 '22 at 06:32
  • @NicolBolas Functions that take care of themselves will definitely be less brittle when there are other functions accessing global state that they need to account for. Adding unnecessary code to a function in a dummy test class, for a crude example, to "account" for this issue, has no upside, but has the definite potential for more mistakes and bugs. I understand your argument, but have given reason as to why it is wrong. I ask that you consider what I've said in more detail. – Kröw Aug 28 '22 at 06:35
  • @Kröw: "*has the definite potential for more mistakes and bugs.*" What mistakes? The only mistake it could make is binding to the wrong unit. But the code that set `glActiveTexture` could *also* make that mistake. So what "more" bugs are introduced? – Nicol Bolas Aug 28 '22 at 13:21
  • @NicolBolas that is definitely not the only mistake that could be made. There are plenty of mistakes that can be made. You are only considering a narrow spectrum of what kind of issues can occur in line with your argument. And as I've said repeatedly now, seemingly to no avail, as you introduce more code that is not necessary, you are always introducing more potential for mistakes. (This is an immensely obvious trend.) I think it would be very much to your benefit to consider how a program with 10000 lines of code is more likely to have a bug than a program with 10, or one. – Kröw Aug 29 '22 at 00:00
  • @Kröw: "*There are plenty of mistakes that can be made.*" Then name one. I've named an exact mistake that cannot happen if you use both; you refuse to name any mistakes that cannot happen if you only use `glBindTexture`. We're not talking about some generality here; I'm talking about a specific API which has a specific purpose. You can repeat all you like that "more code that is not necessary" is bad, but that doesn't make it true in *this* case. – Nicol Bolas Aug 29 '22 at 00:21
  • @NicolBolas "*We're not talking about some generality here;*" I can't stress enough that you must understand what I've said before if you are to be able to make counterarguments to it. You are persistently refusing to read the boon of information I've given that directly counters everything you've said so far. If you seriously cannot see mistakes that can happen when introducing new code, then I'll point you towards the following: (1) every possible misspelling of the extra, completely unnecessary statement you wish to add showing up during compile time, – Kröw Aug 29 '22 at 03:06
  • @NicolBolas (2) invoking the wrong function, leading to unexpected behavior that can even stay hidden while the program is checked, (3) (particularly with your approach) unexpected behavior resulting from people following such "habit" advice without having a deep understanding of all of the side effects and behavior that the excessive statement adds. I think this is particularly important; if you're going to call a function, it would be best for you to know how it behaves precisely. – Kröw Aug 29 '22 at 03:07
  • @NicolBolas Calling unnecessary functions is going to force developers to spend plenty of unnecessary time learning about this behavior or, if they don't, will introduce a large potential for very hidden bugs. – Kröw Aug 29 '22 at 03:07
  • @Kröw: "*every possible misspelling of the extra, completely unnecessary statement you wish to add showing up during compile time*" You could misspell it anywhere; that's not unique to this function. "*invoking the wrong function*" You could invoke the wrong function when you meant to call `glBindTexture`. "*unexpected behavior resulting from people following such "habit" advice without having a deep understanding of all of the side effects and behavior that the excessive statement adds*" What side effects? Please, use your deep knowledge of OpenGL to explain what these side effects are. – Nicol Bolas Aug 29 '22 at 03:11
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/247634/discussion-between-nicol-bolas-and-krow). – Nicol Bolas Aug 29 '22 at 03:12
  • @NicolBolas "*You could misspell it anywhere.*" Not if it is not *written*, anywhere. Your argument means nothing in this context. My point is that these plethora of mistakes cannot happen to a call to the unnecessary code you wish to add, if they are not added. You may have plenty of experience with the OpenGL API, but I strongly suggest you enrich your knowledge on common code principles. It will definitely be in your favor in practice. These issues are trivial, yet they can have a large effect on your code! :-) – Kröw Aug 29 '22 at 03:14