What exactly is a VBO in OpenGL? - opengl

I am trying to understand the theory behind OpenGL and I'm studying VBOs at the moment.
This is what I understand so far: when we declare a series of vertices, let's say 3 vertices that form a triangle primitive, we basically store those nowhere, they're simply declared in code.
But, if we want to store them somewhere we can use a VBO that stores the definition of those vertices. And, through the same VBO we send all that vertex info to the Vertex Shader (which is a bunch of code). Now, the VBO is located in the GPU, so we are basically storing all that info on the GPU's memory when we call the VBO. Then the Vertex Shader, which is part of the Pipeline Rendering process, "comes" to the GPU's memory, "looks" into the VBO and retrieves all that info. In other words, the VBO stores the vertex data (triangle vertices) and sends it to the Vertex Shader.
So, VBO -> send info to -> Vertex Shader.
Is this correct? I'm asking to make sure if this is the correct interpretation, as I find myself drawing triangles on screen and sometimes letters made up of many triangles with a bunch of code and functions that I basically learned by memory but don't really understand what they do.
To break it down:
// here I declare the VBO
unsigned int VBO;
// we have 1 VBO, so we generate an ID for it, and that ID is: GL_ARRAY_BUFFER
glGenBuffers(1, &VBO)
// GL_ARRAY_BUFFER is the VBO's ID, which we are going to bind to the VBO itself
glBindBuffer(GL_ARRAY_BUFFER, VBO)
// bunch of info in here that basically says: I want to take the vertex data (the
// triangle that I declared as a float) and send it to the VBO's ID, which is
// GL_ARRAY_BUFFER, then I want to specify the size of the vertex
// data, the vertex data itself and the 'static draw' thingy
glBufferData(...).
After doing all that, the VBO now contains all the vertex data within. So we tell the VBO, ok now send it to the Vertex Shader.
And that's the start of the Pipeline, jsut the beginning.
Is this correct? (I haven't read what VAOs do yet, before I get to that I'd like to know if the way I deconstruct VBOs in my mind is the right way, or else I'm confused)

I think you are mixing up lots of different things and have several confusions, so I'm try to work through most of them in the order you brought them up:
when we declare a series of vertices, let's say 3 vertices that form a triangle primitive, we basically store those nowhere, they're simply declared in code.
No. If you store data "nowhere", then you don't have it. Also you are mixing up declaration, definiton and initialization of variables here. For vertex data (like all other forms of data), there are two basic strategies:
You store the data somewhere, typically in a file. Specifying it directly in source code just means that it is stored in some binary file, potentially the executable itself (or some shared library used by it)
You procedurally generate the data through some mathematical formula or more general by some algortihm
Methods 1. and 2 can of course be mixed, and usually, method 2 will need some parameters (which itself need to be stored somewhere, so the parameters are just case 1 again).
And, through the same VBO we send all that vertex info to the Vertex Shader (which is a bunch of code). Now, the VBO is located in the GPU, so we are basically storing all that info on the GPU's memory when we call the VBO.
OpenGL is actually just a specification which is completely agnostic about the existence of a GPU and the existence of VRAM. And as such, OpenGL uses the concept of buffer objects (BOs) as some continuous block of memory of a certain size which is completely managed by the GL implementation. You as the user can ask the GL to create or destroy such BOs, specify their size, and have complete control of the contents - you can put an MP3 file into a BO if you like (not that there would be a good use case for this).
The GL implementation on the other hand controls where this memory is actually allocated, and GL implementations for GPUs
which actually have dedicated video memory have the option to store a BO directly in VRAM. The hints like GL_STATIC_DRAW are there to help the GL implementation decide where to best put such a buffer (but that hint system is somewhat flawed, and better alternatives exist in modern GL, but I'm not going into that here). GL_STATIC_DRAW means you intent to specify the contents once and use the may times as the source of a drawing option - so the data won't change often (and certainly not on a per-frame basis or even more often), and it might be a very good idea to store it in VRAM if such a thing exists.
Then the Vertex Shader, which is part of the Pipeline Rendering process, "comes" to the GPU's memory, "looks" into the VBO and retrieves all that info.
I think one could put it that way, although some GPUs have a dedicated "vertex fetch" hardware stage which actually reads the vertex data which is then fed to the vertex shaders. But that's not a really important point - the vertex shader needs to access each vertex' data, and that means the GPU will read that memory (VRAM or system memory or whatever) at some point before or during the execution of a vertex shader.
In other words, the VBO stores the vertex data (triangle vertices)
Yes. A buffer object which is used as source for the vertex shader's per-vertex inputs ("vertex attributes") is called a vertex buffer object ("VBO"), so that just follows directly from the definition of the term.
and sends it to the Vertex Shader.
I wouldn't put it that way. A BO is just a block of memory, it doesn't actively do anything. It is just a passive element: it is being written to or being read from. That's all.
// here I declare the VBO
unsigned int VBO;
No, you are declaring (and defining) a variable in the context of your programming language, and this variable is later used to hold the name of a buffer object. And in the GL, object names are just positive integers (so 0 is reserved for the GL as "no such object" or "default object", depending on the object type).
// we have 1 VBO, so we generate an ID for it, and that ID is: GL_ARRAY_BUFFER
glGenBuffers(1, &VBO)
No. glGenBuffers(n,ptr) just generates names for n new buffer objects, so it will generate n previously unused buffer names (and mark them as used) and returns them by writing them to the array pointed to byptr. So in this case, it just creates one new buffer object name and stores it in your VBO variable.
GL_ARRAY_BUFFER has nothing to do with this.
// GL_ARRAY_BUFFER is the VBO's ID, which we are going to bind to the VBO itself
glBindBuffer(GL_ARRAY_BUFFER, VBO)
No, GL_ARRAY_BUFFER is not the VBO's ID, the value of yourVBO variable is the VBO's ID (name!).
GL_ARRAY_BUFFER is the binding target. OpenGL buffer objects can be used for different purposes, and using them as the source for vertex data is just one of them, and GL_ARRAY_BUFFER refers to that use case.
Note that classic OpenGL uses the concept of binding for two purposes:
bind-to-use: Whenever you issue a GL call which depends on some GL objects, the objects you want to work with have to be currently bound to some (specific, depending on the use case) binding target (not only buffer objects, but also textures and others).
bind-to_modify: Whenever you as the user want to modify the state of some object, you have to bind it first to some binding target, and all the object state modify functions don't directly take the name of the GL object to work on as parameter, but the binding target, and will affect the object which is currently bound at that target. (Modern GL also has direct state access which allows you to modify objects without having to bind them first, but I'm also not going into details about that here).
Binding a buffer object to some of the buffer object binding targets means that you can use that object for the purpose defined by the target. But note that a buffer object doesn't change because it is bound to a target. You can bind a buffer object to different targets even at the same time. A GL buffer object doesn't have a type. Calling a buffer a "VBO" usually just means that you intent to use it as GL_ARRAY_BUFFER, but the GL doesn't care. It does care about what is buffer is bound as GL_ARRAY_BUFFER at the time of the glVertexAttribPointer() call.
// bunch of info in here that basically says: I want to take the vertex data (the
// triangle that I declared as a float) and send it to the VBO's ID, which is
// GL_ARRAY_BUFFER, then I want to specify the size of the vertex
// data, the vertex data itself and the 'static draw' thingy
glBufferData(...).
Well, glBufferData just creates the actual data storage for a GL buffer object (that is, the real memory), meaning you specify the size of the buffer (and the usage hint I mentioned earlier where you tell the GL how you intend to use the memory), and it optionally allows you to initialize the buffer by copying data from your application's memory into the buffer object. It doesn't care about the actual data, and the types you use).
Since you use GL_ARRAY_BUFFER here as the target parameter, this operation will affect the BO which is currently bound as GL_ARRAY_BUFFER.
After doing all that, the VBO now contains all the vertex data within.
Basically, yes.
So we tell the VBO, ok now send it to the Vertex Shader.
No. The GL uses Vertex Array Objects (VAOs) which store for each vertex shader input attribute where to find the data (in which buffer object, at which offset inside the buffer object) and how to interpret this data (by specifying the data types).
Later during the the draw call, the GL will fetch the data from the relevant locations within the buffer objects, as you specified it in the VAO. If this memory access is triggered by the vertex shader itself, or if there is a dedicated vertex fetch stage which reads the data before and forwards it to the vertex shader - or if there is a GPU at all - is totally implementation-specific, and none of your concern.
And that's the start of the Pipeline, just the beginning.
Well, depends on how you look at things. In a traditional rasterizer-based rendering pipline, the "vertex fetch" is more or less the first stage, and vertex buffer objects will just hold the memory where to fetch the vertex data from (and VAOs telling it which buffer objects to use, and which actual locations, and how to interpret them).

