6
\$\begingroup\$

I'm aware it's not a simple yes/no question and for the moment I can't tell if it can be simply answered, or is it a topic for a long discussion which is not suitable for our Q&A format.

I want to do some VBO management in order to reduce calls to GL.

I have 4 VBOs for all meshes:

  • one for static draws
  • one for dynamic draws
  • one for stream draws
  • one for indices

I want these four to handle my whole scene - this is going to reduce calls to glBindBuffer.

My mesh object consists respectively of static part, dynamic part and stream part, each of the part is specified by vertex specificator that is created at runtime, just by pushing back attribute objects containing size/type/offset to a member vector.

Based on the vertex specificators you can fill the parts with interleaved data, you don't have to do this for all the parts though. As I read here, separating vertex parts with different usage modes is good as it allows you to update all the dynamic/stream data at once without ever touching the static data. For example, doing particle simulation I may not be necessarily interested in streaming texture coordinates - changing vertex positions may be enough.

What's going to happen next:

  1. sort all mesh objects by the vertex specificator of its static part
  2. upload all the meshes' static parts' vertex data in obtained order to the static VBO
  3. sort all mesh objects by the vertex specificator of its dynamic part
  4. upload all the meshes' dynamic parts' vertex data in obtained order to the dynamic VBO

... and so on.

In short, static/dynamic/stream chunks (each in one of the 3 VBO's to which it belongs) with the same vertex types will be next to each other, and this is going to reduce calls to glVertexAttribPointer. Here I will need to smartly organize meshes that may want to use various parts, and then implement kind of lazy binds, probably if mesh needs to call glPointer for two different VBOs (separate static and stream parts for example), check if one of them is not already bound and call corresponding glPointer first.

Of course, each of the big batch obtained that way will then be sorted inside on the level of draw calls to reduce switches of shaders, textures and so on.

In short, this is my idea:

enter image description here

Although such a case may be uncommon, it's just to illustrate what should my mesh organizer be able to deal with.

Well, now it's only a plan and I haven't yet implemented it but..

How do the modern, high performance engines do their VBO and gl*Pointer state management? Is there something wrong with my concept, or am I totally misguided? Google results for VBO management and similiar tend to give me topics where people are asking for help because their programs crash, or just usage examples that tell nothing about optimizing my rendering procedures on VBO level but just "avoid redundant calls to GL", or some actual one-line tips (like glBufferData with NULL). So what I've described above is what I've concluded myself using those informations and I'm not sure if I am even on the right path.

Could somebody show me some good and actually proven practises managing VBOs in big 3D scenes, or maybe guide me a bit if I am actually reasoning right ?

\$\endgroup\$
4
  • \$\begingroup\$ There are no good and proven practices with regard to buffer object management in big 3D scenes. Because, by and large, games don't use OpenGL. The best you're going to be able to get is to just do whatever the most recent open-source IdTech engine does. And even that is only valid for rendering that kind of scene. \$\endgroup\$ Commented Aug 10, 2012 at 14:23
  • \$\begingroup\$ @NicolBolas I agree that most AAA games use D3D but even Valve started to port their games to OpenGL. blogs.valvesoftware.com/linux \$\endgroup\$ Commented Aug 10, 2012 at 15:05
  • \$\begingroup\$ Anonymous: they're just using a d3d wrapper around OpenGL. The programming API their devs use is still d3d. Valve also of course only has a single primary scene layout on their ported games (fpses so far) so their optimization techniques are still very genre specific. \$\endgroup\$ Commented Aug 24, 2012 at 21:59
  • \$\begingroup\$ then good thing I'm actually interested in fps'es, too. \$\endgroup\$ Commented Aug 24, 2012 at 22:29

1 Answer 1

7
\$\begingroup\$

This answer is more or less in flux, due to the recent advent of this.

In general, what you want to avoid is calling glVertexAttribPointer wherever possible. There are several tools for this; the biggest is the use of BaseVertex indexed rendering. This allows you to put multiple models into the same buffers, with the same vertex formats. Then, you draw each one with a glDrawElementsBaseVertex call, updating the base vertex and the index buffer offset.

Naturally, this requires that many of your models share a vertex format: they take the same attributes, stored in the same order, with the same offsets and strides. You should strive to have relatively few different kinds of vertex formats.

Thus, you have a few large arrays of vertices, all of the same format, which your BaseVertex and index lists select individual meshes from.


Vertex attrib binding brings with it entirely new ideas, the specific performance of which are not entirely clear. However, since vertex attribute binding is taken almost verbatum from Direct3D's concept of vertex formats and streams, it is useful to look to that API for guidance.

There, a vertex format is an immutable object. You create a format, and that's the end of it; it cannot be changed or modified. This suggests that there is a significant cost associated with changing vertex formats. Indeed, when NVIDIA was coming up with bindless vertex transfer, they took the opportunity to do something very similar: separate the format from the buffer that provides it.

Therefore, a reasonable suggestion is to follow D3D conventions: set the format once for a VAO and don't touch it. Just change the buffer binding with glBindVertexBuffer (the equivalent functionality in D3D is mutable).

\$\endgroup\$
3
  • \$\begingroup\$ +1, I didn't know about any of these, it sounds very interesting. Looks like I should become more familiar with GL 3.0+ capabilities. Could you please, by the way, elaborate the thought "by and large, games don't use OpenGL" in relation to "big 3d scenes" ? Did you mean that D3D is actually better/faster than OpenGL at rendering hundreds of thousands, or maybe millions of triangles ? \$\endgroup\$ Commented Aug 10, 2012 at 17:41
  • \$\begingroup\$ @geneotech: I meant exactly what I said: OpenGL, by and large, is not used for such things. Because most games are written in Direct3D. It's not that OpenGL isn't capable of it; it's that OpenGL simply isn't used in high-end games nearly as often as D3D. \$\endgroup\$ Commented Aug 10, 2012 at 17:52
  • 1
    \$\begingroup\$ and that's why there are no proven practices(...). Alright, now I've got your point. \$\endgroup\$ Commented Aug 10, 2012 at 18:06

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .