1
\$\begingroup\$

I'm learning OpenGL and I haven't seen any advice on managing vertex buffers in all of the tutorials I've read.

The basic problem is that I have some memory allocated as a buffer B in which I'm going to store vertex data to send to the graphics card.

Then I have the data that represents my domain D. This is the data that the game's simulation is run against. Let's say in a simple case it's just a list of 100,000 circles that will be moving around. Let's also assume that all of the data can, but might not, change every frame. Nothing is necessarily static.

I'm looking for the techniques people use to efficiently fill B with D.

I could create a new B each frame, but I imagine that would be very expensive.

I could give every object in D a pointer to a location in B and have it update that pointer directly, but that strikes me as error prone as then I have to manage all of these pointers.

I could also traverse D and fill a reused B every frame. This is what I'm currently leaning towards. The only problem here is that I'm forced to update every vertex in B every frame (because the location of the vertex data for a particular D could change within B) unless I come up with a more sophisticated scheme that guarantees that that an object in D always gets the same spot in B.

So I can think of several options, but I'm wondering what people typically do. I imagine almost everyone has to solve this problem at some point.

\$\endgroup\$
  • 1
    \$\begingroup\$ Your solutions get progressively less attractive to me, because each one suggests modifying part of a buffer that is more likely to be queued up for use in another command that has not finished yet (e.g. the frame the GPU is currently processing). That introduces implicit synchronization overhead in the driver to prevent modifying memory that has not been used yet. It sounds to me like you are looking for a general strategy for efficient buffer streaming, I do not know how technical you want to get with this, but you could start here. \$\endgroup\$ – Andon M. Coleman May 14 '14 at 22:04
  • \$\begingroup\$ I suppose the answer is that I want to get as technical as I need to. Thanks for the link. I read it and some other related sites and I think I understand what you're saying. I don't want to modify the buffer with new data, because I have to wait for OpenGL to be done with it, meaning I can't update/render in parallel. Does that mean that creating a new buffer every frame is really my best bet? Should I create a set of buffers and cycle through them? The site you linked me to lists downsides for all of its proposals. Is there no commonly accepted solution? Is it unique to every application? \$\endgroup\$ – Twernmilt May 14 '14 at 23:30
  • 1
    \$\begingroup\$ Very generally, if you read that link in the order it is written, each of the things introduced requires a newer and newer version of GL. Buffer orphaning (creating a new buffer data store each frame) or multi-buffering are the most portable. Multi-buffering is difficult to implement correctly though, because it is hard to know for sure how many frames worth of data updates are still pending - NV often suggests using 3 buffers as a minimum (1 for active GPU execution, 1 for a queued frame and 1 for the frame the CPU is currently setting up). \$\endgroup\$ – Andon M. Coleman May 14 '14 at 23:53
  • \$\begingroup\$ I always find relevant knowing how successful games do it. Take a look at the source code of Doom3, they have a double buffered "VertexCache": github.com/id-Software/DOOM-3-BFG/blob/master/neo/renderer/… \$\endgroup\$ – glampert May 15 '14 at 3:19
0
\$\begingroup\$

Based on what I know from reading, your best bet is fully orphaning the buffer each frame and filling the entire thing. As far as how you architect your rendering engine, it depends on the scene. To use your example, if all you're drawing is 100,000 circles, you're best off having D be stored in a format that can be written directly to B and used for instanced rendering.

In any case, you should be trying to reduce the time it takes to translate D to B as much as possible. I would suggest architecting D in a data-oriented way - contiguous and using a structure-of-arrays design rather than array-of-structures - so that you can boil it down to a few straight memcpy()'s.

\$\endgroup\$
  • \$\begingroup\$ Thanks for the advice. It sometimes feels like a shame that efficiency concerns seem to end up controlling the entire structure of your data model in real time games. Also, full disclosure, I'm doing this all in Haskell (although I end up using plenty of FFI down to C). \$\endgroup\$ – Twernmilt May 15 '14 at 18:25
  • \$\begingroup\$ I don't know if there's really much you can do to alleviate the costs of translating what I'm assuming is fragmented heap memory from Haskell into contiguous memory required by OpenGL, other than writing a backend in C/C++ and using Haskell as a sort of scripting or glue language. \$\endgroup\$ – jmegaffin May 15 '14 at 19:55
  • \$\begingroup\$ Haskell's support for contiguous arrays of memory is actually quite good. \$\endgroup\$ – Twernmilt May 15 '14 at 20:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.