It all boils down to this: when you work in "normal" programs, all what you have is the CPU, caches, registers, main memory, etc.
However, when you work with computer graphics (and other fields), you want to use a GPU because it is faster for that particular task. The GPU is an independent computer on its own, with its own processor, pipeline and main even memory.
This means your program needs to somehow transfer all the data to the other computer and tell the other computer what to do with it. This is no easy task, so OpenGL simplifies things for you. Thus they give you an abstraction (VBO) that represents a buffer of vertices in the GPU, among many other abstractions for other tasks. Then they give you functions to create that resource (glGenBuffers), fill it with data (glBufferData), "bind it" to work with it (glBindBuffer), etc.
Remember, it is all a simplification for your benefit. In truth, the details of how everything is performed underneath is way more complex. Having abstractions like VBOs for vertices or IBOs for indexes makes it easier to work with them.

Related

How does openGL store VBO & 'GL_ARRAY_BUFFER' on GPU?

Though I've understood the state design of OpenGL enough to work with it, I've still struggled visualizing the inner workings on the CPU/GPU. Currently I'm stuck wondering how VBO's are copied onto the GPU using GL_ARRAY_BUFFER.
I previously understood the VBO's to be a 'state' of GL_ARRAY_BUFFER, this led me to 3 different options as to how that might work, shown below.
The top answer of the following thread explains: "The GL_ARRAY_BUFFER target for buffer objects represents the intent to use that buffer object for vertex attribute data"
What does the GL_ARRAY_BUFFER target mean in glBindBuffer?
which, as I understand it, means that GL_ARRAY_BUFFER is sort of a 'state' of a VBO. It could have a different state, but it does require to have a state to be able to be copied onto 'the' GPU buffer/ a smaller allocated buffer on the GPU? Or am I misunderstanding it? does 'binding' mean something different from setting a state? (this 4th option is not visualized below).
Are any of these 4 ideas accurate? or is it something completely different?
Apologies for the horrendous diagram. I hope it's clear enough though.
Any confirmation / correction would be greatly appreciated!
I also looked though this post
What exactly is a VBO in OpenGL?
which states
"Since you use GL_ARRAY_BUFFER here as the target parameter, this operation (glBufferData(...)) will affect the BO which is currently bound as GL_ARRAY_BUFFER.
After doing all that, the VBO now contains all the vertex data within.
Basically, yes."
this implies the VBO memory on the GPU is set through the GL_ARRAY_BUFFER, which is what I understood at first.
options 3 & 4 seem most logical to me. Could it be that VBO and GL_ARRAY_BUFFER are both states of eachother simultaneously, depending on the context?: which VBO is active / which target is active for the VBO
Frankly, it's not any of the options you listed. GL_ARRAY_BUFFER is a client-side binding point that's used to name the active buffer that you operate on with other commands. It's used purely in communications with the driver. Furthermore, by means of DSA (direct state access, OpenGL 4.5+) you can fully set up a VBO without ever binding it to anything.
This is probably a better diagram to describe the situation:
Note the GL_ARRAY_BUFFER binding point can be tracked either by the driver or the user-process libGL. It's really not essential.
glBufferData creates the buffer object and the data store of the buffer and optionally initializes the data. As long as glBufferData is not called there is no object and no reserved (GPU) data store. The buffer's size is immutable. glGenBuffers creates only the "name" of the buffer (the buffer ID).
Actually a buffer has no type. However, a buffer can be used for different things and to each target (like GL_ARRAY_BUFFER) a different buffer can be bound. GL_ARRAY_BUFFER is only used to identify the buffer in various API functions.

