The fastest way to download streaming points and sometimes delete

So, I have a system (using OpenGL 4.x) where I get a stream of dots (potentially with color and / or normal) from an external source. And I need to draw these points as GL_POINTS using custom switchable shaders for coloring (color can be generated using procedures or derived from vertex color or normal direction).

The flow consists of receiving a group of points (with a normal or color or without it) of an arbitrary count (typical from 1 to 70 thousand points) over a fairly regular interval (from 4 to 10 Hz), I need to add these points to my current points and draw all the points received so far.

I'm sure my vertex type will not change, they tell me at the beginning of the streaming that you can expect, so I either use a striped vertex with: pos + normal + color, pos + normal, pos + color, or just pos.

My current solution is to select alternating vertex VBOs (with surrounding VAOs) of the corresponding vertex type in the configuration file indicated by the maximum number of vertices (highlighted by the DYNAMIC hint).

As I enter new points, I populate my current unfilled VBO with glBufferSubData. I keep an account (activePoints) of how many vertices the VBO VBO border currently has and use glBufferSubData to fill the range starting with activePoints if my current update group has more vertices than can fit in my border buffer (since I limit the number of vertices on VBO), then I assign a new VBO and fill in the range starting from 0 and ending with the number of remaining points in my update group (not added to the last buffer), if I still have remaining points, I do it again and again. It is rare that an update group spans over 2 buffers.

When rendering, I displayed all of my VBOs (-1) using glDrawArrays (m_DrawMode, 0, numVertices), where numVertices is equal to the maximum size allowed by the buffer, and my border buffer with glDrawArrays (m_DrawMode, startElem, numElems) don't mind that completely filled with real peaks.

Of course, at some point I will have more points than online, so I have an LRU mechanism that overrides the oldest (according to LRU alg) VBOs sets as needed.

Is there a better way to do this? Buffer orphanage? Stream hint? Map vs SubData? Something else?

The second problem is that I am now being asked to delete points (at irregular intervals), starting from 10 to 2000 at a time. But these points are irregularly spaced in the order in which I received them initially. I can find out which offsets in which they are currently going out, but are more scattered than the range. I “deleted them”, finding their offsets in the desired buffers and one after the other, calling glBufferSubData with a range of 1 (which is rare in their buffer) and changing their place somewhere far away, they will never be visible. In the end, I think the buffers should be removed from this flushing of the delete request, but at the moment I do not.

What would be the best way to handle this?

+4
source share
1 answer

Mapping can be more efficient than glBufferSubData , especially when you need to “delete” points. Explicit flushing can be of particular help. In addition, the mapping allows loading buffer filling into another stream.
Be sure to get the access bits correctly (or the performance is terrible), in particular, do not display the “read” area if everything you do is writing.

Removing points from the vertex buffer is not as easy as you probably know. For "several" points (for example, 10 or 20), I would simply set w = 0, which will lead them to infinity and continue to draw everything as before. If your clip plane is not at infinity, it just cancels them. With explicit flushing, you don’t even need to store a separate copy in memory.
For "many" points (for example, 1000) you can use glCopyBufferSubData to remove holes. Moving memory to the GPU is fast, and for thousands of dots, it's probably worth it. Then you need to maintain a count for each vertex buffer, so after deleting some of them you get fewer points.

To “delete” all vertex buffers, you just need to overpower them (and reuse them). OpenGL will do the same on its own behalf, and this is the most efficient way to continue drawing and reusing memory.

Using glDrawElements instead of glDrawArrays , as suggested by Andon M. Coleman, is usually good advice, but it doesn't help you in this case. The reason I would like to do this is because the post-conversion cache works by marking the vertices by their index, so drawing elements take advantage of the post-conversion cache, while drawing arrays do not work. However, the post-conversion cache is only useful for complex geometries such as triangular lists or triangular stripes. You draw dots, so in any case you will not use a post-converted cache, but using indexes increases the memory bandwidth both on the GPU and on the PCIe bus.

+4
source

Source: https://habr.com/ru/post/1497677/


All Articles