A doubt about ARB_vertex_program

I am working on a project which needs very clean geometry management. I decided to take this as a good chance to develop an API to wrap around some geometry-related OpenGL functionalities. This is definetly necessary to make project development easier.
Now, since the very beginning, I was very determined to pass per-vertex data using the interface defined by ARB_vertex_program. As I stated in a recent post in beginner’s forum, this allows more functionalities and also looks easier to implement. Having to call VertexAttribPointerARB(index, …) and EnableVertexAttribArrayARB(n) makes the code way better than having to choose what I am working and using a bunch of ifs to decide what function to use between ColorPointer, VertexPointer and stuff like that.

Now, ARB_vertex_program defines all the calls to VertexAttribPointerARB(0, …) to be equivalent to Vertex*(…). They both produce a vertex, no matter if vertex programs are enabled or not. Fine.
There are some references in the specification which says that aliasing between standard vertex attributes and generic vertex attributes can alias.
Building on the two things above, I was also thinking that EnableVertexAttribArrayARB(n) should be equivalent to EnableClientState, but looks like it is not.

glVertexPointer(vertexComponents, vertexFormat, vertexStride, vertexPointer);
glEnableClientState(GL_VERTEX_ARRAY);
glColorPointer(colorComponents, colorFormat, colorStride, colorPointer);
glEnableClientState(GL_COLOR_ARRAY);

After that, calling DrawElements produces the expected results - something is gettin rendered.

glVertexAttribPointerARB(0, vertexComponents, vertexFormat, vertexNormalize, vertexStride, vertexPointer);
glEnableVertexAttribArrayARB(0);
glVertexAttribPointerARB(3, colorComponents, colorFormat, colorNormalize, colorStride, colorPointer);
glEnableVertexAttribArrayARB(3);

Does not render at all.
I figured out there are two ways to make it work:
1- Enable vertex program mode and bind a decent VP. This is a quick and dirty solution.
2- Use standard attributes when possible - in the case VPs are enabled, they will override generic attributes and everything will go fine anyway.

I think using ifs to do (2) would be the better way however, I am not sure - this would require a lot of ifs in a performance path.

In other terms this means I can define a standard vertex attribute (example: color) to define a generic attribute (3), however, I cannot define a generic attribute (3) to define a standard attribute (color).
Since I am quite sure someone already figured out the best way wrap around that, I would like to get some advices on the topic.
Thanks.

>>In other terms this means I can define a standard vertex attribute (example: color) to define a generic attribute (3), however, I cannot define a generic attribute (3) to define a standard attribute (color).<<

Scrapped the previous answer.
The behaviour is described in the spec: http://oss.sgi.com/projects/ogl-sample/registry/ARB/vertex_program.txt

(5) This extension adds a set of generic vertex attributes to the existing
conventional attributes. The sum of the number of generic and
conventional attributes supported on a given platform may exceed the total
number of per-vertex attributes supported in hardware. How should this
situation be handled?

  RESOLVED:  Implementations may alias conventional and generic vertex
  attributes, where pairs of conventional and generic vertex attributes
  share the same storage.  Such aliasing will effectively reduce the
  number of vertex attributes a hardware platforms.  While implementations
  may alias attributes, that behavior is not required.  [b]To accomodate both
  behaviors, changing a generic vertex attribute leaves the corresponding
  conventional attribute undefined, and vice versa.[/b]

  This undefined behavior is a compromise between the existing
  EXT_vertex_shader extension (which does not permit aliasing) and the
  NV_vertex_program extension (which requires aliasing).  The mapping
  between generic and conventional vertex attributes is found in Table X.1
  below.  This mapping is taken from the NV_vertex_program specification
  and generalized to define behavior for &gt;8 texture coordinate sets.

  Applications that mix conventional and generic vertex attributes in a
  single rendering pass should be careful to avoid using attributes that
  may alias.  To limit inadvertent use of such attributes, loading a
  vertex program that used a pair of attributes that may alias is
  guaranteed to fail.  Applications requiring a small number of generic
  vertex attributes can always safely use generic attributes 6 and 7, and
  any supported attributes corresponding to unused or unsupported texture
  units.  For example, if an implementation supports only four texture
  units, generic attributes 12 through 15 can always be used safely.

[This message has been edited by Relic (edited 08-12-2003).]

Originally posted by Relic:
Scrapped the previous answer.

I was quite sure my post was unclear.
As you kindly pasted from the ext spec, changing a conventional attribute will override the generic attribute and vice versa.

I was hoping this would work also for vertex attribute arrays, but looks like it isn’t.

So, while VertexAttrib(0, …) is equivalent to Vertex(…), VertexAttribPointerARB(0, …) is not equivalent to VertexPointer(…).
This is not an idea, it’s a fact I tested today. Since it looked a bit strange to me, I wanted to share this also to get some feedback on it.
This means that while attributes will alias, attribute array bindings won’t.

It’s incredible how much I made up my mind in just a few hours… my previous post is useless at best.

Originally posted by Obli:
So, while VertexAttrib(0, …) is equivalent to Vertex(…), VertexAttribPointerARB(0, …) is not equivalent to VertexPointer(…).

If you replace all your Vertex(…) calls by VertexAttrib(0, …) calls, it will work absolutely the same way, but you might replace every “vertex.position” by “vertex.attrib[0]” in your vertex program string.

Ok thanks, I’ll have to keep this in mind when I’ll do vertex programs.

I decided to go straight for generic attributes only. They are way easier to use and this is important.
The side effect of not having support for fixed function vertex pipes is not significative.

I hope this post turns out useful to someone other in the future… it was one of the reasons that pushed me to post it.

Actually, this raises a question I’ve been wondering.

glColorPointer (and SecondaryColorPointer) are special to the rendering system. They are allowed to use unsigned bytes for their data types and still be optimizal (under VBO, for example).

Is there a way to get this functionality with the generic attributes? Can I make a generic attribute look like a color attribute?

Originally posted by Korval:
Is there a way to get this functionality with the generic attributes? Can I make a generic attribute look like a color attribute?

I call glVertexAttribPointerARB with type set to GL_UNSIGNED_BYTE and the normalized flag set to true instead of glColorPointer. Works fine. If it’s accelerated with VBO I cannot say since I haven’t done any benchmarking regarding this.

I think the optimization comes between vertex processing and fragment processing, and therefore has nothing to do with VBO. Radeon 9500s and better, for example, use 12 bit fixed point precision for colour interpolation. Presumably, it’s a bunch faster than interpolating using the GPU’s full 24 bit floating point precision (colour doesn’t need a high dynamic range anyway). Of course, a way to bench this would be to send colour from the vertex program to the fragment program as a texture coordinate (rather than as a colour).

Originally posted by Obli:
changing a conventional attribute will override the generic attribute and vice versa.

No, not overridden, but left undefined!
It’s implementation dependent, don’t rely on it.

I think the optimization comes between vertex processing and fragment processing

No, the optimization is specifically for vertex transfer. The optimized formats are either “floats” or “unsigned bytes for colors”. Anything else will result in unoptimal performance with VBO, VAR, or VAO.

[This message has been edited by Korval (edited 08-15-2003).]

I’ve run some tests (on a Radeon 9800 Pro with Catalyst 3.6 drivers), and with VBO, glColorPointer is much faster than glVertexAttribPointerARB with GL_UNSIGNED_BYTE. The performance in the latter case was equivalent to not using VBO at all (over 5 times slower in this case).

It’s implementation dependent, don’t rely on it.

Ah, I really missed this one (I forgot this is NV_vp specific hardware behaviour). Anyway it does not matter, I gone for generic vertex attribs only.

No, the optimization is specifically for vertex transfer

I don’t think so. By the way the fact implementations are encouraged to optimize floats and ubytes does not mean signed shorts won’t. They are just arrays of bytes after all. If ubytes are supported, I am quite sure clever driver engineers will find a way to support all the rest.

glColorPointer is much faster than glVertexAttribPointerARB with GL_UNSIGNED_BYTE. The performance in the latter case was equivalent to not using VBO at all

This is bad because from my experience using generic vertex attribs is much easier and a bit faster at run time. It’s a real shame this easier way does not get optimized.
Since this thing is somewhat worring, I will try to do a test on my app to see what happens. It will take at least some days since I’m doing other things right now but as soon as I’m done I’ll do it and I’ll post the results.

I don’t think so. By the way the fact implementations are encouraged to optimize floats and ubytes does not mean signed shorts won’t. They are just arrays of bytes after all. If ubytes are supported, I am quite sure clever driver engineers will find a way to support all the rest.

If the hardware isn’t designed to understand shorts, no amount of driver programming can get around that; if you don’t use shorts, the driver will have to convert the data itself. Just like if your CPU doesn’t understand 32-bit words, then 32-bit math will be slower than 16-bit math (assuming the CPU understands that).

This was referred to a pure data-transfer problem. Of curse if hw does not understand it then there’s bad troubles.