Why does glBufferData have mode parameter? - opengl

unsigned int vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
We bind the buffer in OpenGL in 3rd line, we set the mode to GL_ARRAY_BUFFER or anything else.
Why should we set the mode again in glBufferData which just use the last bounded buffer?

Note, that the first parameter of glBindBuffer is not a mode, but a buffer binding point to which the buffer will be bound. There are several of these binding points and a buffer can also be bound to more than one binding point at a time.
The reason why one needs to repeat this is that multiple buffers can be bound to different buffer binding points at the same time. When, for example, rendering with indexed geometry, there will be one buffer bound to GL_ARRAY_BUFFER and another buffer bound to GL_ELEMENT_ARRAY_BUFFER. The first parameter of glBufferData now identifies which of the bound buffers you want to upload data to.
In the Direct State Access extension, the need to specify the binding point has been replaced by passing the buffer handle directly to the methods:
glNamedBufferData(GLuint buffer, GLsizei size, const void *data, GLenum usage)

Related

Is there any difference in OpenGL between creating Index Buffers with GL_ARRAY_BUFFER and creating them with GL_ELEMENT_ARRAY_BUFFER?

I've been delving into OpenGL a while, and now, working on a project, I found that, when I'm creating an index buffer, if I bind it to a GL_ARRAY_BUFFER instead to a GL_ELEMENT_ARRAY_BUFFER has (apparently) the same result.
I mean, the vertex buffers are always bound to GL_ARRAY_BUFFER, but if I create an index buffers like this:
glCreateBuffers(1, &m_BufferID);
glBindBuffer(GL_ARRAY_BUFFER, m_BufferID);
glBufferData(GL_ARRAY_BUFFER, count * sizeof(uint), vertices, GL_STATIC_DRAW);
And then, when drawing geometry for instance, I bind it to a GL_ELEMENT_ARRAY_BUFFER, works just fine, and I don't know why I thought that index buffers had to be created with GL_ELEMENT_ARRAY_BUFFER too, but... Is there any "inner" difference actually?
In terms of the nature of the buffer object itself? No. All buffer objects are the same and can be used for any task appropriate for a buffer object. A buffer object does not take on special properties by which binding it was initially used with.
However, the GL_ELEMENT_ARRAY_BUFFER binding point is itself a bit unusual. It's not part of global context state; it's part of VAO state. So if you have no VAO bound (under a core profile context), then you can't bind anything to that binding point. And when you bind to that binding point, you are affecting the state of the currently bound VAO. And if you change the currently bound VAO, you will be changing which buffer is bound to the element array binding point.
So generally, you should only bind to that point if what you intend to do is attach the buffer to the currently bound VAO.
Yes it ist. While the ARRAY_BUFFER binding is a global state, the ELEMENT_ARRAY_BUFFER binding is stated in the Vertex Array Object. See Index buffers.
Hence, glBindBuffer(GL_ELEMENT_ARRAY_BUFFER m_BufferID) changes a state in the currently bound Vertex Array Object.
Note that compared to the index buffer (ELEMENT_ARRAY_BUFFER), the vertex buffer binding (ARRAY_BUFFER) is a global state.
Each attribute which is stated in the VAOs state vector may refer to a different ARRAY_BUFFER. This reference is stored when glVertexAttribPointer is called. Then the buffer which is currently bound to the target ARRAY_BUFFER, is associated to the specified attribute index and the name (value) of the object is stored in the state vector of the currently bound VAO.
However the index buffer is a state of the VAO. If a buffer is bound to the target ELEMENT_ARRAY_BUFFER, this buffer is assigned to the currently bound Vertex Array Object.

Why do I need to specify data for both the VBO and while calling glVertexAttribPointer?

When using OpenGl I usually create a VBO and pass the vertex data to it with
glBufferData();
I have been reading this source recently, and please let me cite one part of it:
While creating the new storage, any pre-existing data store is deleted. The new data store is created with the specified size in bytes and usage. If data is not NULL, the data store is initialized with data from this pointer. In its initial state, the new data store is not mapped, it has a NULL mapped pointer, and its mapped access is GL_READ_WRITE.
From this I conclude, that while buffer data function is set, the data from the buffer is copied to the VBO.
Now, when calling glVertexAttribPointer() I have to pass a pointer to the data again.
I understand the purpose of attrib pointers - they tell the OpenGL state machine how the data is organised in the VBO.
However, passing the pointer both to VBO and then to the glVertexAttribPointer function seems redundant, since the VAO saves the attrib pointer configuration anyway, and to call glVertexAttribPointer one has to store the vertex data in the program memory anyway - so the memory gets duplicated (one primal copy and the copy made by glBufferData()).
Why is this apparent redundancy present? Or maybe I understand something the wrong way?
Maybe I misunderstood the documentation and the data is not copied to VBO, but what would be the purpose of VBOs anyway then?
You don't have to. If a named buffer object is bound to the ARRAY_BUFFER target then the last argument (pointer) of glVertexAttribPointer is treated as a byte offset into the buffer object's data store.
Either (only compatibility profile):
float *data;
glBindBuffer(GL_ARRAY_BUFFER, 0); // 0 is default
glVertexAttribPointer(..., data);
or
float *data;
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, ..., data, ...);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(..., (void*)0);

Why must you use both glBindBuffer and glBindBufferRange to create a uniform buffer in OpenGL?

