VAO usage pattern


Lately, I’ve been pondering on the intended usage pattern of Vertex Array Objects (VAO). Clearly, their intent is to “batch” multiple calls to glVertexAttribPointer() for meshes with many attributes.

For now, I’ve been considering to create a VAO for each individual mesh/shader combination because different shader programs may require a different set of vertex attributes to be enabled. This will likely result in a large number of created VAOs and I’ve read reports of users telling that this results in a performance hit on certain driver implementations.

Another option would be to create a single VAO per mesh and use the same VAO across all shader programs. My concern with this approach is that some attributes may be enabled while they are not required by the shader. The specification is rather vague about the actual behavior of unused yet enabled attributes and I suspect that the details of how to deal with this is left to hardware vendors. I fear I may run into performance/compatibility issue if I follow this path.

Of course, it would be possible to enable/disable individual vertex attributes on the VAO slightly before invoking a “draw” command, but then, VAO lose their primary purpose of “doing everything in a single bind() call”.

Thus, I would like to have some recommendations regarding VAO usage and how I can expect them to behave under the two different paths (ie: 1 VAO per shader/mesh combination & 1 VAO per mesh with unused but enabled attributes). Which option is more reasonable?

Thanks for your help,

glGetActiveAttrib should only show attributes the shader uses. I always assume that the shader’s in charge of what’s fetched from the attributes, not the current enabled state of them. Having said that, if you interleave your attributes then you’ll pay for fetching redundant data regardless of enable states as the fetches are aligned to 32 byte chunks from what i gather.

Thanks for the clarifications.

I currently use one VAO per vertex format. VAO mostly contains buffer pointers, which are just offsets when using buffer objects, and these offsets depend on the vertex format.

I also tend to put meshes that share the same vertex format to a single vertex buffer object, so I have less changing buffer objects.

I use the BaseVertex() variant of glDraw commands. This way there is no need to remap vertex indices when sharing multiple meshes in vertex buffer object, and there is less issues running out of vertex indices.

I keep track of the currently bound VAO, vertex buffer object and index buffer object, so I avoid no-change calls to OpenGL.

For each mesh I use the same vertex buffer and thus effectively same vertex format for all shaders, even when they use varying subsets of vertex attributes. All my vertex formats are interleaved, so there is slight overhead when shader does not consume all of the attributes. But I think this is better than non-interleaved vertex buffers or creating duplicate versions with attribute subsets.