OpenGL - glDrawElements vs Vertex Array Objects

I need help to see the trade-offs between them.
It looks to me that glDrawElements() needs to get the index-data "live" as a parameter.
On the other side if I use VAOs then during startup I buffer the data and the driver might decide to put it on the GPU, then during rendering I only bind the VAO and call glDrawArrays().
Is there no way to combine the advantages? Can we buffer the index-data too?
And how would that look in the vertex shader? Can it use the index and look it up in the vertex positions array?
This information is really a bit hard to find, but one can use glDrawElements also in combination with a VAO. The index data can then (but doesn't have to) be supplied by a ELEMENT_ARRAY_BUFFER. Indexing works then as usual, one does not have to do anything special in the vertex shader. OpenGL ensures already that the indices are used in the correct way during primitiv assembly.
The spec states to this in section 10.3.10:
DrawElements, DrawRangeElements, and DrawElementsInstanced source
their indices from the buffer object whose name is bound to ELEMENT_-
ARRAY_BUFFER, using their indices parameters as offsets into the buffer object
This basically means, that whenever a ELEMENT_ARRAY_BUFFER is bound, the indices parameter is used as an offset into this buffer (0 means start from the beginning). When no such buffer is bound, the indices pointer specifies the address of a index array.

Meaning of "Single Vertex Buffer"

I am trying to understand the meaning of a "performance tip" given in the GCW Zero OpenGL instructions:
always use vertex buffer objects (VBOs)
put vertices into one interleaved VBO, not multiple VBOs
Does this mean that I should put ALL MY OBJECTS into a single vertex buffer (and remember the start / finish index pertaining to each object). Or does it simply mean that each object should be in one vertex buffer (rather than a buffer for each attribute).
Is it normal to have multiple objects in the same vertex buffer?
Does this mean that I should put ALL MY OBJECTS into a single vertex
buffer (and remember the start / finish index pertaining to each
object)
Or does it simply mean that each object should be in one
vertex buffer (rather than a buffer for each attribute).
This "performance tip" says nothing about multiple objects. What it says is that you should put all the attributes into the same VBO, using interleaved attribute arrays. Which is likely to be the most cache efficient strategy, and a reasonable advice in the general case.
Putting multiple objects is also quite common, especially if they have only relatively few vertices. You can save a lot of state switches and ideally even draw calls that way. But it depends on the scene, of course. Combining things into the same VBO is most useful for static objects which are often drawn together.

Use of Vertex Array Objects and Vertex Buffer Objects

I am trying to understand these two, how to use them and how they are related. Let's say I want to create a simple terrain and a textured cube. For both objects I have the array of triangles vertices and for the cube I have an array containing the texture's data. My question is: how do I use VAOs and VBOs to create and render these two?
Would I have to create a VAO and VBO for each object?
or should create a VAO for each object's VBO (vertices, texture data, etc.)?
There are many tutorials and books but I still don't get the very idea of how these concepts must be understood and used.
Fundamentally, you need to understand two things:
Vertex Array Objects (VAOs) are conceptually nothing but thin state wrappers.
Vertex Buffer Objects (VBOs) store actual data.
Another way of thinking about this is that VAOs describe the data stored in one or more VBOs.
Think of VBOs (and buffer objects in general) as unstructured arrays of data stored in server (GPU) memory. You can layout your vertex data in multiple arrays if you want, or you can pack them into a single array. In either case, buffer objects boil down to locations where you will store data.
Vertex Array Objects track the actual pointers to VBO memory needed for draw commands.
They are a little bit more sophisticated than pointers as you would know them in a language like C, however. Vertex pointers keep track of the buffer object that was bound when they were specified, the offset into its address space, stride between vertex attributes and how to interpret the underlying data (e.g. whether to keep integer values or to convert them to floating-point [0.0,1.0] by normalizing to the data type's range).
For example, integer data is usually converted to floating-point, but it is the command you use to specify the vertex pointer (glVertexAttribPointer (...) vs. glVertexAttribIPointer (...)) that determines this behavior.
Vertex Array Objects also track the buffer object currently bound to GL_ELEMENT_ARRAY_BUFFER.
GL_ELEMENT_ARRAY_BUFFER is where the command: glDrawElements (...) sources its list of indices from (assuming a non-zero binding) and there is no glElementArrayPointer (...) command. glDrawElements (...) combines the pointer and draw command into a single operation, and will use the binding stored in the active Vertex Array Object to accomplish this.
With that out of the way, unless your objects share vertex data you are generally going to need a unique set of VBOs for each.
You can use a single VAO for your entire software if you want, or you can take advantage of the fact that changing the bound VAO changes nearly the entire set of states necessary to draw different objects.
Thus, drawing your terrain and cube could be as simple as changing the bound VAO. You may have to do more than that if you need to apply different textures to each of them, but the VAO takes care of all vertex data related setup.
Your question is not easily answerable here, but rather in a tutorial. You probably already know these two websites, but if not, I'm leaving the references.
OGLDEV
OpenGL-Tutorial.org
Now trying to elucidate your questions, a Vertex Array Object is an OpenGL object designed with the goal of reducing API overhead for draw calls. You can think of it as a container for a Vertex Buffer and its associated states. Something similar perhaps to the old display-lists.
Normally, there is a 1 to 1 relationship between a VAO and a VBO; that is, each VAO contains a unique VBO. But this is not strictly necessary. You could have several VAOs referencing the same VBO.
The simplest way to model this in code, I think, would be for you to have a VAO class/type and a method to attach a VBO to it. Then give an instance of VAO to each mesh. The mesh in turn can have a reference to a VBO type that may be its own or a shared one.

OpenGL vertex buffer confusion

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.