To create a uniform buffer object in OpenGL, why must I call both glBindBuffer and glBindBufferRange? According to documentation,
Think of glBindBufferRange as binding the buffer to two places: the particular index and the target​. glBindBuffer only binds to the target​, not the index.
So then glBindBuffer seems superfluous to me if you are already binding a buffer to that same target using glBindBufferRange.
I am reading Learning Modern 3D Graphics Programming and chapter 7 shows how to make uniform buffer objects. The code used in the book:
glGenBuffers(1, &g_GlobalMatricesUBO);
glBindBuffer(GL_UNIFORM_BUFFER, g_GlobalMatricesUBO);
glBufferData(GL_UNIFORM_BUFFER, sizeof(glm::mat4) * 2, NULL, GL_STREAM_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glBindBufferRange(GL_UNIFORM_BUFFER, g_iGlobalMatricesBindingIndex, g_GlobalMatricesUBO, 0, sizeof(glm::mat4) * 2);
This code works until I comment out the call to glBufferData, in which case I get a black screen. This is surprising to me because afterwards we are binding g_GlobalMatricesUBO to the GL_UNIFORM_BUFFER binding target anyways. The documentation linked to earlier also says:
Do note that this does not replace standard buffer binding with glBindBuffer. It does in fact bind the buffer to the target​ parameter, thus unbinding whatever was bound to that target. But usually when you use glBindBufferRange, you are serious about wanting to use the buffer rather than just modify it.
Which seems to touch on what I'm confused about, but I do not understand this explanation. It says it unbinds whatever was previously bound to the target, which seems to reinforce my (wrong) idea that binding a buffer to the target beforehand is unnecessary.
glBufferData does not only initialize the buffer, it creates the buffer object's data store with the specified size. You can think about it like memory allocation in c++.
glBufferData creates a data store for the buffer object which is currently bound to the specified target. In this case it creates a data store for the named buffer object g_GlobalMatricesUBO, because it is bound to the specified target GL_UNIFORM_BUFFER.
glBindBufferRange doesn't create any data store, it use the data store which has to exist. The buffer object with the data store is specified by the 3rd parameter.

OpenGL: Do I still need an array of vertices after buffering to VBO?

Let's say that I have an array of vertices and a VBO pointer:
std::vector<Vertex> vertices;
GLuint vbo;
glBindBuffer(GL_ARRAY_BUFFER, vbo);
Now I buffer the data:
glBufferData(
GL_ARRAY_BUFFER,
vertices.size()*sizeof(Vertex),
&vertices[0],
GL_STATIC_DRAW
);
If I understand this correctly I still need to keep vertices array due to GL_STATIC_DRAW. However if I change it to GL_STATIC_COPY then all of the data will be copied to GPU's memory so I can free memory used by vertices. Is that correct? If that's the case why do we need *_DRAW? Is that useful because of the GPU's memory limit? Plus how does GL_STATIC_READ really work?
All of this is explained in the glBufferData() man pages.
https://www.opengl.org/sdk/docs/man/html/glBufferData.xhtml
You don't need to keep an extra copy in your program's memory. The whole purpose of glBufferData() is to copy data from your program to an OpenGL buffer, once the copy is complete, you can do whatever you want with your program memory.
If data is not NULL, the data store is initialized with data from this pointer.
Do not use GL_STATIC_COPY, that is incorrect. The documentation reads:
COPY
The data store contents are modified by reading data from the GL, and used as the source for GL drawing and image specification commands.
So GL_STATIC_COPY is only for internal copies between different OpenGL buffers, not for copies from your application to OpenGL. Use DRAW.

How does VAO keep buffer bindings?

I am struggling to understand how exactly VAO is handling buffer mapping.
What I'm doing could be described in this pseudocode:
SetUp:
BindVAO
BindArrayBuffer
glBufferData(GL_ARRAY_BUFFER, ExpectedMaxCount, NULL, GL_DYNAMIC_DRAW);//Allocate storage
glEnableVertexAttribArray
glVertexAttribPointer
BindElementBuffer
Allocate storage (no data yet)
UnbindVAO
UnbindArrayBuffer
UnbindElementBuffer
Draw:
SubArrayAndElementDataIfNeeded
BindVAO
DrawElements
Is this correct that when DrawElements is called OpenGL uses bound VAO to resolve array and element buffer bindings? After a Draw call the bound array buffer is 0, but element buffer is still the one that was used to Draw.
Is it mandatory to allocate buffer memory during VAO setup? Would VAO be invalidated if BufferData was called after setup?
I am struggling to understand how exactly VAO is handling buffer mapping.
Be very careful when using the word "mapping" around "buffers"; that has a specific meaning when dealing with buffer objects, one that you probably don't intend.
Is this correct that when DrawElements is called OpenGL uses bound VAO to resolve array and element buffer bindings? After a Draw call the bound array buffer is 0, but element buffer is still the one that was used to Draw.
One has nothing to do with the other. A Vertex Array Object, as the name implies, contains all of the state that is necessary to pull vertex data from arrays. When you bind one, all of that state comes back into the context.
The reason the "bound array buffer" is 0 after the call is because it was 0 before the call. Draw calls do not change OpenGL state.
Furthermore, you seem to have fallen for the GL_ARRAY_BUFFER trap. The GL_ARRAY_BUFFER binding only matters to three functions: glVertexAttribPointer, glVertexAttribIPointer, and glVertexAttribLPointer (see a pattern?). These are the only functions that look at that binding. What they do is take the buffer that is bound at the time these functions are called and associates that buffer with the current VAO. GL_ARRAY_BUFFER is not part of the VAO's state. A buffer object becomes associated with a VAO only when you call one of those three functions. Once you make that call, you can bind whatever you want to GL_ARRAY_BUFFER.
GL_ELEMENT_ARRAY_BUFFER is part of the VAO's state.
Is it mandatory to allocate buffer memory during VAO setup? Would VAO be invalidated if BufferData was called after setup?
Technically no, but it's good form to not use a buffer until it has storage. Especially if they're static buffers.