Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 5 of 5

Thread: Adding new vertex data to a vao

  1. #1
    Intern Newbie
    Join Date
    Nov 2011
    Location
    Surrey
    Posts
    31

    Adding new vertex data to a vao

    Hi

    I have a single VAO for my scene and the render cycle iterates through some draw commands. There is a vertex buffer bound to the VAO (as well as other buffers) and everything renders fine. I'd now like to add an object/s which means the render cycle needs to be extended and the new vertex data needs to be loaded in to the GPU.

    What is the most efficient way of doing this? I know I can't extend the buffer, I need to create a new one if I need a larger buffer. But i feel like I am missing a good technique of doing this.

    An example of what I am asking is as follows. I have a UI and I want to display a list of data (assume each row is a collection of triangles forming quads for font letters, aka text) that is not known and could change at run time. I also might want to add a new row at runtime.

    Thanks

    Peter

  2. #2
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,975
    Quote Originally Posted by bobtedbob View Post
    I know I can't extend the buffer, I need to create a new one if I need a larger buffer. But i feel like I am missing a good technique of doing this.
    If you can determine an upper bound on the amount of data, allocate the buffer at that size. Even if the upper bound is a significant proportion of your total video memory, it's better to know that up front than to run out of memory at some arbitrary point in the future.

    If you can't determine a bound, double the size of the buffer each time you need to enlarge it, and copy the data from the previous buffer with glCopyBufferSubData(). Increasing the size by a constant multiple each time ensures that the overall time taken is proportional to the total size (n+n/2+n/4+n/8+...=2n). Increasing by a constant amount results in the time being quadratic in the total size (n+(n-k)+(n-2k)+...+2k+k=n(n+k)/2k). C++ containers such as std::vector and std::string use this approach.

  3. #3
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    4,542
    Quote Originally Posted by bobtedbob View Post
    There is a vertex buffer ... as well as other buffers ...
    I'd now like to add an object/s which means the render cycle needs to be extended and the new vertex data needs to be loaded in to the GPU.

    What is the most efficient way of doing this? I know I can't extend the buffer, I need to create a new one if I need a larger buffer.
    One technique for implementing this is the one you're onto: that is, let each object that you're drawing have its own dedicated spot in GPU memory. Typically folks start with thinking they need a separate buffer object for each vertex attribute for each draw call. Then they learn about vertex attribute interleaving, and decide that they can have a single buffer object per draw call. Later you realize that that's inefficient and doesn't support dynamic updates very well. So you start grouping things, by having "big" buffer objects that you place the vertices for many draw calls. That helps your efficiency, but it's still a bit of a pain when you try and figure out how to do dynamic updates. You end up with fragmentation, block usage tracking, hole fitting, possibly compaction, needing to grow your buffer space, etc. In other words, complexity.

    That tends to suggest using another technique: just have one big buffer object that you fill and use as a ring buffer (fill/draw/fill/draw/fill/draw/...). Each time you draw, if the vertex data is already in the buffer, you just skip the fill step, point the GPU to it, and issue the draw call (draw/draw/draw/...). Once the buffer fills up, you just start over. This is the Streaming Buffer Object concept. Hi performance, and no memory management/fragmentation issues to deal with. To implement these techniques, read: Buffer Object Streaming in the wiki. There are a number of variations of this technique, but that's the jist of it. For one variation, see this 2014 presentation: Approaching Zero Driver Overhead. Search down to Dynamic Streaming of Geometry and read on.

    One thing you may already realize. There's nothing about buffer objects that says they can only contain one type of data (e.g. vertex attributes, index data, indirect command buffers, etc.). It's just a hunk of bytes. You can pack all of that in one buffer object end-to-end. Just point the GPU vertex attributes to the vertex attributes data, the GPU index list to the index data, etc. and everything works just fine with one buffer object. Less buffer objects to have to manage is a good thing.
    Last edited by Dark Photon; 11-07-2018 at 08:06 PM.

  4. #4
    Intern Newbie
    Join Date
    Nov 2011
    Location
    Surrey
    Posts
    31
    Thanks for both replies, this has open me up to a whole load of new options. Would I be right in saying the persistent mapped buffer solution with the fencing etc is similar to what vulkan makes you do? I'm going to research those topics more in the links Dark Photon provided

  5. #5
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    4,542
    Quote Originally Posted by bobtedbob View Post
    Would I be right in saying the persistent mapped buffer solution with the fencing etc is similar to what vulkan makes you do?
    Re fencing and suballocation, yes. Re persistent maps ... it doesn't really make you use it that way, but with Vulkan maps persistent by default (AFAIK) it certainly does encourage it.

    While you could have the GPU render from device memory not visible to the host and use a staging buffer to transfer data into it from the CPU (something OpenGL does in some cases but hides from you), that's extra copies and extra synchronization that's probably needless in most cases.

    Buffer maps in Vulkan aren't coherent by default though, so you still need to request that if you want it or manage the flushing yourself (similar to OpenGL).

    Check it out here:

    Last edited by Dark Photon; 11-08-2018 at 06:47 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •