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.
Related
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.
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.
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.
Imagine a typical game where objects in the simulated world are created and destroyed. When these objects are created, their vertex data is stored in a VBO. This VBO is rendered once per frame.
Is there a best practice for dealing with dead objects? I.e. when the object is destroyed and thus no longer needs to be rendered, what should happen to its corresponding VBO data?
It seems like you'd want to "free" that memory up for future use by other objects. Otherwise, your VBO would eventually be filled almost entirely with dead data.
I have one possible idea for implementing this: a map of VBO memory wherein individual bytes are marked as free or in use. (This map would live on the CPU as a normal array, not on the GPU.) When an object is created, we buffer its data to a free region as determined by the map. We mark that region as used on the map. Then when the object is destroyed, we mark that same region as free. I'm thinking you would store the map either as an array of booleans if you're lazy, or pack it in as one map bit per VBO byte if you want to do it right.
So far, does this sound like the best approach? Is there a more common approach that I'm not seeing?
I know a lot of these questions hinge on the characteristics of the scene you're rendering, so here's the context. My scene consists of several hundred objects. Each object has about eight vertices. Each vertex has a position and texture coordinate stored as floats. So, we're looking at approximately:
4 bytes per float * 6 floats per vert * 8 verts per object * 500 objects
= 96,000 bytes of vertex data
Sounds like you're thinking of using a pool allocator. There's a lot of existing work done on those, which should apply quite well to allocations inside a VBO also.
It will be pretty straightforward if all elements are the same size. Otherwise, you need to be concerned about fragmentation, but heap managers are quite well known.
The simplest improvement I would offer is to start your scan for a free slot from the last slot filled, instead of always from the beginning.
You can trade space for speed by using a deque-style data structure to store a list of free locations, which eliminates the need to scan for a free spot.
The size of the data stored in the VBO really has no impact on the manager. Only the number of slots which can be invididually repurposed.
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.