What is the significance of the target argument in glBufferData - opengl

When creating a Buffer and setting its data, it is required to bind it first to a target and then populate the buffer bound to that target with some data:
GLenum target = GL_ARRAY_BUFFER;
glGenBuffers(1, &bufferId);
glBindBuffer(target, bufferId);
glBufferData(target, m_capacity*sizeof(value_type), m_data, GL_STREAM_DRAW);
glBindBuffer(target, 0);
But to my understanding it does not really matter if I a buffer that was populated on the GL_ARRAY_BUFFER target is later used on e.g. the GL_UNIFORM_BUFFER target. But if this is the case why do we need the target to populate the buffer and why is the signature of glBufferData not:
void glBufferData( GLint bufferId,
GLsizeiptr size,
const GLvoid * data,
GLenum usage);
Is that just a historical reason or because opengl is a statemachine or do I miss something and the target has an other purpose there.

This is a common OpenGL API thing - most of the work with OpenGL objects (textures, buffers, ...) is done via binding them to a specific target and then using this target to refer to currently bound object (more on this here). Unfortunatelly, I do not know the exact reason for this, but it seems to appear historical now - I've seen some proposed extension for direct object access via object id's (UPD: user ratchet freak says that it is direct_state_access extension, core in 4.5).
The documentation on glBindBuffer says that
When a buffer object is bound to a target, the previous binding for that target is automatically broken.
I'd suppose that changing a buffer's binding type and expecting the buffer's state to stay preserved is not a good idea.
UPDATE
From OpenGL wiki
The target​ defines how you intend to use this binding of the buffer object. When you're just creating and/or filling the buffer object with data, the target you use doesn't technically matter.
So, it seems that the target matters only on how you use the buffer, and you can safely bind it to any random type and fill it with data, but it still seems to be a bad practice.

To use glBufferData, you need some way of indicating the target of the data you are uploading. The target parameter (the first one), lets this call know the destination for your data. If your only aim is to upload the data and then unbind, as you said, it doesn't really matter which buffer binding you use. You are free to bind that buffer to any other binding at a later time.
However, it quite common to setup vertex attributes during GL_ARRAY_BUFFER data initialization time as well (with glVertexAttribPointer/glEnableVertexArray), which might be another reason to use GL_ARRAY_BUFFER binding over any other arbitrary binding. Also, if you intend to actually use the buffer data you are uploading in a subsequent draw call, and don't need to break the binding, it is more efficient to leave the binding in place.

Related

How to use a single buffer object as both VBO and UBO (possibly any other kind of buffers also) in opengl

My question relates to how allocations are handled in opengl.
If you create a buffer object using glGenBuffers(1, &id) then let's say populate it with a mesh's vertex data using glBindBuffer(GL_ARRAY_BUFFER, id) and glBufferData(GL_ARRAY_BUFFER, ...). The question I have now is : will the data I uploaded be bound to the GL_ARRAY_BUFFER tag specifically? So could I for example later use glBindBuffer(GL_UNIFORM_BUFFER, id) and use that data as a uniform buffer or does changing the associated target cause memory to be freed forcing me to use glGetBufferSubData to retrieve and re-upload the data now bound to the GL_UNIFORM_BUFFER tag? It seems intuitive that a buffer object keeps it's data as long as it is not deleted and that the target parameter is more to hint to the gpu where the data might be more optimally stored and what operations might be done with the buffer. What effects does doing something like this have on the state of opengl and is there a recommended alternative other than duel-uploading or re-uploading.
The buffer target does not have any effect on the content of a buffer. A buffer itself doesn't even know to which target it is bound. You can at any time bind the buffer to any other target and it can even be bound to multiple targets at the same time.
Buffer targets are only used by the API to determine which buffer a command should operate on. For example, glBufferData requires you to bind the buffer to the same target that you pass to it. But it doesn't really matter which target you are using. Some other commands, like glVertexAttribPointer expect a buffer to be bound to a certain target, but also here the binding doesn't alter/modify the buffer itself.
Note, that Direct State Access (DSA) methods which are core since OpenGL 4.5 do not use binding targets at all while providing the same functionality as the stateful methods.

