PDA

View Full Version : glVertexAttribPointer + GLSL + Ati = grr



RickA
09-04-2006, 09:28 AM
I'm trying to create a renderer using only the generic vertex attribute submission functions and GLSL. By all accounts this should be possible.

However, I've run into problems on Ati cards. First the code:
App:

virtual bool Render(const Scene& scene )
{
prog.Bind();
Clear();

CUSTOMVERTEX *data = new CUSTOMVERTEX[scene.numVertices];

std::copy(scene.data, &scene.data[scene.numVertices], data);
data[1].x = 0.1;

glEnableVertexAttribArray(prog.GetLocationOfAttrib ("color"));
glEnableVertexAttribArray(prog.GetLocationOfAttrib ("pos"));
glVertexAttribPointer(prog.GetLocationOfAttrib("color"), 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(CUSTOMVERTEX), &scene.data[0].color);
glVertexAttribPointer(prog.GetLocationOfAttrib("pos"), 3, GL_FLOAT, GL_FALSE, sizeof(CUSTOMVERTEX), &data[0].x);
//glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(CUSTOMVERTEX), &scene.data[0].x);
glDrawArrays( GL_TRIANGLES, 0, scene.numVertices );

delete [] data;

return true;
}Vertex shader:

attribute vec3 pos;
attribute vec4 color;
varying vec4 colorI;
void main()
{
colorI = color;
gl_Position = gl_ModelViewMatrix*vec4(pos, 1);
}Fragment shader:

varying vec4 colorI;
void main()
{
gl_FragColor = colorI;
}Now on nVidia cards this works just fine. On Ati cards I need to uncomment the line with glEnableClientState(GL_VERTEX_ARRAY);
The code then does work. The position is indeed sourced from the altered copy and not from whatever goes into glVertexPointer.

What am I missing?

A copy of my program can be downloaded here (http://www.daedalus-development.net/ricka/dllrender.zip) . If anyone with an Ati card can get something other than a black screen when running the OpenGL2.bat file, please let me know. The other profiles show the same scene running in different renderers.

Edit: after a suggestion on GameDev that I check the locations it turns out that that was the problem. pos was at location 2, and color at location 1. Since I wasn't assigning anything to position 0, that appeared to break. By setting pos to location 0 explicitly before linking, the program does work on Ati cards.

Now my next question: is this all expected behaviour according to the spec. If pos and color are at location 2 and 1, then what is at location 0? I assume vertex position, but gl_Vertex isn't used.

Komat
09-04-2006, 10:53 AM
The generic vertex attribute 0 is special one according to the OGL specification. For example specifying it using the glVertexAttrib{234} call has the same effect as calling glVertex{234}.

Additionally the definition (Chapter 2.8, page 27 of OGL 2.1 specification) of the behaviour of ArrayElement (which is part of definition of DrawArrays function) contains following code:


if (generic attribute array 0 enabled) {
if (generic vertex attribute 0 array normalization flag is set, and type is not FLOAT or DOUBLE)
VertexAttrib[size]N[type]v(0, generic vertex attribute 0 array element i);
else
VertexAttrib[size][type]v(0, generic vertex attribute 0 array element i);
}
else if (vertex array enabled) {
Vertex[size][type]v(vertex array element i);
}Based on this code it looks that if you do not enable generic attribute 0 or vertex pointer array, the vertex position is not specified and because none from commands that issue vertex is called, nothing should be rendered.

EDIT: Clarified

Komat
09-04-2006, 11:17 AM
It seems to me that in this case the ATI driver behaves more to the spec by not issuing any vertices into rendering.

If you enable the vertex array, the vertex issuing is enabled (even if your shader ignores the vertex position completelly) any you see geometry that uses data from other generic attributes.

RickA
09-04-2006, 02:09 PM
After checking the code on nVidia hardware, it seems that on that hardware color is assigned location 1, and pos is assigned location 0. Thereby satisfying the 'upload data to location 0' requirement mentioned.

mjkrol
09-05-2006, 04:36 AM
Originally posted by RickA:
After checking the code on nVidia hardware, it seems that on that hardware color is assigned location 1, and pos is assigned location 0. Thereby satisfying the 'upload data to location 0' requirement mentioned. You just were lucky this time. Do not expect it to happen on other hardware or even on future forceware revisions.
If you do not explicitly bind an attribute to a slot, the linker does it for you. But it does not touch the slot 0. If you do not use gl_Vertex in a vertex shader, you *must* bind one of the generic attributes to slot 0 before glLinkProgram call is issued.

RickA
09-06-2006, 01:37 AM
Does this also mean I should do the glVertexAttribPointer for whatever attribute is at location 0 last?

Relic
09-06-2006, 02:16 AM
No, it's only important that the vertex array set you use is completely defined when issueing the rendering call.

Korval
09-06-2006, 11:10 AM
If you do not use gl_Vertex in a vertex shader, you *must* bind one of the generic attributes to slot 0 before glLinkProgram call is issued.What is the point of making the user perform this kind of busywork? I mean, the driver knows at link time whether you've bound something to slot 0 or not. As such, it should therefore be able to bind one of the unbound ones to slot 0 so that you may have a valid rendering array set without doing any manual binding.

Komat
09-06-2006, 12:06 PM
Originally posted by Korval:
What is the point of making the user perform this kind of busywork? I mean, the driver knows at link time whether you've bound something to slot 0 or not. As such, it should therefore be able to bind one of the unbound ones to slot 0 so that you may have a valid rendering array set without doing any manual binding.
Problem is that the OGL specification does not specify (at least I found nothing about that) that automatic assignment will bind stream to attribute 0 so driver is free to not use it.

Actually the driver does not know at link time which attributes will be sourced per vertex from vertex arrays and which will serve as some form of low frequency constant trough glVertexAttribX() calls (even if application doing this without explicit binding of such attributes is asking for troubles) so that sort of fully automatic guaranteed assignment would be problematic to implement.

This might be the reason why the specification does not request that automatic binding will utilize attribute 0.

RickA
09-07-2006, 01:15 AM
Originally posted by Komat:

Originally posted by Korval:
What is the point of making the user perform this kind of busywork? I mean, the driver knows at link time whether you've bound something to slot 0 or not. As such, it should therefore be able to bind one of the unbound ones to slot 0 so that you may have a valid rendering array set without doing any manual binding.
Problem is that the OGL specification does not specify (at least I found nothing about that) that automatic assignment will bind stream to attribute 0 so driver is free to not use it.

Actually the driver does not know at link time which attributes will be sourced per vertex from vertex arrays and which will serve as some form of low frequency constant trough glVertexAttribX() calls (even if application doing this without explicit binding of such attributes is asking for troubles) so that sort of fully automatic guaranteed assignment would be problematic to implement.

This might be the reason why the specification does not request that automatic binding will utilize attribute 0. I don't quite follow this? Isn't it as simple as scanning the vertex shader for use of gl_Vertex? If there's no reference to gl_Vertex, then anything sent to the GPU with glVertexPointer won't be used, so location 0 is unused.

Komat
09-07-2006, 01:36 AM
Originally posted by RickA:
I don't quite follow this? Isn't it as simple as scanning the vertex shader for use of gl_Vertex? If there's no reference to gl_Vertex, then anything sent to the GPU with glVertexPointer won't be used, so location 0 is unused. There is no problem knowing if something is bound to location 0 at link time. Problem is with guaranteed selection of attribute that should be automatically bound at that position. Probably best solution would be if the Draw* calls required that vertex is issued regardless of what is bound where.

Overmind
09-07-2006, 09:18 AM
The problem is not deciding if something should be automatically bound to 0, the problem is deciding *what* should be bound to 0.

Just imagine someone will use immediate mode rendering, then it will make a huge difference which attribute gets the index 0. Assume the driver decides to use an attribute that is only updated every 10 vertices.

Better let the user decide such things, there is no way for the driver to know the meaning of the attributes.

Korval
09-07-2006, 11:15 AM
Just imagine someone will use immediate mode renderingSee that? That right there.

That's why I can't wait to get the new object model/new API, so I can see legacy crap that like that go away, and take the bad design (the concept of an index 0 being "special") with it.

V-man
09-07-2006, 12:40 PM
The problem is that he is using glVertexPointer.
You should either use Generic Vertex Attribute or not. You should also bind the attribute locations yourself.
The purpose of GVA is to forget about the predefined stuff of old fixed function days.
All you need to know is that attribute 0 is the trigger.

Overmind
09-07-2006, 12:50 PM
I don't like the idea of any single attribute being special. And I like the idea of the index 0 being special even less. But that's backwards compatibility...

So I'll stick to gl_Vertex/glVertexPointer until the new API arrives, then there won't be a need for a special "trigger" attribute.

mjkrol
09-08-2006, 03:01 AM
Originally posted by Overmind:
I don't like the idea of any single attribute being special. And I like the idea of the index 0 being special even less. But that's backwards compatibility...

So I'll stick to gl_Vertex/glVertexPointer until the new API arrives, then there won't be a need for a special "trigger" attribute. Okay, I see what you are trying to do. A very generic engine that takes a shader and queries for all the attribute names the shader exports. Then it loads some geometry that has multiple data streams with names assigned to them matching the ones from the shader. Finally, the engine sumbits those streams in a generic fashion, like VertexAttribPointer() or VertexAttrib(). Right?

All you have to do is pick an arbitrary attribute - let it be the first returned from query - and bind it to slot 0. It can be any of them, because GL does not understand the notion of attribute frequency in arrays. Then link the program.
And now, if you use GVA, submit attrib pointers in any order and then Draw*(). It is that simple. If you use immediate mode, remember to submit the attrib 0 last. Period.

The requirement of explicitly binding to slot 0 is here because of the immediate mode mess as Overmind stated. If you don't mess around with it, the attribute 0 loses its special value.

Overmind
09-08-2006, 07:20 AM
Attribute 0 loses it's special meaning when you're using vertex arrays exclusively, but it still has to be there.

I was more or less saying, I can't wait for OpenGL 3.0, because then we won't have to care about all this because there (hopefully) won't be any integer index in the API at all, not even a special one like zero :p

V-man
09-09-2006, 07:59 AM
Also if you use fixed functions, the driver needs to know which GVA is the vertex, which is texcoord, ...
so it becomes necessary to predefine the indices (0 = vertex).

When you just use GVA and shaders, we should be free to not use GVA 0

Komat
09-09-2006, 06:09 PM
Originally posted by V-man:
Also if you use fixed functions, the driver needs to know which GVA is the vertex, which is texcoord, ...
Fixed function does not use generic attributes other than 0 (which is explicitly specified as being equivalent of vertex position) in any way.

V-man
09-10-2006, 06:52 AM
Right. In a way it's important to have index 0 as vertex so that we could use ftransform() unless if they want to introduce a new function like glThisGVAIndexIsMyVertex(int index)