I have to draw a buffer that holds a couple thousand vertices. I am using a vbo to store the data.
I know I will have to update the VBO many times - but only in small parts at a time.
So I am wondering what the best method to doing so is:
Split VBO up into smaller VBOs (that hold like 300 verts) and then update individual VBOs with 1 call?
One big VBO and use lots of glBufferSubData() calls?
Use glMapBuffer() and one big VBO?
There is another option, which is a bit like option 3 - use one big VBO (probably with GL_STREAM_DRAW mode) that is reset each frame (by calling glBufferData with a NULL buffer pointer and the same size each time) then glMapBuffer-ed right away. The buffer is left mapped as it is filled in, then unmapped just before drawing. Repeat.
The call to glBufferData tells OpenGL that the old buffer contents aren't needed, so the glMapBuffer doesn't have to potentially wait to ensure the GPU is finished with by the GPU.
This approach seems to be the one officially sanctioned by the vertex_buffer_object extension. See the "Vertex arrays using a mapped buffer object" example:
http://www.opengl.org/registry/specs/ARB/vertex_buffer_object.txt
This suggests that OpenGL (or the driver?) will be watching for this sort of behaviour, and (when spotted) arrange things so that it is performed efficiently.
Doesn't sound like a good idea: it forces you to draw it in several calls while changing the bound buffer between each draw call.
Might do the trick if your buffer is huge.
The whole buffer will certainly be uploaded to the GPU. This will certainly be as efficient as one glBufferData, but you can do it asynchronously.
If think that glBufferData or glMapBuffer are the better solution if your buffer is small. 100000 * sizeof(float) * 3 ~= 1MB. There should be no problem with that.
Related
I am working with PointCloud data that I need to render using opengl. I get a new vector of data points every frame. I want that I be able to cache the data previously sent to opengl and only send the newest frame data to it. How can I do so?
I did some searching and found this idea here:
// Bind the old buffer to `GL_COPY_READ_BUFFER`
glBindBuffer (GL_COPY_READ_BUFFER, old_buffer);
// Allocate data for a new buffer
glGenBuffers (1, &new_buffer);
glBindBuffer (GL_COPY_WRITE_BUFFER, new_buffer);
glBufferData (GL_COPY_WRITE_BUFFER, ...);
// Copy `old_buffer_size`-bytes of data from `GL_COPY_READ_BUFFER`
// to `GL_COPY_WRITE_BUFFER` beginning at 0.
glCopyBufferSubData (GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, old_buffer_size);
But it looks like its finally sending previous and new data in the new buffer instead of caching and sending only the latest data. So I am not sure if its the best way. Please correct me if I am wrong or suggest alternative.
So you store some data in your CPU memory, and you append more data to this storage. Then you want to send only the appended data to GPU, not the whole buffer.
Your code example is irrelevant for this task, as glCopyBufferSubData copies data from a location in GPU memory to another location in GPU memory again.
You need a combination of glBufferData and glBufferSubData. glBufferData allocates memory in GPU and optinoaly initializes it. glBufferSubData writes some data to already allocated GPU buffer. You may treat glBufferData as C's malloc or C++ new, while glBufferSubData is like a special version C's memcpy or C++ std::copy. More precisely, glBufferSubData is memcpy from CPU to GPU, and glCopyBufferSubData is memcpy from GPU to GPU.
How to cook them together? The same way as in C. Call glBufferData once at initialization time (when program starts), and call glBufferSubData when you need to append data. Be sure to allocate enough space! A buffer allocated by glBufferData does not grow, as well as malloced buffer. Overflowing a buffer with glBufferSubData causes undefined behavior and may crash your application.
Try to predict space requirement for your buffer, and call glBufferData only if your data does not fit into the buffer.
Remember that calling glBufferData with already allocated buffer binding will deallocate existing buffer and create a new one.
glBufferSubData will not reallocate your buffer, but will overwrite data which is already there.
Let me illustrate it with C translation:
glGenBuffers(..., buf); // float* buf;
glBindBuffer(buf); // Tell opengl that we will use buf pointer, no analog in C.
glBufferData(/*non-null pointer*/); // buf = malloc(/*..*/); memcpy(to_gpu, from_cpu);
glBufferData(/*another non-null pointer*/); // free(buf); buf = malloc(/*..*/); memcpy(to_gpu, from_cpu);
glBufferSubData(...); // memcpy(to_gpu, from_cpu);
Ideomatic approach
What you need is:
glGenBuffers(..., buf); // float* buf;
glBindBuffer(buf); // Tell opengl that we will use buf pointer, no analog in C.
// Initialization
glBufferData(/*non-null pointer*/); // buf = malloc(/*..*/); memcpy(to_gpu, from_cpu);
// Hot loop
while (needToRender) {
if(needToAppend) {
if (dataDoesNotFit) glBufferData(...); // Reallocate, same buffer name
else glBufferSubData(...); // memcpy(to_gpu, from_cpu);
}
}
Here we reallocate memory only occasionally, when we need to append something and buffer is too small.
Other approaches
I advised to reallocate with glBufferData as you already have all data in a single buffer on CPU. If not (i.e. you have a chunk of data on GPU and another chunk on CPU, but not together), you could use glCopyBufferSubData for reallocating:
glBufferData(/*alloc new_gpu_buffer*/);
glCopyBufferSubData(/*from old_gpu_buffer to new_gpu_buffer*/);
glDeleteBuffers(/*old_gpu_buffer*/);
glBufferSubData(/*from_cpu_buffer to new_cpu_buffer*/)p; // Add some new data from CPU.
Another approach for updating GPU data is mapping it to CPU, so you just access GPU memory by pointer. It's likely to be slow (blocks the buffer, stalls the pipeline), and is useful only in special cases. Use it if you know what you do.
Since OpenGL is an API focused on drawing things (ignoring compute shaders for the moment) and when drawing a scene you normally start from an empty canvas, you'll have to retain the complete backlog of point cloud data throughout for the whole span of time, you want to be able to redraw.
Assuming that for large amounts of point cloud data, redrawing the whole set might take some time, some form of cachine might seem reasonable. But let's do some back of the envelope calculateions first:
Typical GPUs these days are perfectly capable of performing full vertex setup at a rate well over 10^9 vertices / second (already 20 years ago GPUs were able to do something on the order of 20·10^6 vertices / second). Your typical computer display has less than 10·10^6 pixels. So because of the pigeonhole principle, if you were to draw more than 10·10^6 points you're either producing serious overdraw or fill up most of the pixels; in practice it's going to be somewhere inbetween.
But as we've already seen, GPUs are more than capable of drawing that many points at interactive framerates. And drawing any more of them will likely fill up your screen or occlude data.
Some form of data retirement is required, if you want the whole thing to remain readable. And for any size of pointcloud that is readable your GPU will be able to redraw the whole thing just fine.
Considering the need for data retirement, I suggest you allocate a large buffer, that is able to hold a whole set of points over their lifetime, before eviction, and use it as a circular round robin buffer: Have an offset where you write over new data as it arrives (using glBufferSubData), at the edges you may have to split this in two calls, pass the latest writing index as a uniform, to fade out points by their age, and then just submit a single glDrawElements call to draw the whole content of that buffer in one go.
I have a couple questions about how OpenGL handles these drawing operations.
So lets say I pass OpenGL the pointer to my vertex array. Then I can call glDrawElements with an array of indexes. It will draw the requested shapes using those indexes in the vertex array correct?
After that glDrawElements call could I then do another glDawElements call with another set of indexes? Would it then draw the new index array using the original vertex array?
Does OpenGL keep my vertex data around for the next frame when I redo all of these calls? So the the next vertex pointer call would be a lot quicker?
Assuming the answer to the last three questions is yes, What if I want to do this on multiple vertex arrays every frame? I'm assuming doing this on any more than 1 vertex array would cause OpenGL to drop the last used array from graphics memory and start using the new one. But in my case the vertex arrays are never going to change. So what I want to know is does opengl keep my vertex arrays around in-case next time I send it vertex data it will be the same data? If not is there a way I can optimize this to allow something like this? Basically I want to draw procedurally between the vertexes using indicies without updating the vertex data, in order to reduce overhead and speed up complicated rendering that requires constant procedurally changing shapes that will always use the vertexes from the original vertex array. Is this possible or am I just fantasizing?
If I'm just fantasizing about my fourth question what are some good fast ways of drawing a whole lot of polygons each frame where only a few will change? Do I always have to pass in a totally new set of vertex data for even small changes? Does it already do this anyways when the vertex data doesn't change because I notice I cant really get around the vertex pointer call each frame.
Feel free to totally slam any logic errors I've made in my assertions. I'm trying to learn everything I can about how opengl works and it's entirely possible my current assumptions on how it works are all wrong.
1.So lets say I pass OpenGL the pointer to my vertex array. Then I can call glDrawElements with an array of indexes. It will draw the
requested shapes using those indexes in the vertex array correct?
Yes.
2.After that glDrawElements call could I then do another glDawElements
call with another set of indexes? Would it then draw the new index
array using the original vertex array?
Yes.
3.Does OpenGL keep my vertex data around for the next frame when I redo
all of these calls? So the the next vertex pointer call would be a lot
quicker?
Answering that is a bit more tricky than you might. The way you ask these questions makes me to assume that uou use client-side vertex arrays, that is, you have some arrays in your system memory and let your vertes pointers point directly to those. In that case, the answer is no. The GL cannot "cache" that data in any useful way. After the draw call is finished, it must assume that you might change the data, and it would have to compare every single bit to make sure you have not changed anything.
However, client side VAs are not the only way to have VAs in the GL - actually, they are completely outdated, deprecated since GL3.0 and been removed from modern versions of OpenGL. The modern way of doing thins is using Vertex Buffer Objects, which basically are buffers which are managed by the GL, but manipulated by the user. Buffer objects are just a chunk of memory, but you will need special GL calls to create them, read or write or change data and so on. And the buffer object might very well not be stored in system memory, but directly in VRAM, which is very useful for static data which is used over and over again. Have a look at the GL_ARB_vertex_buffer_object extension spec, which orignially introduced that feature in 2003 and became core in GL 1.5.
4.Assuming the answer to the last three questions is yes, What if I want
to do this on multiple vertex arrays every frame? I'm assuming doing
this on any more than 1 vertex array would cause OpenGL to drop the
last used array from graphics memory and start using the new one. But
in my case the vertex arrays are never going to change. So what I want
to know is does opengl keep my vertex arrays around in-case next time
I send it vertex data it will be the same data? If not is there a way
I can optimize this to allow something like this? Basically I want to
draw procedurally between the vertexes using indicies without updating
the vertex data, in order to reduce overhead and speed up complicated
rendering that requires constant procedurally changing shapes that
will always use the vertexes from the original vertex array. Is this
possible or am I just fantasizing?
VBOs are exactly what you are looking for, here.
5.If I'm just fantasizing about my fourth question what are some good
fast ways of drawing a whole lot of polygons each frame where only a
few will change? Do I always have to pass in a totally new set of
vertex data for even small changes? Does it already do this anyways
when the vertex data doesn't change because I notice I cant really get
around the vertex pointer call each frame.
You can also update just parts of a VBO. However, it might become inefficient if you have many small parts which are randomliy distributed in your buffer, it will be more efficient to update continous (sub-)regions. But that is a topic on it's own.
Yes
Yes
No. As soon as you create a Vertex Buffer Object (VBO) it will stay in the GPU memory. Otherwise vector data needs to be re-transferred (an old method of avoiding this was Display Lists). In both cases the performance of subsequent frames should stay similar (but much better with the VBO method): you can do the VBO creation and download before rendering the first frame.
The VBO was introduced to provide you exactly with this functionality. Just create several VBOs. Things get messy when you need more GPU memory than available though.
VBO is still the answer, and see Modifying only a specific element type of VBO buffer data?
It sounds like you should try something called Vertex Buffer Objects. It offers the same benefits as Vertex Arrays, but you can create multiple vertex buffers and store them in "named slots". This method has much better performance as data is stored directly in Graphic Card memory.
Here is a good tutorial in C++ to start with.
I have just started learning about vertex buffer objects in C++. I am reading a book about OpenGL that says that VBO rendering is more efficient than other forms of rendering because the data is stored on the GPU instead of on the heap. However, I am confused how this could be if you still have to load an array of data from the heap to the GPU. Every few seconds, I update the vertex data of my program, which means that I must then use glBufferData() to refresh the data to update to the new state. I don't see how this is more efficient than just rendering the array normally. I was wondering if I am calling glBufferData() more than is necessary, or if there is a better way to update the vertex data directly on the GPU.
Well, glBufferData (...) does more than you think. True it supplies data to a VBO, but the more important point is that it allocates memory on the server side (GPU for all intents and purposes) for vertex storage.
In your example, the number of vertices, and therefore size required to store them does not seem to change when you refresh your data. What you should actually be doing is calling glBufferSubData (...) to update the data without re-allocating space for it. Coupled with a correct usage flag (e.g. GL_DYNAMIC_DRAW) this can be much more efficient than copying from client to server everytime something is drawn.
Think of glBufferData (...) as a combination of malloc (...) and memcpy (...). glBufferSubData (...) on the other hand is memcpy (...). To this, end you can even do memory mapping of VBOs into your application's address space without having to allocate storage in both the client and server using glMapBuffer (...) and glUnmapBuffer (...), which are analogous to mmap (...) and munmap (...).
You should try to avoid modifying your vertex data every few frames. Vertex/fragment shaders are specifically there to allow you to modify your geometry on the fly, with some limitations of course.
However, in the simplest case (if you don't care about maximizing your performance), it is entirely possible to rewrite the buffer on every frame, and it should still beat calling glBegin..glEnd for every object.
I have some Haskell / OpenGLRaw code that does something like this:
verticesPtr <- newArray ...
glVertexPointer 3 gl_DOUBLE 0 verticesPtr
buffersPtr <- malloc
glGenBuffers 1 buffersPtr
buffer <- peek buffersPtr
glBindBuffer gl_ARRAY_BUFFER buffer
glBufferData gl_ARRAY_BUFFER 4 verticesPtr gl_STREAM_DRAW
glDrawArrays gl_LINE_STRIP 0 4
glDeleteBuffers 1 buffersPtr
I have two questions concerning this code:
I am calling this from within the draw callback. Does this entirely negate the usefulness of storing my vertex data in the server?
If I should place this code outside draw, should I change the gl_STREAM_DRAW command to something more static?
Yes, you are throwing away most of the benefits of buffer objects by using them in this manner. In all likelihood, it will still be faster than glBegin/glEnd since the driver becomes aware of all of the data simultaneously, rather than incrementally, but there's no guarantee it will be faster, and may even be slower for small buffer sizes due to the overhead of creating and destroying the buffer object.
Yes, as described in the glBufferData API docs you should avoid STREAM_DRAW unless the buffer is changing every or close to every frame. My personal rule of thumb is:
Changes only once in a while --> STATIC
Changes often, but less often than it stays the same --> DYNAMIC
Changes more often than it stays the same --> STREAM
Would someone care to explain the difference to be between a VertexBuffer, a VertexArray, a VertexBufferObject, and a VertexArrayObject? I'm not even sure if these are all terms for different things, but I've seen all of them appear in the OpenGL spec.
I know that a VertexBuffer simply contains vertices and nothing else, once bound, and once I've set the vertex pointers, I can use DrawArrays to draw it. I've done it this way many times.
I am using what I think is a VertexArray, which stores the state of any vertex buffers that are set, and also any vertex pointers. Binding a VertexArray automatically binds the vertex buffer and sets the vertex pointers. I have used this (mostly) successfully too.
But what is a VertexBufferObject, and a VertexArrayObject? Are they better? Doesn't VertexArray give me everything I need?
A vertex array is simply some data in your program (inside your address space) that you tell OpenGL about by providing a pointer to it.
While more efficient than specifying every single vertex individually, they still have performance issues. The GL must make a copy at the time you call DrawElements (or a similar function), because that is the only time it can be certain that the data is valid (after all, nothing prevents you from overwriting the data right away). This means that there is a significant hindrance to parallelism, and thus a performance issue.
Vertex buffer objects ("vertex buffers") are raw blocks of data that you do not own, i.e. they are not in your address space. You can either copy data into the buffer object with Copy(Sub)Data or by temporarily mapping it to your address space. Once you unmap the buffer, it does no longer belong to you. The huge advantage is that now the GL can decide what to do with it, and when to upload it. It knows that the data will be valid, because you cannot access it. This makes CPU/GPU parallelism a lot easier.
Vertex array abjects are a bit of a misnomer. There are no vertices or arrays in them. They are merely a kind of "state description block" which encapsulate the bindings of one or several vertex buffer objects (including any VertexAttribPointer calls). As such, they are both a convenience function and somewhat more efficient (fewer function calls), but not strictly necessary. You could do anything that a VAO does by hand, too.
BufferObject: a GPU allocated memory buffer
Vertex Buffer Object: a BufferObject containing vertices informations (colors, position, custom data used by a shader, ...)
Pixel Buffer Object: a BufferObject containing pixel or texel informations. Mainly used to upload textures.
Element Buffer Object: a BufferObject containing indices (used by glDrawElements).
Vertex Array: memory used by gl*Pointer call. Might be host memory or a Vertex Buffer Object if it is bound using glBindBuffer command with GL_ARRAY_BUFFER.
Element Array: memory used by glDrawElements call. Might be host memory or an Element Buffer Object if it is bound using glBindBuffer command with GL_ELEMENT_ARRAY_BUFFER.