Buffer Streaming - What Behavior is Defined

Started by TeamworkGuy2, January 23, 2013, 16:31:42

Previous topic - Next topic

TeamworkGuy2

Consider a VBO containing interleaving vertices, normals, and UVs that model a bouncing slime blob.
Almost every vertex is going to change ever frame (a frame being a call to Display.update() which implies a platform dependent call to SwapBuffers()).
I would like to be able to update the VBO every frame with new data generated by the CPU (move data from application into VBO/VRAM).

I think, the idea is to give Open GL a buffer to render and never touch the buffer until we know that Open GL is done rendering it.
Approaches I've heard of include:

  • Ring of buffers (java-gaming.org link) where each primary buffer has 1-2 secondary buffers and the primary buffer is switched with one of the secondary buffers after each frame, this way one buffer is never touched more than once every second or third frame (the assumption being that Open GL will be done rendering the buffer by then).
  • Orphan a buffer after filling it with new data (opengl.org link) and hope that the driver reuses these orphaned buffers so that frame times are not weighted down by the driver freeing old buffers and allocating new buffers.
  • Vender specific synchronization/fence objects to ensure that certain areas of a buffer are done being rendered before writing to them again.

Thread on java-gaming.org with source code for mapping/updating a group of VBO's in a synchronized way http://www.java-gaming.org/topics/opengl-lightning-fast-managed-vbo-mapping/28209/msg/255584/view.html#msg255584.
Post on opengl.org about orphaning buffers with a call to glBufferData(null) http://www.opengl.org/discussion_boards/showthread.php/170118-VBOs-strangely-slow?p=1197780#post1197780.


Is it undefined behavior to [write to a buffer > call glDrawElements*() > call Display.update() > go back and write to the buffer again]?
Can I be sure that a buffer is done being rendered by Open GL once Display.update() is called and returns?  Can I be sure Open GL is done with a buffer after calling Display.update() two or three times?

If I am only trying to write and render a buffer once per frame, which buffer update approach should I use and what combination of parameter for glBufferSubData() vs glMapBufferData() vs [something else] should I use?

Feel free to ask for code, more specific question, etc.  This question may be too broad/generic or I may not be communicating it clearly :)

spasi

Quote from: TeamworkGuy2 on January 23, 2013, 16:31:42Is it undefined behavior to [write to a buffer > call glDrawElements*() > call Display.update() > go back and write to the buffer again]?
Depends on the method used to write to the buffer. On one end you have BufferSubData that will block if the buffer is still used by the GL. On the other end you have MapBufferRanged with the unsynchronized bit that will not block, but then you get undefined behavior without appropriate synchronization. In between there are other methods and that will block or not block, with varying degrees of synchronization/validation performed by the GL driver.

Quote from: TeamworkGuy2 on January 23, 2013, 16:31:42Can I be sure that a buffer is done being rendered by Open GL once Display.update() is called and returns?
No. SwapBuffers is an asynchronous call, just like every other GL call. Though it's often the point where the GL driver will decide to block (either because of vsync or because the CPU is sending frames faster than the GPU can process them).

Quote from: TeamworkGuy2 on January 23, 2013, 16:31:42Can I be sure Open GL is done with a buffer after calling Display.update() two or three times?
Yes. Most GL drivers use double-buffering, with triple-buffering being the worst case. You can safely (and asynchronously) mutate a buffer that's been rendered 2(3) frames ago. That's the reason Riven's code on JGO works.

Quote from: TeamworkGuy2 on January 23, 2013, 16:31:42If I am only trying to write and render a buffer once per frame, which buffer update approach should I use and what combination of parameter for glBufferSubData() vs glMapBufferData() vs [something else] should I use?
I'd say it depends on the amount of data. Riven's code is great if the dynamic data is relatively small. Because you have multiple copies in memory, the more data you need to update the more wasteful that technique will become (but still fast). For large models, I'd go with VBO orphaning, it's the best alternative.

Here are two PDFs that you may find useful:

- Asynchronous Buffer Transfers
- Don’t Throw it all Away: Efficient Buffer Management

spasi

Btw, any technique that relies on the CPU feeding the GPU with good performance will use double or triple buffering. That means that what's being rendered at the current frame will always lag behind what's being calculated on the CPU. The only way to get both good performance and latency-free rendering is to do the updates on the GPU. For models that means skeletal animation, for particle systems doing it all in a compute shader or OpenCL kernel, etc.

TeamworkGuy2

Thank you for the quick reply and information Spasi, you answered exactly what I was asking.
I had time to look at the PDFs and they were both very informative.
Thanks for your time :)