VAO vertex buffers Topic is solved

Problems building or running the engine, queries about how to use features etc.
User avatar
bishopnator
Goblin
Posts: 299
Joined: Thu Apr 26, 2007 11:43 am
Location: Slovakia / Switzerland
x 11

VAO vertex buffers

Post by bishopnator »

Ogre Version: :?: 3.0
Operating System: :?: Win11
Render System: :?: D3D11 and GL3+

What are the rules with creating vertex buffers stored in VAO? VAO can hold multiple vertex buffers and each vertex buffer can contain vertices with multiple vertex elements.

Is it valid to have VAO with e.g. 1st VB with vertex elements A+B then 2nd VB with vertex elements C+D+E and 3rd VB with just a single vertex element F? Or it is actually either a single VB with A+B+C+D+E+F or 6 VBs and each holds only a single vertex element?

Are there any restrictions due to render systems? Is it still necessary to order the vertex elements in certain order like it was in DX9? Or in D3D11 and GL3+ it doesn't matter anymore?

I need to add custom vertex element (like TEXCOORD4) to an existing mesh loaded from mesh file. It has all vertex elements packed within a single VB and I can create new VB with added element, copy the old vertex buffer with adding new values to the vertices or I can just create new vertex buffer and simply add it to the VAO (so there will be original VB with position+normal+uv0) and my newly added vb which stores uv4.

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5433
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1341

Re: VAO vertex buffers

Post by dark_sylinc »

Hi!

It is actually either a single VB with A+B+C+D+E+F

Yes. For v2 meshes, it is a single VB with A+B+C+D+E+F.
For v1 meshes, any arbitrary combination is possible (e.g. 3 VB with A; B+C+D; E+F).