Uploading index buffer without changing VAO state

In order to upload an index buffer to the GPU, I have to call glBindBuffer with GL_ELEMENT_ARRAY_BUFFER then call glBufferData etc. on it.
However, for my engine design where everything is condensed into as few functions as possible this comes unhandy as using GL_ELEMENT_ARRAY_BUFFER with glBindBuffer changes VAO state and I would like to deal with the buffers without changing VAO state.
Can someone tell me if it is possible to allocate and upload an index buffer without touching VAO state? Or would I have to restore GL_ELEMENT_ARRAY_BUFFER state manually?
The following assumes that direct state access functionality is not available to you. If it is, you should just use that, so that you don't have to bind objects just to modify them in the first place.
There is no such thing as an "index buffer" in the OpenGL API. There are just buffer objects, which can be at any point used for any number of purposes (one of which is for vertex indices in a rendering command). No buffer is ever wedded to the notion of being specifically for index data.
Buffer binding points therefore are meaningful only to the degree that you use the functionality associated with those binding points. GL_ARRAY_BUFFER is meaningful only because glVertexAttribPointer calls look at the buffer bound to that binding point. But if you're not actually making a glVertexAttribPointer call, then GL_ARRAY_BUFFER is just a binding point, no different from any other.
For general buffer object management, you therefore can bind any buffer to any binding point. GL_UNIFORM_BUFFER, GL_COPY_READ_BUFFER​, whatever. If you're not using the binding for its special purpose, then no binding is different from another (except GL_ELEMENT_ARRAY_BINDING which is part of VAO state).
So just bind the "index buffer" to some innocuous binding point (the indexed ones like GL_UNIFORM_BUFFER are particularly harmless, since they only get special functions when you use glBindBufferRange) and do your upload from there.

First Inizialization of VBO. Does it matter where to bind?

Say i want just to create and fill a buffer.
GLuint ret;
glGenBuffers(1,&ret);
glBindBuffer(GL_ARRAY_BUFFER, ret);
glBufferData(GL_ARRAY_BUFFER,size,data,usage);
glBindBuffer(GL_ARRAY_BUFFER,0);
Does it really matter which target i use in the two calls? (Of course they must be the same).
For example: can i fill the buffer writing to the GL_ARRAY_BUFFER target while it's binded on it and later on in the code bind the sane buffer to the GL_UNIFORM_BUFFER target and use it's data for filling a uniform block with glBindBufferRange?
It does not matter; any target should work. I've created buffers with targets matching the intended usage before and it made no difference.
I guess an OpenGL implementation (i.e. driver) could allocate memory differently depending on the target passed but I've not seen evidence of this.
Also, the newer glNamedBufferData which does the same thing as glBufferData without requiring a previous glBindBuffer call does not have a target parameter. This hints strongly that the targets are interchangeable.

Binding to GL_ELEMENT_ARRAY_BUFFER with no VAO bound

