I am a newbee to OpenGL. Now I could render something on screen, which is great. Now I want to streaming some data point(GL_POINTS) on my screen. However, initially it doesn't show anything. And it costs me several days to find out how to make it works.
The point is, I use an VBO to save my data and call glBufferSubData() to update the buffer. However, it ONLY works if I call glBufferData() before the first render loop. In other words, if I just do
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
in my initializing function (before first render loop), and in my updateData loop I do
glBindVertexArray(VAO);
glBindBuffer(VBO);
glBufferData(GL_ARRAY_BUFFER, myData.size() * sizeof(float), &myData[0], GL_DYNAMIC_DRAW);
... // glVertexAttribPointer and other required general process
It won't render anything. It seems I have to glBufferData(/some random data here/) to "allocate" the buffer (I thought it was allocated when calling glGenBuffer()). And use
glBufferSubData(/*override previous data*/) or
glMapData()
to update that buffer.
So my question would be...what is the proper/normal way to initialize an VBO if I don't know how much data/vertex I need to draw in the compile time? (right now I just glBufferData() a loooooong buffer and update it when needed)
Note: OpenGL3.3, Ubuntu16.04
Update:
In my opinion, it works in the way like allocating char[], I have to say pointing out how much I need for the string char[200], and fill in the data via snprintf(). But we now have vector or string, that allows us to dynamically change the memory location. Why OpenGL doesn't support that? If they did, how should I use it.
I thought it was allocated when calling glGenBuffer()
The statement:
int *p;
Creates an object in C/C++. That object is a pointer. It does not point to an actual object or any kind of storage; it's just a pointer, waiting to be given a valid address.
So too with the result of glGenBuffers. It's a buffer object, but it has no storage. And like an uninitialized pointer, there's not much you can do with a buffer object with no storage.
what is the proper/normal way to initialize an VBO if I only don't know how much data/vertex I need to draw in the compile time?
Pick a reasonable starting number. If you overflow that buffer, then either terminate the application or allocate additional storage.
But we now have vector or string, that allows us to dynamically change the memory location. Why OpenGL doesn't support that?
Because OpenGL is a low-level API (relatively speaking).
In order to support dynamic reallocation of storage in the way you suggest, the OpenGL implementation would have to allocate new storage of the size you request, copy the old data into the new storage, and then destroy the old storage. std::vector and std::string have to do the same stuff; they just do it invisibly.
Also, repeatedly doing that kind of operation horribly fragments the GPU's address space. That's not too much of a problem with vector and string, since those arrays are usually quite small (on the order of kilobytes or low megabytes). Whereas a single buffer object that takes up 10% of a GPU's total memory are hardly uncommon in serious graphics applications. Reallocating that is not a pleasant idea.
OpenGL gives you the low-level pieces to build that, if you want to suffer the performance penalty for doing so. But it doesn't implement it for you.
Related
OpenGL has functions that can create and multiple objects at once
glCreateBuffers(1,&handle);
...
glDeleteBuffers(1,&handle);
I guess the intention is that it saves time to create/destroy all objects at once. But is that only at initialization, or does it affect the memory layout such as increased locality, resulting in shorter render time.
Before this question is marked as duplicate, of Is there an advantage to generating multiple indexes (names) at once in OpenGL?, this question is about object creation with ARB_direct_state_access, rather than name creation, which RetoKoradi comments is cheap.
The VRAM is not a disk, it's a Random Access Memory. OpenGL doesn't need to scan it through to reach something on it. There's usually a memory table stored somewhere, which keeps track of the locations of the buffers and vertex arrays. There's also a pointer that points to the current VAO, VBO, IBO, texture, framebuffer, etc.
When you use one of the glBindXYZ functions, you pass a handle to OpenGL. It then looks up the pointer to the bufffer/vertex array/texture/etc from the memory table, and sets the relevant pointer to the result.
The gen functions work like this, because most people know how many vbos or vaos they'll need, and this makes creating them easier. It's only a problem, when you have a variable amount of vbos.
Creating multiple buffers at once doesn't have an advantage over creating them one-by-one right after each other in terms of memory layout. Both
glCreateBuffers(1, &handle1);
// Stuff
glCreateBuffers(1, &handle2);
// Stuff
glCreateBuffers(1, &handle3);
// Stuff
and
glCreateBuffers(3, &handles);
// Stuff x 3
result in the same. In both cases the vbos are as close as possible (if they are already used up memory blocks where the next vbo should go, then it will be a bit further away from the others.
I have a huge vbo, and the entire thing changes every frame.
I have heard of different methods of quickly changing buffer data, however only one of them seems like a good idea for my program. However I dont understand it and cant find any code samples for it.
I have heard people claim that you should call glBufferData with "null" as the data then fill it with your real data each frame. What is the goal of this? What does this look like in code?
It's all in the docs.
https://www.opengl.org/sdk/docs/man/html/glBufferData.xhtml
If you pass NULL to glBufferData(), it looks something like this:
int bufferSize = ...;
glBufferData(GL_ARRAY_BUFFER, bufferSize, NULL, GL_DYNAMIC_DRAW);
void *ptr = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
...
Ignore most of that function call, the only two important parts are bufferSize and NULL. This tells OpenGL that the buffer has size bufferSize and the contents are uninitialized / undefined. In practice, this means that OpenGL is free to continue using any previous data in the buffer as long as it needs to. For example, a previous draw call using the buffer may not have finished yet, and using glBufferData() allows you to get a new piece of memory for the buffer instead of waiting for the implementation to finish using the old piece of memory.
This is an old technique and it works fairly well. There are a couple other common techniques. One such technique is to double buffer, and switch between two VBOs every frame. A more sophisticated technique is to use a persistent buffer mapping, but this requires you to manage memory fences yourself in order for it to work correctly.
Note that if you are uploading data with glBufferData() anyway, then calling glBufferData() beforehand with NULL doesn't actually accomplish anything.
I have code for rendering models, but if I use too many vertices I meet a problem: program cant allocate memory enough to handle all vertices.
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(3,GL_FLOAT,0,VertexArray);
glNormalPointer(GL_FLOAT,0,NormalArray);
glColorPointer(3,GL_FLOAT,0,ColorArray);
Here is my code, its just a part of it, but I think enough. VertexArray is got by using new operator, it is a pointer on an array. But if I use array of length, e.g. 10000000 values I get an error.
Is there any way to allocate memory from different parts of RAM? Or any other way to find a solution?
If you're drawing models that wont be modified often after their first call you could switch to using VBOs and use the STATIC_DRAW flag, this will most likely tell your GPU to put them in video memory, you'll have more breathing room memory wise if you move to using some VBOs for models that you don't need to keep changing/have all the vertex data readily accessible on your CPU. (Even if not there are ways to access this vertex data and update, such as glBufferSubData, and using the DYNAMIC_DRAW flag instead).
VBOs are stored in GPU memory, not system meory, giving you much more capacity before you start hitting a memory cap.
The old glVertexPointer method doesn't have this benefit.
UPDATE I just discovered my question is likely a duplicate of If you call glBufferData after already calling it on a buffer, is there a memory leak?
Hopefully my question is still useful to someone, as I give code samples, rather than merely mentioning the gl function calls, as in that Q&A.
I don't understand the relationship between glGenBuffers / glBindBuffer / glBufferData and gldeletebuffers.
Consider drawing a sequence of lines (a line strip). The original sequence is drawn over some number of frames, but then new user input increases the number of lines.
My first thought is to re-use the buffer object name assigned by glGenBuffers, when the size changes. But since the buffer size needs to be larger, I can't use the existing buffer as-is.
NOTE: At this time, I would rather not assume some "maximum size", allocate that, and then do sub-data calls for the size I currently need.
Consider code based on this example:
When should I call glDeleteBuffers()?
If I had done these lines in an initialization function before drawing the first frame (code may not compile -- I'm concerned about the call sequence, not the exact parameters to pass -- I'm actually working in C# under Xamarin using OpenTK to access OPENGL ES 2.0, but it is easier to find examples in C++ using opengl):
GLuint VBO;
void init(int size, float* data) {
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
}
which many frames later (or when app exits) is released via:
void destroy() {
glDeleteBuffers(1, &VBO);
}
But now I want to have a "re_init" function that allocates a different size, what exactly do I need to do?
I could re-assign a new VBO buffer name:
void re_init(newSize, newData) {
destroy();
init(newSize, newData);
}
But this seems like overkill. What is the minimum work that I can do? And is that any more efficient than the brute-force destroy/create-a-new-one above?
It seems that any set of calls I do works, but i don't know whether the result is leaking memory or not. I will eventually need to learn how to test for memory leaks in the environment I am in, but right now I want to get the theory right, in hopes that I will write code that is both efficient and non-leaking.
Will this leak memory?
void re_init(newSize, newData) {
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, newSize, newData, GL_STATIC_DRAW);
}
That is, I haven't done glDeleteBuffers on the old buffer, because doing so freed the VBO buffer name, and I am trying to find out how to not do so.
One question is whether there is a way to re-use a VBO buffer name, with data of a different size?
Or am I better off sticking to the simple model of freeing the buffer and its name every time I need to change buffer size? (That is what glDeleteBuffers seems to do.)
There are 3 separate entities in play here:
A buffer name. Since it is an integer value lot of people like to call this an "id". But if you read official OpenGL documentation, it is always called "name".
A buffer object. This is the object that contains the state attributes, like the current size, the usage flags, etc.
A buffer store. This is the memory that contains the actual buffer content.
With these definitions, we can describe what each call is doing:
glGenBuffers() creates buffer names.
glBindBuffer() creates a buffer object the first time the given name is bound, and makes it the current buffer for other calls operating on buffers.
glBufferData() deletes the current buffer store if there already was one, and creates a new buffer store.
glBufferSubData() modifies data in the existing data store.
glDeleteBuffers() deletes the buffer names, as well as the associated buffer objects and buffer stores if they exist.
This means that calling glBufferData() on the same buffer object multiple times is perfectly fine, and will not cause any memory leaks.
A subtle detail in the list above is that glGenBuffers() does not create buffer objects. That only happens the first time the name is bound. This does not really matter for buffer objects, but it is important to understand for other types of objects (like textures) that have the same behavior.
glBufferData will replace the content of the buffer object - as indicated is the spec/doc, "while creating the new storage, any pre-existing data store is deleted" - so this won't leak memory.
For efficiency, there are many factors to consider, and no universal guidelines - I suggest you profile in your application, once you have a real use case with your data.
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.