I’m wondering if there’s a straightforward way to use a VBO as a queue for incoming data in OpenGL ES. Specifically, I’d like to generate a waveform, such as an ECG trace, that stores and renders the last 10K points on the line, with new points coming in constantly. I’d like to be able to allocate a single VBO for this line, and then for each new point (or set of points) that comes in, prepend that point to the front of the VBO, and shift all the remaining points down. It seems like there should be an easy way to do this, but I’m not seeing anything offhand that can shift data in a VBO. Is there a good, efficient way to do this?
My alternative, as I can see it, is to use the VBO as a circular buffer, and then render the “head” and “tail” of the line separately, but that just seems unnecessarily complicated for some reason. I feel like I’m missing some options. If VBO shifting isn’t possible, are there less complicated ways of achieving the same effect?
A circular buffer should work fine, and may not be as complex as you think. This is basically the way that DirectSound works, so it’s a valid and proven approach, and you might even be able to find some code to borrow from.
Let us know how you get on if you decide to do this; it seems an interesting thing.
Can you imagine the cost of effectively shifting all data points each time you add one ?
Rendering head and tail separately is only 2 draw calls instead of one.
Read this thread of interesting optimizations on VBO in “write only” mode (from the CPU side) :
You could even avoid the second draw call by storing only an index instead of the real position in the vbo, place the real positions in a 1d float texture that you update and pass an offset to your vertex shader to get the circular buffer behavior.
So your “position” for the i-th vertex is just (i, 0, 0) and you perform the texture lookup at (i+offset) to get the actual position. Frankly I don’t think this micro optimization will buy you much/anything performance wise, but thought I’d throw it out there.
I went ahead and implemented it as a circular buffer; not too hard. Had to add an extra point at the end of the buffer, and make sure buffer[N] always equals buffer, so that there wasn’t a hole between the head and the tail of the graph when rendering the pieces separately. I managed to wrap it up in its own class, so it’s fairly seamless to the end user, but still limited if you want to use a custom color buffer or something.
Mainly I figured that this might be a common-enough requirement that such a thing might already exist in the OpenGL standard or even in hardware.
I’m still doing ES 1.1, so no vertex shader yet, but I’ll try it if I upgrade, which may be pretty soon, as it could make things more flexible in terms of combining with other shaders a bit more seamlessly. Thanks!
I ended up doing something even simpler – created a static element array buffer = [0, 1, …, N-1, 0, 1, …, N-1], and then still use my dynamic vbo (of N elements) in circular buffer form using BufferSubData to buffer new data. Then, and instead of making two DrawArrays calls for the head and the tail and filling the hole between the two, I’m able to make one DrawElements call using my element array buffer as the index pointer, and (_totalPoints % N) as the offset, and that one call draws the whole line. Easy! Makes it much easier to match my color buffer to the correct points as well.