generic vertex attribs and display lists

I am trying to offer support for generic attributes in display lists. Problem is, display lists dereference vertex attributes at compile time, including their location indices.

In the non-display list path, I do the following:-

1. render mesh...
1.1 query the currently bound shader.
1.2 if this mesh hasn't encountered this shader before...
1.2.1 enumerate the shaders active attributes (names/types/size etc.).
1.2.2 for any attributes that match the meshes attributes, I get their location and cache it as a coupling structure between the mesh and that particular shader.
1.3 fetch the coupling structure for this mesh/shader combo.
1.4 bind the attributes to the cached location indices.

So the mesh has a unique location list for each shader its rendered with.
But that isn’t possible with display lists. I’d have to have a unique compilation of the display list for each shader.
Is there any way around this? another design pattern perhaps?
Thanks for any help offered.

one solution I can think of, which isn’t very pleasant, is to have multiple copies of the shader with attribute locations overridden by the mesh I’m using it with.

1. compile display list.
1.1 bind all attributes to an incrementing attribute slot index.
2. render display list.
2.1 query the currently bound shader.
2.2 if this shader hasn't encountered this sequence of attributes before...
2.2.1 compile and link the shader.
2.2.2 enumerate the shaders active attributes (names/types/size etc.).
2.2.3 for any attributes that match the meshes attributes, forcibly change the shaders attribute locations to match the location compiled into the display list.
2.2.4 compile and link the shader under a new shader handle.
2.2.5 cache the new shader handle.
2.3 fetch the correct shader handle for this display lists sequence of attributes and bind it.

Not very nice at all. Oh dear.

Why so complicated? Which kind /number of attributes are you working with?

I chose to use fixed locations (i.e. vertex position will always have location 0, normals have 1, tangent/bitangent use 4/5 etc.).
Works well for me…

thanks for the reply, skynet.
yes, I see what you mean and I have used that system in the past.
I’d like to be a bit more flexible, so that whatever project comes through the door we can knock up a sensible mesh/material system without resorting to attribute hijacking (e.g. putting some interpolated value in texcoord4 followed by a comment saying what it really should be interpreted as by the reader).
The system is there in the API. Attributes have names, there’s a fair few entry points for supporting this system. It works perfectly if you’re not using display lists.
But you’re right, it does look like it’s going to get complicated with display lists. A real pity.
Some attributes that have cropped up in projects in the past: tree bend factor, terrain gradient coordinates, ambient occlusion factor, water density…that kind of thing. Project specific per-vertex values. Like I say, they’ve always had to be aliased to texcoord7 or colour1.

Ah, I see - too many (possible) attributes to give them all a distinct locations. But in the end, you can’t use them all at once anyway… so there should be a mapping where some attributes alias, but it doesn’t matter because the are never used together at the same time.

Maybe you could use fixed locations that are per-project, runtime-configurable (via config script or so):

“occlusion factor = 2”
“water_density = 3”

Is ‘classic’ aliasing with built-in attributes still a problem today? I mean, you probably use glVertexAttribPointer everywhere and no FFP anymore…

thanks again, skynet.
well, yes, your solution of a global aliasing config would work…but it’s not very elegant is it? I want to avoid the possibility of things going wrong for the end user (usually other developers). Having an aliasing clash in a global config could be difficult to diagnose.
I do use the FFP where ever possible (on engineering models where there’s no need for anything other than the fixed function lighting model - highly tessellated with no textures, let alone normal maps). We work almost exclusively with NV Quadro’s, and they appear to still have the FFP in silicon. I get about 30% better performance when using the fixed function compared to using a shader. Even a very simple pass through shader.

I’m thinking of just having a rule, like you suggest.
I’ll have a list of attributes that will be my “built in” attributes (hard-coded, no config file). I will force the locations of these attributes when building a shader, and when building a mesh. Any other attribute used in a mesh will not get compiled into a display list, and will therefore not get picked up by the shader that uses it.
Seems a reasonable compromise, considering we only need display lists for the intensive engineering models which tend not to use shaders anyway.
Anything that does use shaders and project-specific vertex attribute names will just run slower because they won’t be in display lists.

BTW, just to confirm what I know is correct, I will basically have to link the shader twice when I build it? Link once so I can query the active attribs, then link again after I’ve forced them to specific locations? Seems like madness to me. Not sure what I’d have done differently if I were the ARB though.

You don’t need to link twice. You may call glBindAttribLocation before linking the program:

BindAttribLocation may be issued before any vertex shader objects are attached
to a program object. Hence it is allowed to bind any name (except a name
starting with "gl ") to an index, including a name that is never used as an attribute
in any vertex shader object. Assigned bindings for attribute variables that do not
exist or are not active are ignored.

Well, if you are dependent on knowing the active attributes then yes, you probably need to link twice.

yes, the whole point of this is so I don’t have to know what string an attrib is specified with in the shader or the mesh. So long as they match, that is all that counts.
thanks for your ideas skynet, very much appreciated. Talking about it definitely helped me straighten out a reasonable, albeit compromised design.