The buffer currently bound to the GL_ELEMENT_ARRAY_BUFFER target in OpenGL is part of the state contained in a Vertex Array Object (VAO from here on). According to the OpenGL 4.4 core profile spec then, it would seem that attempting to change or access the GL_ELEMENT_ARRAY_BUFFER while no VAO is bound is an error:
10.4 Vertex Array Objects
... An INVALID_OPERATION error is generated by any commands which
modify, draw from, or query vertex array state when no vertex array
is bound. This occurs in the initial GL state, and may occur as a
result of BindVertexArray or a side effect of DeleteVertexArrays.
This is supported by the OpenGL wiki's Buffer Object page:
GL_ELEMENT_ARRAY_BUFFER​
All rendering functions of the form gl*Draw*Elements*​ will use the pointer
field as a byte offset from the beginning of the buffer object bound to this
target. The indices used for indexed rendering will be taken from the buffer
object. Note that this binding target is part of a Vertex Array Objects state,
so a VAO must be bound before binding a buffer here.
Now, it would be nice if this were not the case. It would make it easy to create and manage index buffers separately from any particular VAO. But if just binding a buffer to GL_ELEMENT_ARRAY_BUFFER is verboten when there's no VAO bound, the only alternative is for the class representing an index buffer to bind a dummy VAO when they are created/updated/etc.
Nicol Bolas' excellent OpenGL tutorial says that this type of use is in fact valid:
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER): Calling this without a VAO bound will not fail.
This seems to contradict the standard and opengl.org wiki. Is there something in the standard supporting this that I've missed, or is this only referring to compatibility profile contexts where using a VAO is not required?
If you have an AMD or NV GPU you can always use the EXT_direct_state_access extension to manipulate a buffer object without binding it (this is purely a driver feature and does not require any special class of hardware). Sadly, Intel, Mesa and Apple have not bothered to implement this extension despite its 5 year existence -- lazy slackers.
Have a look at the following functions, they will make what you are describing a lot easier:
glNamedBufferDataEXT (...)
glNamedBufferSubDataEXT (...)
glMapNamedBufferEXT (...)
glUnmapNamedBufferEXT (...)
Now, since adoption of DSA is sparse, you will probably have to write some fallback code for systems that do not support it. You can reproduce the functionality of DSA by writing functions with identical function signatures that use a dummy VAO to bind VBOs and IBOs for data manipulation on systems that do not support the extension. You will have to keep track of what VAO was bound before you use it, and restore it before said function returns to eliminate side-effects.
In a good engine you should shadow the VAO binding state rather than having to query it from GL. That is, instead of using glBindVertexArray (...) directly you implement a system that wraps that call and therefore always knows what VAO is bound to a particular context. In the end, this makes emulating DSA functionality where driver support does not exist a lot more efficient. If you attempt something like this, you need to be aware that glDelete (...) functions implicitly unbind (by binding 0) the object being deleted if it is bound in the current context.
But if just binding a buffer to GL_ELEMENT_ARRAY_BUFFER is verboten when there's no VAO bound, the only alternative is for the class representing an index buffer to bind a dummy VAO when they are created/updated/etc.
New reply to an old question, but a simple way to work with an index buffer without requiring a VAO (or interfering with the currently bound VAO) is to bind the buffer to a target other than GL_ELEMENT_ARRAY_BUFFER.
For example, instead of this:
glBindVertexArray(vaoID); // ...Do I even have a VAO yet?
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID); // <- Alters VAO state!
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, ...);
-- one might write this instead:
glBindBuffer(GL_COPY_WRITE_BUFFER, indexBufferID);
glBufferSubData(GL_COPY_WRITE_BUFFER, ...);
(Here I arbitrarily used GL_COPY_WRITE_BUFFER, which exists to provide a temporary target to make copying between buffers easier, but most other targets would be fine as well.)

Concept behind OpenGL's 'Bind' functions

