87

When setting up attribute locations for an OpenGL shader program, you are faced with two options:

glBindAttribLocation() before linking to explicitly define an attribute location.

or

glGetAttribLocation() after linking to obtain an automatically assigned attribute location.

What is the utility for using one over the other?

And which one, if any, is preferred in practice?

genpfault
  • 51,148
  • 11
  • 85
  • 139
Jing
  • 1,881
  • 2
  • 15
  • 13
  • 6
    I didn't bother using `glBindAttribLocation` in my graphics engine, which worked nicely on linux. When I ported to windows, it was using my normals as vertices - I had to explicitly tell it the order of the variables in my shader via `glBindAttribLocation` to get it to work... – Jarrett Oct 18 '13 at 18:53

3 Answers3

99

I know one good reason to prefer explicit location definition.

Consider that you hold your geometry data in Vertex Array Objects. For a given object, you create a VAO in such way that the indices correspond to, for example:

  • index 0: positions,
  • index 1: normals,
  • index 2: texcoords

Now consider that you want to draw one object with two different shaders. One shader requires position and normal data as input, the other - positions and texture coords.

If you compile those shaders, you will notice that the first shader will expect the positions at attribute index 0 and normals at 1. The other would expect positions at 0 but texture coords at 1.

Quoting https://www.opengl.org/wiki/Vertex_Shader:

Automatic assignment

If neither of the prior two methods assign an input to an attribute index, then the index is automatically assigned by OpenGL when the program is linked. The index assigned is completely arbitrary and may be different for different programs that are linked, even if they use the exact same vertex shader code.

This means that you wouldn't be able to use your VAO with both shaders. Instead of having one VAO per, say, object, you'd need - in the worst case - a separate VAO per object per shader.

Forcing the shaders to use your own attribute numbering convention via glBindAttribLocation can solve this problem easily - all you need to do is to keep a consistent relation between attributes and their estabilished IDs, and force the shaders to use that convention when linking.

(That's not really a big issue if you don't use separate VAOs, but still might make your code clearer.)


BTW:

When setting up attribute locations for an OpenGL shader program, you are faced with two options

There's a third option in OpenGL/GLSL 3.3: Specify the location directly in shader code. It looks like this:

layout(location=0) in vec4 position;

But this is not present in GLSL ES shader language.

cxw
  • 16,685
  • 2
  • 45
  • 81
Kos
  • 70,399
  • 25
  • 169
  • 233
  • 1
    I don't see the point. VAO are really light-weight and you will usually recreate them for each frame. In your case, you would just create different VAOs before calling each shader, won't you? – PierreBdR Jun 08 '12 at 16:32
  • 1
    Yes, you can do that of course. It will work just as well, we're only discussing conventions here. :) – Kos Jun 08 '12 at 19:03
  • 4
    The third option is actually available in GLES2.0 but the format is slightly different: layout(location = 0) attribute vec4 position; Note that you'll also need this at the top of your GLSL file: #extension GL_EXT_separate_shader_objects : enable – Gavin Maclean Nov 08 '12 at 15:03
  • 35
    *"VAO are really light-weight and you will usually recreate them for each frame. In your case, you would just create different VAOs before calling each shader, won't you?"* - No, you won't usually do this, since this in the end completely invalidates the whole purpose of VAOs. Why then use a VAO at all? – Christian Rau Mar 11 '13 at 13:51
  • If I do not explicitly bind attribute, as you said, "If you compile those shaders, you will notice that the first shader will expect the positions at attribute index 0 and normals at 1. The other would expect positions at 0 but texture coords at 1.". Where can I find in the official link about it? – user1914692 Nov 07 '14 at 01:05
  • @user1914692 Edited and added a reference to OpenGL wiki. – Kos Nov 07 '14 at 09:14
  • 2
    Just a note. You wouldn't keep your geometry data in a VAO. That would be in a VBO. VAOs don't have data storage. – average joe Oct 07 '15 at 19:49
  • @averagejoe hello, does the post suggest otherwise? – Kos Oct 08 '15 at 12:54
  • @Kos Yes. _Consider that you hold your geometry data in Vertex Array Objects..._ :) – average joe Oct 08 '15 at 18:02
  • 1
    As of GLSL ES version 3.00 the location qualifier is available. – jcmonteiro Mar 02 '16 at 14:23
  • @Kos wrote _"you wouldn't be able to use your VAO with both shaders"_ - A possibility is to collect the `glGetAttribLocation` of each attribute of both shaders and `glEnableVertexAttribArray` them before drawing with the respective shader, or am I wrong? – mskr Aug 31 '16 at 10:17
22

Another answer here is that glGetAttribLocation returns data to the caller, which means that it implicitly requires a pipeline flush. If you call it right after you compile your program, you're essentially forcing asynchronous compilation to occur synchronously.

Litherum
  • 22,564
  • 3
  • 23
  • 27
  • 1
    More detail: http://src.chromium.org/svn/trunk/src/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_bind_uniform_location.txt – Litherum Feb 19 '13 at 21:06
  • Thanks, this is a very important consideration. – Jing Sep 14 '13 at 06:02
  • 1
    It's my understanding that under most situations you would have to call `glGetUniformLocation` anyway; is this particular consideration still relevant? – Mike Weir Jan 09 '16 at 22:15
  • @MikeWeir since GL 4.3 you can set [explicit uniform location](https://www.opengl.org/wiki/Uniform_(GLSL)#Explicit_uniform_location). – Ruslan Aug 25 '16 at 16:14
  • 1
    @Ruslan They're using OpenGL ES. – Mike Weir Aug 26 '16 at 15:26
  • @MikeWeir OK, since OpenGL ES 3.0. – Ruslan Aug 26 '16 at 15:28
  • https://src.chromium.org/viewvc/chrome/trunk/src/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_bind_uniform_location.txt Updated link for @Litherum's comment. That link seems to be broken. – Sahil Singh Sep 15 '19 at 10:31
11

The third option, ie layout(location=0) in vec4 position; in the shader code, is now available in OpenGL ES 3.0/GLSL 300 es. Only for vertex shader input variables though.

lane
  • 633
  • 12
  • 18
  • 7
    As they hint, Intel cards may not support this (while being perfectly 3.0+ comformant otherwise, as I get it), which is disgusting :) – mlvljr Aug 09 '14 at 21:35