This limitation is imposed by OgreNext and not by the RenderSystems, which comes from our ability to do multi-mesh instancing via some baseVertex and baseInstance tricks (basically boils down to APIs allowing us to specify a different buffer offsets; and that's how multi-mesh instancing works).
If we were only to target Vulkan & D3D12 perhaps we could make this restriction go away, but even then it is deeply in-grained into OgreNext right now.

This is a controversial choice because there are a few reasons to use multi-buffer meshes(*).

There was some WIP createMultiSourceVertexBufferPoolImpl which was in theory designed to allow multi-vertex buffer v2 VAOs. But it was never completed. It was too difficult to get it to work with baseVertex/baseInstance and there was no interest for it.

(*) One of those reasons is shadow map rendering (e.g. putting the poisition data in its own buffer) but we workaround that by cloning the vertex & index buffer, stripping it of irrelevant data (like UVs and normals) and then merging all redundant vertices. That's why you'll see we have 2 Vaos per Mesh (VpNormal and VpShadow) and they can either be the same VAO (i.e. no clone and stripping) or different VAOs (cloned and stripped).
VertexShadowMapHelper can automatically perform this operation for you.

I need to add custom vertex element (like TEXCOORD4) to an existing mesh loaded from mesh file. It has all vertex elements packed within a single VB and I can create new VB with added element, copy the old vertex buffer with adding new values to the vertices or I can just create new vertex buffer and simply add it to the VAO (so there will be original VB with position+normal+uv0) and my newly added vb which stores uv4.

A couple things:

1. We have functionality that helps dealing with this. See VertexBufferDownloadHelper.
You basically tell it what semantics you want them to download and returns you all the pointers to the data so that you can modify it.
Since you want to add a TEXCOORD (and you can't simply add a vertex buffer) you can use VertexBufferDownloadHelper to copy all data into a new, larger buffer and then add your extra data.

2. v2 VAOs vertex buffer order have no requirements and the order in which you specify the semantics are the order in which the elements must appear in the buffer.
The only gotcha is that:

  1. Internally OgreNext may assign some arbitrary number to them. For example in GL3+ vertex attributes map to a predefined number. See GL3PlusVaoManager::VERTEX_ATTRIBUTE_INDEX. However I don't see how you should have to worry or even know about this. It's an implementation detail.

  2. In GL3+ we map VES_BINORMAL to vertex index 16. This may not work on some GPU/drivers that advertise 16 slots (i.e. slots 0 through 15). Just use something else, like VES_TEXTURE_COORDINATES. The details are explained in this comment.

Are there any restrictions due to render systems? Is it still necessary to order the vertex elements in certain order like it was in DX9? Or in D3D11 and GL3+ it doesn't matter anymore?

As far as the API goes, it doesn't matter anymore. What's way more important nowadays is that the vertex isn't fat. e.g. use half16 or unorm8x4/unorm16x2 when possible instead of float32. Try to make it as small as possible per vertex.

User avatar
bishopnator
Goblin
Posts: 299
Joined: Thu Apr 26, 2007 11:43 am
Location: Slovakia / Switzerland
x 11

Re: VAO vertex buffers

Post by bishopnator »

Thanks for very detailed explanation also including those helper classes - I was prepared to implement the functionality by myself. Just a side note that it would be great to consider for future release (not necessarily 3.0 or 4.0, but just to have it on roadmap) to update interface of the Ogre::Mesh (aka Mesh2) to clearly support only a single VB per LOD instead of having same interface as for Ogre::v1::Mesh.

With very minimal effort doable also in the current release, adding a comment like you wrote me, can be put somewhere in the source code so there is no change in API.

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5433
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1341

Re: VAO vertex buffers

Post by dark_sylinc »

bishopnator wrote: Sat Jul 20, 2024 8:29 am

Thanks for very detailed explanation also including those helper classes - I was prepared to implement the functionality by myself. Just a side note that it would be great to consider for future release (not necessarily 3.0 or 4.0, but just to have it on roadmap) to update interface of the Ogre::Mesh (aka Mesh2) to clearly support only a single VB per LOD instead of having same interface as for Ogre::v1::Mesh.

With very minimal effort doable also in the current release, adding a comment like you wrote me, can be put somewhere in the source code so there is no change in API.

OgreNext's v2 omterface definitely supports this. SubMesh::destroyVaos specifically considers the case where the same VB is shared to avoid double free.

I'm just not sure what the MeshLodGenerator Component is doing though.

User avatar
bishopnator
Goblin
Posts: 299
Joined: Thu Apr 26, 2007 11:43 am
Location: Slovakia / Switzerland
x 11

Re: VAO vertex buffers

Post by bishopnator »

Actually I meant, that in Ogre::SubMesh it is possible to assign whatever VAO you want - through VaoManager you can create vao with multiple vertex buffers. I tend to limit such things using custom types so the compiler already verifies the usage. Here for Ogre::SubMesh there should be custom vao implementation which can hold only a single VB and hence developer is forced to create such instance through VaoManager. Then all my questions would vanish automatically without any doubt.

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5433
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1341

Re: VAO vertex buffers

Post by dark_sylinc »

Actually I meant, that in Ogre::SubMesh it is possible to assign whatever VAO you want - through VaoManager you can create vao with multiple vertex buffers.

This is on... purpose?

It's possible to create a VAO that has no vertex & index buffer (e.g. Terra), a VAO that has no vertex buffer but has an index buffer (e.g. ParticleFX2 plugin); all thanks to gl_VertexID tricks being available to the vertex shader. For more info you can see the presentation and the video.

Even for traditional meshes, LOD VAOs that have independent vertex buffers have their value, as it allows for better cache utilization as the vertex data for each LOD is all close together.

The only limitation we have right now, because it was too difficult to address, is to have two LODs with different vertex semantics (e.g. LOD0 has tangents, LOD1 does not have tangents), because this would require two different shaders for the same SubMesh (e.g. LOD0 uses normal mapping, LOD1 has no normal mapping).

Although the theoretical benefit is alluring (progressively disabling detailed shader effects for higher LODs) it would mean too many indirections (which translates to slower performance and more code complexity) to hold an arbitrary number of Hlms hashes per Renderable in literally the hottest path.