I am learning OpenGL from this tutorial.
My question is about the specification in general, not about a specific function or topic.
When seeing code like the following:
glGenBuffers(1, &positionBufferObject);
glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
I'm confused about the utility of calling the bind functions before and after setting the buffer data.
It seems superfluous to me, due to my inexperience with OpenGL and Computer Graphics in general.
The man page says that:
glBindBuffer lets you create or use a named buffer object. Calling glBindBuffer with target set to
GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER or GL_PIXEL_UNPACK_BUFFER and buffer set to the
name of the new buffer object binds the buffer object name to the target. When a buffer object is bound to a
target, the previous binding for that target is automatically broken.
What exactly is the concept/utility of 'binding' something to a 'target' ?
the commands in opengl don't exist in isolation. they assume the existence of a context. one way to think of this is that there is, hidden in the background, an opengl object, and the functions are methods on that object.
so when you call a function, what it does depends on the arguments, of course, but also on the internal state of opengl - on the context/object.
this is very clear with bind, which says "set this as the current X". then later functions modify the "current X" (where X might be buffer, for example). [update:] and as you say, the thing that is being set (the attribute in the object, or the "data member") is the first argument to bind. so GL_ARRAY_BUFFER names a particular thing that you are setting.
and to answer the second part of the question - setting it to 0 simply clears the value so you don't accidentally make unplanned changes elsewhere.
The OpenGL technique can be incredibly opaque and confusing. I know! I've been writing 3D engines based upon OpenGL for years (off and on). In my case part of the problem is, I write the engine to hide the underlying 3D API (OpenGL), so once I get something working I never see the OpenGL code again.
But here is one technique that helps my brain comprehend the "OpenGL way". I think this way of thinking about it is true (but not the whole story).
Think about the hardware graphics/GPU cards. They have certain capabilities implemented in hardware. For example, the GPU may only be able to update (write) one texture at a time. Nonetheless, it is mandatory that the GPU contain many textures within the RAM inside the GPU, because transfer between CPU memory and GPU memory is very slow.
So what the OpenGL API does is to create the notion of an "active texture". Then when we call an OpenGL API function to copy an image into a texture, we must do it this way:
1: generate a texture and assign its identifier to an unsigned integer variable.
2: bind the texture to the GL_TEXTURE bind point (or some such bind point).
3: specify the size and format of the texture bound to GL_TEXTURE target.
4: copy some image we want on the texture to the GL_TEXTURE target.
And if we want to draw an image on another texture, we must repeat that same process.
When we are finally ready to render something on the display, we need our code to make one or more of the textures we created and copied images upon to become accessible by our fragment shader.
As it turns out, the fragment shader can access more than one texture at a time by accessing multiple "texture units" (one texture per texture unit). So, our code must bind the textures we want to make available to the texture units our fragment shaders expect them bound to.
So we must do something like this:
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, mytexture0);
glActiveTexture (GL_TEXTURE1);
glBindTexture (GL_TEXTURE_2D, mytexture1);
glActiveTexture (GL_TEXTURE2);
glBindTexture (GL_TEXTURE_2D, mytexture2);
glActiveTexture (GL_TEXTURE3);
glBindTexture (GL_TEXTURE_2D, mytexture3);
Now, I must say that I love OpenGL for many reasons, but this approach drive me CRAZY. That's because all the software I have written for years would look like this instead:
error = glSetTexture (GL_TEXTURE0, GL_TEXTURE_2D, mytexture0);
error = glSetTexture (GL_TEXTURE1, GL_TEXTURE_2D, mytexture1);
error = glSetTexture (GL_TEXTURE2, GL_TEXTURE_2D, mytexture2);
error = glSetTexture (GL_TEXTURE3, GL_TEXTURE_2D, mytexture3);
Bamo. No need for setting all this state over and over and over again. Just specify which texture-unit to attach the texture to, plus the texture-type to indicate how to access the texture, plus the ID of the texture I want to attach to the texture unit.
I also wouldn't need to bind a texture as the active texture to copy an image to it, I would just give the ID of the texture I wanted to copy to. Why should it need to be bound?
Well, there's the catch that forces OpenGL to be structured in the crazy way it is. Because the hardware does some things, and the software driver does other things, and because what is done where is a variable (depends on GPU card), they need some way to keep the complexity under control. Their solution is essentially to have only one bind point for each kind of entity/object, and to require we bind our entities to those bind points before we call functions that manipulate them. And as a second purpose, binding entities is what makes them available to the GPU, and our various shaders that execute in the GPU.
At least that's how I keep the "OpenGL way" straight in my head. Frankly, if someone really, really, REALLY understands all the reasons OpenGL is (and must be) structured the way it is, I'd love them to post their own reply. I believe this is an important question and topic, and the rationale is rarely if ever described at all, much less in a manner that my puny brain can comprehend.
From the section Introduction: What is OpenGL?
Complex aggregates like structs are never directly exposed in OpenGL. Any such constructs are hidden behind the API. This makes it easier to expose the OpenGL API to non-C languages without having a complex conversion layer.
In C++, if you wanted an object that contained an integer, a float, and a string, you would create it and access it like this:
struct Object
{
int count;
float opacity;
char *name;
};
//Create the storage for the object.
Object newObject;
//Put data into the object.
newObject.count = 5;
newObject.opacity = 0.4f;
newObject.name = "Some String";
In OpenGL, you would use an API that looks more like this:
//Create the storage for the object
GLuint objectName;
glGenObject(1, &objectName);
//Put data into the object.
glBindObject(GL_MODIFY, objectName);
glObjectParameteri(GL_MODIFY, GL_OBJECT_COUNT, 5);
glObjectParameterf(GL_MODIFY, GL_OBJECT_OPACITY, 0.4f);
glObjectParameters(GL_MODIFY, GL_OBJECT_NAME, "Some String");
None of these are actual OpenGL commands, of course. This is simply an example of what the interface to such an object would look like.
OpenGL owns the storage for all OpenGL objects. Because of this, the user can only access an object by reference. Almost all OpenGL objects are referred to by an unsigned integer (the GLuint). Objects are created by a function of the form glGen*, where * is the type of the object. The first parameter is the number of objects to create, and the second is a GLuint* array that receives the newly created object names.
To modify most objects, they must first be bound to the context. Many objects can be bound to different locations in the context; this allows the same object to be used in different ways. These different locations are called targets; all objects have a list of valid targets, and some have only one. In the above example, the fictitious target “GL_MODIFY” is the location where objectName is bound.
This is how most OpenGL objects work, and buffer objects are "most OpenGL objects."
And if that's not good enough, the tutorial covers it again in Chapter 1: Following the Data:
void InitializeVertexBuffer()
{
glGenBuffers(1, &positionBufferObject);
glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
The first line creates the buffer object, storing the handle to the object in the global variable positionBufferObject. Though the object now exists, it does not own any memory yet. That is because we have not allocated any with this object.
The glBindBuffer function binds the newly-created buffer object to the GL_ARRAY_BUFFER binding target. As mentioned in the introduction, objects in OpenGL usually have to be bound to the context in order for them to do anything, and buffer objects are no exception.
The glBufferData function performs two operations. It allocates memory for the buffer currently bound to GL_ARRAY_BUFFER, which is the one we just created and bound. We already have some vertex data; the problem is that it is in our memory rather than OpenGL's memory. The sizeof(vertexPositions) uses the C++ compiler to determine the byte size of the vertexPositions array. We then pass this size to glBufferData as the size of memory to allocate for this buffer object. Thus, we allocate enough GPU memory to store our vertex data.
The other operation that glBufferData performs is copying data from our memory array into the buffer object. The third parameter controls this. If this value is not NULL, as in this case, glBufferData will copy the data referenced by the pointer into the buffer object. After this function call, the buffer object stores exactly what vertexPositions stores.
The fourth parameter is something we will look at in future tutorials.
The second bind buffer call is simply cleanup. By binding the buffer object 0 to GL_ARRAY_BUFFER, we cause the buffer object previously bound to that target to become unbound from it. Zero in this cases works a lot like the NULL pointer. This was not strictly necessary, as any later binds to this target will simply unbind what is already there. But unless you have very strict control over your rendering, it is usually a good idea to unbind the objects you bind.
Binding a buffer to a target is something like setting a global variable. Subsequent function calls then operate on that global data. In the case of OpenGL all the "global variables" together form a GL context. Virtually all GL functions read from that context or modify it in some way.
The glGenBuffers() call is sort of like malloc(), allocating a buffer; we set a global to point to it with glBindBuffer(); we call a function that operates on that global (glBufferData()) and then we set the global to NULL so it won't inadvertently operate on that buffer again using glBindBuffer().
OpenGL is what is known as a "state machine," to that end OpenGL has several "binding targets" each of which can only have one thing bound at once. Binding something else replaces the current bind, and thus changes it's state. Thus by binding buffers you are (re)defining the state of the machine.
As a state machine, whatever information you have bound will have an effect on the next output of the machine, in OpenGL that is its next draw-call. Once that is done you could bind new vertex data, bind new pixel data, bind new targets etc then initiate another draw call. If you wanted to create the illusion of movement on your screen, when you were satisfied you had drawn your entire scene (a 3d engine concept, not an OpenGL concept) you'd flip the framebuffer.