12
\$\begingroup\$

When I read doc on webGL or OpenGL there can be seen some patterns in how names of functions and objects are used. But I can't understand the difference between buffer object and an array.

There are "vertex buffer objects", "vertex array objects" and even some kind of "buffer array" or "arraybuffer".

In OpenGL context, When something is "array" and when it should be called a "buffer" instead?

\$\endgroup\$
  • \$\begingroup\$ Some perspective, think of fetching data over the network and storing a log of everything received. You need to read the socket and put the received data somewhere so you can pass it around, that's a buffer. It can often be a locally scoped, dynamically allocated simple list type. Sometimes it's as simple as a char* buffer = socketRead(); (pseudocode). The log on the other hand, lives through the entire app lifecycle. So you create an array somewhere and start reading the socket, anytime you get data you write that chunk to the array, giving you a neat list of all the data you received. \$\endgroup\$ – Kevin Nov 1 '18 at 15:12
5
\$\begingroup\$

The naming of Vertex Array Object is somewhat unfortunate. There's three different things that appear (used to appear) in/with/around your application, and which are (have been, historically) named differently, with "array" or "buffer" in the name (well, there's framebuffer objects too, but I'll ignore that).

  1. Data that lives in your application, formally and factually, but which is pulled by OpenGL in one go (as opposed to vertex-by-vertex). This was once upon a time what you would call vertex array.
    The intent of this was to make accessing more efficient since OpenGL could just copy the whole thing in one go at a well-defined time when you gave the promise that data was consistent, and push it over AGP or whatever in one block. This no longer exists.
  2. Data obscured and accessible by a handle that can be "bound", i.e. made active. Data may factually live in main memory, or on the graphics card, or be moved to a PCIe-mappable region, whatever, but either way you formally do not own (even if it is physically in RAM and if the data came from your application) it -- unless you have currently "mapped" it via the corresponding API, getting back a writeable (and sometimes readable) pointer. You are also limited in your ability of controlling what happens to the data at all (you can give some hints, but that's pretty much it).
    OpenGL may move this data around more or less freely, and you are only ever allowed/able to copy to/from the buffer via the corresponding API or access the data while it is being mapped. That is what you call a buffer object (vertex buffer object if it contains vertices, but it really doesn't have to, could as well be image data or uniforms, only vertices were the first to be supported, once upon a time).
    The intent of this is to guarantee that OpenGL can (in principle) do what it wants, it can even push the buffer over PCIe speculatively before you even draw. That works because you do not own the data (OpenGL does!) and you can only access it via the given API, so it is known at all times that data is valid. The driver can even opt to throw away buffer memory on the graphics card when it needs memory for something different and later restore it from its secret copy when needed.
  3. A really stupid misnomer for which a much better name would be something like buffer-set or descriptor-set, this is the infamous vertex array object. It is, from your point of view, nothing but a set of buffer handles bunched together under another obscure handle (which you can bind). As it happens, reality is a bit more complicated. In fact, VAO is much closer to how the actual hardware works. Graphic cards have a small number (often something like 2, 4, or 8) of descriptor sets (not just for buffers, but also for samplers) with so-and-so-many entries in each, between which they can switch very efficiently.
    Now, the intent of the vertex array object is to reduce the number of API calls and to reduce the number of consistency checks that OpenGL must make internally, and of course, to use the hardware as-it-works. If you bind 5 buffers, then each must go through some possibly expensive checks, and each one is a candidate for cache misses in the driver, plus each single one requires communicating with the graphics card to change a descriptor, etc etc. If you instead bind one VAO, the driver can (often) simply switch the descriptor set on the graphics card, and be done.
\$\endgroup\$
7
\$\begingroup\$

A Vertex Array Object (VAO) is an object which contains one or more Vertex Buffer Objects and is designed to store the information for a complete rendered object.

(pulled from khronos)

Each buffer tends to constitute one attribute of a vertex array (object). A VAO can contain many vertex attributes (e.g. position, color, UV). Each might be held in its own buffer, where buffer indicates an unformatted series of contiguous bytes, and where you need to explicitly specify the size (type) per buffer element for both CPU side OpenGL calls and GPU-side shader work.

That's one way. The other ways this can work are:

  • All of the attributes are stored interleaved in a single buffer, OR
  • Some of the attributes exist in their own dedicated buffers, while others share buffers.

The below diagram illustrates these latter two cases.

enter image description here

Bottom line: If the phrase "vertex array" is used unqualified in OpenGL, you can assume it means VAO, which, in an OpenGL context (specifically) is a very different thing indeed from a buffer.

EDIT re your comment: GL_ARRAY_BUFFER indicates an intention to use that buffer object for vertex attribute data, as described above. This is because buffers are not used only for vertex attributes. However, as it is the most common use-case and you are asking about VAOs, I won't go into the others; here however is a list of the other types of buffers that can be set up.

\$\endgroup\$
  • \$\begingroup\$ So buffers are: 1.reside in GPU, 2.most of the time contain one kind of data (only vertex, only color ect), 3.Data is interleaved, that is 111122223333 ect. 4. provide no method to access data (not buffer[2] or buffer[vertex_3434]) Now, arrays are: 1.collection of buffers, 2.store information on how to parse buffers which it contains.(that is array store stride, size of an element, offsets, so data from buffers can be accessed correctly. right? \$\endgroup\$ – coobit Nov 1 '18 at 10:33
  • \$\begingroup\$ 1. Buffers exist on both ends and transfer between CPU and GPU (back AND forth potentially), else how would you populate the data to be uploaded to GPU when loading a mesh from disk?. Yes, elements are of uniform type throughout the buffer, but depending on the tech you are using, each buffer element can be either a primitive or a struct type. Data may be interleaved or be completely uniform, per buffer. You can index into them, just as with a traditional C array on the CPU. Array objects (use this correct terminology or end up confusing yourself!)... (continued below) \$\endgroup\$ – Engineer Nov 1 '18 at 10:43
  • \$\begingroup\$ 2. Yes, and you need to explicitly make sure your in-shader buffer declarations will match those specifications you set on your VAO on the CPU side: "All state related to the definition of data used by the vertex processor is encapsulated in a vertex array object." (khronos docs) \$\endgroup\$ – Engineer Nov 1 '18 at 10:43
  • \$\begingroup\$ So, just to hit the nail more... How did people work before AO only using BO? Or AO were always present in OpenGL and it's just VAO which was introduced later then VBO? \$\endgroup\$ – coobit Nov 1 '18 at 11:02
  • \$\begingroup\$ @coobit io7m.com/documents/history-vertex-spec - this gives you an idea of the differences between fixed pipeline (old school) OpenGL, 3Dfx etc. and modern, programmable pipeline OpenGL and Direct3D. \$\endgroup\$ – Engineer Nov 1 '18 at 11:08
5
\$\begingroup\$

This terminology is rooted in the history of OpenGL. What's important to remember is that, for most of the GL versions which are relevant here, OpenGL was evolved incrementally and by adding new functionality to an already existing API rather than changing the API.

The first version of OpenGL had none of these object types. Drawing was achieved by issuing multiple glBegin/glEnd calls, and one problem with this model was that it was very inefficient, in terms of function call overhead.

OpenGL 1.1 took the first steps to address this by introducing vertex arrays. Instead of directly specifying vertex data you could now source it from C/C++ arrays - hence the name. So a vertex array is just that - an array of vertices and the GL state required to specify them.

The next major evolution came with GL 1.5 and allowed storing vertex array data in GPU memory rather than in system ("client-side") memory. A weakness of the GL 1.1 vertex array specification was that the full set of vertex data had to be transferred to the GPU each time you wanted to use it; if it was already on the GPU then this transfer could be avoided and potential performance gains achieved.

So a new type of GL object was created to allow storing of this data on the GPU. Just like a texture object is used for storing texture data, a vertex buffer object stores vertex data. This is actually just a special case of a more general buffer object type which may store non-specific data.

The API for using vertex buffer objects was piggy-backed on the already existing vertex arrays API, which is why you see weird things like converting byte offsets to pointers in it. So now we have a vertex arrays API that just stores state, with the data being sourced from buffer objects rather than from in-memory arrays.

This brings us almost to the end of our story. The resulting API was quite verbose when it came to specifying vertex array state, so another avenue of optimization was to create a new object type that collected all of this state together, allowed multiple vertex array state changes in a single API call, and allowed GPUs to potentially perform optimizations due to being able to know what state was going to be used ahead of time.

Enter the vertex array object, which collects all of this together.

So, to summarise, a vertex array started life as a collection of state and data (stored in an array) for drawing with. A vertex buffer replaces the in-memory array storage with a GL object type, leaving the vertex array just being state. A vertex array object is just a container object for this state, allowing it to be changed more easily and with fewer API calls.

\$\endgroup\$
0
\$\begingroup\$

I havent worked with OpenGL in a while, so I might only be half-right. Generally speaking: Buffers store an array of unformatted memory. An array is a general term of contiguous memory.

A buffer needs to be bound to the context, whereas an array is just an array of data. If i recall correctly, the data in the buffer is meant to be copied onto the graphics card (hence the binding).

Hope this helps a bit

\$\endgroup\$
  • \$\begingroup\$ What is GL_ARRAY_BUFFER then? Why it was called so? According to you hypothesis it is "Unformatted contiguous memory" :) \$\endgroup\$ – coobit Nov 1 '18 at 9:33
  • \$\begingroup\$ Well, this particular example is just an id to a buffer (to which you bind your array). The Array Buffer (in your example) is used for vertex attributes, so basically you bind your vertex attribute array to a buffer. Sounds confusing so let me give you an example. You have some array on the cpu-side which could be color, normal, positions, etc, and now you want the gpu access it. Thats when the bindBuffer comes in, basically mapping your "cpu-array" to the "gpu-array". \$\endgroup\$ – Juicef Nov 2 '18 at 10:26
  • \$\begingroup\$ As to why it was called so, I cannot answer that. I would presume that it is because you have an array of different data that goes in there, color, normal, etc. \$\endgroup\$ – Juicef Nov 2 '18 at 10:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.