Difference between revisions of "Buffer Object"

From OpenGL.org
Jump to: navigation, search
(Adding the object float.)
(47 intermediate revisions by 3 users not shown)
Line 1: Line 1:
'''Buffer Objects''' is the general term for unformatted linear memory allocated by the OpenGL context. These can be used to store [[Vertex Buffer Objects|vertex data]], pixel data retrieved from images or the framebuffer, and a variety of other things.
+
{{object float}}
 +
 
 +
'''Buffer Objects''' is the general term for unformatted linear memory allocated by the OpenGL context. These can be used to store [[Vertex Buffer Objects|vertex data]], [[Pixel Buffer Object|pixel data retrieved from images or the framebuffer,]] and a [[#General use|variety of other things]].
  
 
== Versioning ==
 
== Versioning ==
Line 9: Line 11:
 
== Creation ==
 
== Creation ==
  
Buffer Objects are [[OpenGL Objects]]; they therefore follow all of the rules of regular OpenGL objects. To create a buffer object, you call <code>glGenBuffers</code>. Deleting them uses <code>glDeleteBuffers</code>. These use the standard Gen/Delete paradigm as most OpenGL objects.
+
Buffer Objects are [[OpenGL Objects]]; they therefore follow all of the rules of regular OpenGL objects. To create a buffer object, you call {{apifunc|glGenBuffers}}. Deleting them uses {{apifunc|glDeleteBuffers}}. These use the standard Gen/Delete paradigm as most OpenGL objects.
  
As with the standard OpenGL object paradighm, this only creates the object's name, the reference to the object. To actually create the object itself, you must bind it to the context. You do this using the following API:
+
As with the standard OpenGL object paradigm, this only creates the object's name, the reference to the object. To actually create the object itself, you must bind it to the context. You do this using the following API:
  
<code>void glBindBuffer(enum ''target'', uint ''bufferName'')</code>
+
  void {{apifunc|glBindBuffer}}(enum ''target'', uint ''bufferName'')
  
The <code>target</code> 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 matter much. It matters more when you intend to tell OpenGL to use the data in the buffer in some way.
+
The <code>target</code> 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. It matters more when you intend to tell OpenGL to use the data in the buffer in some way.
 +
 
 +
: '''Performance Note:''' In the technical sense, the target a buffer is bound to does not matter for the purposes of creating the memory storage for it. However, OpenGL implementations are allowed to make judgments about your intended use of the buffer object based on the ''first'' target you bind it to. So if you intend for your buffer object to be used as a vertex array buffer, you should bind that buffer to GL_ARRAY_BUFFER first. You may later use it as a GL_TRANSFORM_FEEDBACK buffer for readback or whatever, but binding it to GL_ARRAY_BUFFER gives the implementation important information about how you plan to use it overall.
  
 
To create the actual memory storage for a buffer object, you use this API:
 
To create the actual memory storage for a buffer object, you use this API:
  
<code>void glBufferData(enum ''target'', sizeiptr ''size'', const void *''data'', enum ''usage'')</code>
+
  void {{apifunc|glBufferData}}(enum ''target'', sizeiptr ''size'', const void *''data'', enum ''usage'')
  
 
The <code>target</code> parameter is just like the one for <code>glBindBuffer</code>; it says which bound buffer to modify. <code>size</code> represents how many bytes you want to allocate in this buffer object.
 
The <code>target</code> parameter is just like the one for <code>glBindBuffer</code>; it says which bound buffer to modify. <code>size</code> represents how many bytes you want to allocate in this buffer object.
 
While it technically does not matter how you bind the buffer for creations vs. how you use it (create it with one target, unbind and bind it for use as another target) this is not recommended if you can at all help it. OpenGL implementations can, and will, make assumptions based on what target you used to create a buffer object, so don't try to confuse them.
 
  
 
The <code>data</code> parameter is a pointer to user memory that will be copied into the buffer object's data store. If this value is NULL, then no copying will occur, and the buffer object's data will be undefined.
 
The <code>data</code> parameter is a pointer to user memory that will be copied into the buffer object's data store. If this value is NULL, then no copying will occur, and the buffer object's data will be undefined.
Line 35: Line 37:
 
There are two independent parts to the usage pattern: how the user will be reading/writing from/to the buffer, and how often the user will be changing it relative to the use of the data.
 
There are two independent parts to the usage pattern: how the user will be reading/writing from/to the buffer, and how often the user will be changing it relative to the use of the data.
  
There are three ways that the user can specify the data.
+
There are two ways for data to cause a change in the data contents of a buffer object. One way is for the user to explicitly upload some binary data. The other way is for the user to issue GL commands that cause the buffer to be filled in. For example, if you want to have a buffer store the results of a vertex shader computation through the use of transform feedback, the user is not directly changing the buffer information. So this is the latter kind of change.
  
* DRAW: The user will be uploading the data, but the user will not read it back.
+
Similarly, the user can read a buffer's data, using a variety of commands. Or, the user can execute an OpenGL command that causes the GL to read the contents of the buffer and do something based on it. Buffers storing vertex data are read by the GL when rendering.
* READ: The user will not be uploading the data (it will be filled in by GL commands), but the user will be reading it back.
+
* COPY: The user will be neither uploading nor reading the data.
+
  
DRAW is useful for, as the name suggests, drawing. Buffer objects holding vertex data are specified as DRAW.
+
There are three hints that the user can specify the data. They are all based on what the ''user'' will be doing with the buffer. That is, whether the user will be directly reading or writing the buffer's data.
  
READ is used when a buffer object is an intermediate for asynchronous delivery of image data. You can use <code>glReadPixels</code> or <code>glGetTexSubImage</code> to read data into a buffer object.
+
* DRAW: The user will be writing data to the buffer, but the user will not read it.
 +
* READ: The user will not be writing data, but the user will be reading it back.
 +
* COPY: The user will be neither writing nor reading the data.
  
COPY is used when a buffer object is used to pass data from one place in OpenGL to another. For example, you can read image data into a buffer, then use that image data as vertex data in a draw call. You can also use transform feedback to achieve the same thing in a more direct way. You have the feedback data go to a buffer object, then use that buffer object as vertex data.
+
DRAW is useful for, as the name suggests, drawing. The user is uploading data, but only the GL is reading it. Buffer objects holding vertex data are generally specified as DRAW, though there can be exceptions.
  
There are three ways that the user can be changing the data.
+
READ is used when a buffer object is used as the destination for OpenGL commands. This could be rendering to a [[Buffer Texture]], using [[Image Load Store|arbitrary writes to buffer textures]], doing a [[Pixel Buffer Object|pixel transfer into a buffer object]], using [[Transform Feedback]], or any other OpenGL operation that writes to buffer objects.
 +
 
 +
COPY is used when a buffer object is used to pass data from one place in OpenGL to another. For example, you can read image data into a buffer, then use that image data as vertex data in a draw call. Your code never actually sends data to the buffer directly, nor does it read data back. You can also use [[Transform Feedback]] to achieve the same thing in a more direct way. You have the feedback data go to a buffer object, then use that buffer object as vertex data. And while the user is causing the buffer to be updated via rendering commands, at no time is the user ''directly'' either reading from or writing to the buffer's storage.
 +
 
 +
There are three hints for how frequently the user will be changing the buffer's data.
  
 
* STATIC: The user will set the data once.
 
* STATIC: The user will set the data once.
* DYNAMIC: The user will set the data occassionally.
+
* DYNAMIC: The user will set the data occasionally.
 
* STREAM: The user will be changing the data after every use. Or almost every use.
 
* STREAM: The user will be changing the data after every use. Or almost every use.
  
STREAM is pretty easy to understand: the buffer object's contents will be updated after almost every use. STATIC is pretty easy to understand too. The buffer object's contents will be updated once and never changed.
+
STREAM is pretty easy to understand: the buffer object's storage will be updated after almost every use. STATIC is pretty easy to understand too. The buffer object's contents will be updated once and never changed.
  
What is unclear is when DYNAMIC becomes STREAM or STATIC. These are only hints, after all. It is pefectly legal OpenGL code to modify a STATIC buffer after it has been created, or to never modify a STREAM buffer.
+
What is unclear is when DYNAMIC becomes STREAM or STATIC. These are only hints, after all. It is perfectly legal OpenGL code to modify a STATIC buffer after it has been created, or to never modify a STREAM buffer.
  
Is it better to use STATIC for buffers that are updated very infrequently? Is it better to use DYNAMIC for buffers that get updated frequently, but not at STREAM speed? Is it better to use DYNAMIC for buffers that get ''partially'' updated? These are questions that can only be answered with careful profiling. And even then, the answer will only be accurate for that particular driver version of that particular hardware.
+
Is it better to use STATIC for buffers that are updated very infrequently? Is it better to use DYNAMIC for buffers that get updated frequently, but not at STREAM speed? Is it better to use DYNAMIC for buffers that get ''partially'' updated? These are questions that can only be answered with careful profiling. And even then, the answer will only be accurate for that particular driver version from that particular hardware vendor.
  
In any case, STREAM, STATIC, and DYNAMIC can be matched with READ, DRAW, and COPY in any combination. STREAM_COPY means that you will be doing transform feedback writes (or other kinds of GL-based writes) into the buffer after almost every use; it will not be updated with <code>BufferSubData</code> or similar functions. STATIC_READ means that you will fill the buffer up from the GL, but you will only do this once.
+
In any case, STREAM, STATIC, and DYNAMIC can be matched with READ, DRAW, and COPY in any combination. STREAM_COPY means that you will be doing transform feedback writes (or other kinds of GL-based writes) into the buffer after almost every use; it will not be updated with {{apifunc|glBufferSubData}} or similar functions. STATIC_READ means that you will fill the buffer up from the GL, but you will only do this once.
  
 
== Data Specification ==
 
== Data Specification ==
  
We have seen that <code>BufferData</code> can be used to update the data in a buffer object. However, this also recreates the buffer object, causing it to be reallocated. This is not usually what one wants, as recreating the buffer can often be a heavyweight operation.
+
We have seen that {{apifunc|glBufferData}} can be used to update the data in a buffer object. However, this also reallocates the buffer object's storage. This is not usually what one wants, as recreating the buffer can often be a heavyweight operation.
  
 
Instead, one can use the following API:
 
Instead, one can use the following API:
  
<code>void glBufferSubData(enum ''target'', intptr ''offset'', sizeiptr ''size'', const void *''data'')</code>
+
  void {{apifunc|glBufferSubData}}(enum ''target'', intptr ''offset'', sizeiptr ''size'', const void *''data'')
  
 
The <code>offset</code> parameter is an integer offset into the buffer object where we should begin updating. The <code>size</code> parameter is the number of bytes we should copy out of <code>data</code>. For obvious reasons, <code>data</code> cannot be NULL.
 
The <code>offset</code> parameter is an integer offset into the buffer object where we should begin updating. The <code>size</code> parameter is the number of bytes we should copy out of <code>data</code>. For obvious reasons, <code>data</code> cannot be NULL.
 +
 +
=== Clearing ===
 +
{{infobox feature
 +
| main = Buffer clearing
 +
| core = 4.3
 +
| core_extension = {{extref|clear_buffer_object}}
 +
}}
 +
 +
A buffer object's storage can be cleared, in part or in full, to a specific value. These functions work in a similar fashion to [[Pixel Transfer]] operations, though with some significant differences:
 +
{{clear float}}
 +
void {{apifunc|glClearBufferData}}(GLenum {{param|internalformat}}, GLenum {{param|format}}, GLenum {{param|type}}, const void * {{param|data}});
 +
void {{apifunc|glClearBufferSubData}}(GLenum {{param|internalformat}}, GLintptr {{param|offset}}, GLsizeiptr {{param|size}}, GLenum {{param|format}}, GLenum {{param|type}}, const void * {{param|data}});
 +
 +
{{apifunc|glClearBufferData}} works as {{apifunc|glClearBufferSubData}}, except it operates on the entire buffer's contents. It does not respecify the storage for the buffer.
 +
 +
{{param|internalformat}} must be a sized [[Image Format]], but only of the kind that [[Buffer Texture#Image formats|can be used for buffer textures]]. This defines how OpenGL will store the data in the buffer object. {{param|format}} and {{param|type}} operate as normal for [[Pixel Transfer]] operations.
 +
 +
{{param|data}} is a pointer to a single pixel's worth of data, rather than the rows that are used in actual pixel transfers. So if {{param|format}} is {{enum|GL_RG}} and {{param|type}} is {{enum|GL_UNSIGNED_BYTE}}, then {{param|data}} should be a pointer to an array of two {{code|GLubyte}}s.
 +
 +
This function will copy the given data repeatedly throughout the specified range of the buffer. {{param|offset}} must be a multiple of the byte size defined by the {{param|internalformat}}, as must {{param|size}}.
 +
 +
=== Copying ===
 +
 +
Data can be copied from one buffer object to another. To do this, first bind the source and destination buffers to different {{param|target}}s. These could be any target, but {{enum|GL_COPY_READ_BUFFER​}} and {{enum|GL_COPY_WRITE_BUFFER}} have no special semantics, so they make useful targets for this purpose.
 +
 +
Once both are bound, use this function:
 +
 +
void {{apifunc|glCopyBufferSubData}}(GLenum {{param|readtarget}}, GLenum {{param|writetarget}}, GLintptr {{param|readoffset}}, GLintptr {{param|writeoffset}}, GLsizeiptr {{param|size}});
 +
 +
{{param|readtarget}} is the buffer you bound the ''source'' buffer to. So this is where you get the data to copy from. {{param|writetarget}} is the buffer you bound the ''destination'' buffer to. {{param|readoffset}} is the byte offset from the beginning of the source buffer to start reading. {{param|writeoffset}} is the byte offset from the beginning of the destination buffer to start writing to. {{param|size}} is the number of bytes to read.
 +
 +
Errors will be given if the offset/sizes would cause reading to or writing from locations outside of the respective buffer objects' storage.
  
 
=== Mapping ===
 
=== Mapping ===
 +
{{apifunc|glBufferSubData}} is a nice way to present data to a buffer object. But it can be wasteful in performance, depending on your use patterns.
  
 +
For example, if you have an algorithm that generates data that you want to store in the buffer object, you must first allocate some temporary memory to store that data in. Then you can use {{apifunc|glBufferSubData}} to transfer it to OpenGL's memory. Similarly, if you want to read data back, {{apifunc|glGetBufferSubData}} is perhaps not what you need, though this is less likely. It would be really nice if you could just get a pointer to the buffer object's storage and write directly to it.
  
 +
You can. To do this, you must ''map'' the buffer. This gives you a pointer to memory that you can write to or read from, theoretically, just like any other. When you unmap the buffer, this invalidates the pointer (don't use it again), and the buffer object will be updated with the changes you made to it.
  
=== Streaming ===
+
While a buffer is mapped, you can freely unbind the buffer. However, you cannot call any function that would cause OpenGL to read, modify, or write to that buffer while it is mapped. Thus, calling {{apifunc|glBufferData}} is out, as is using any function that would cause OpenGL to read from it (rendering with a [[Vertex Array Objects|VAO]] that uses it, etc).
  
Buffer objects provide a number of possible usage patterns for streaming. Exactly which will work best depends on the particulars of the hardware.
+
To map a buffer, you call {{apifunc|glMapBufferRange}}. The signature of this function is this:
  
Tf you're streaming data, STREAM is going to need to be in your usage. And since we're talking about updating from the user side, you should be using STREAM_DRAW.
+
  void *{{apifunc|glMapBufferRange}}(GLenum {{param|target}}, GLintptr {{param|offset}}, GLsizeiptr {{param|length}}, GLbitfield {{param|access}});
  
There is a parallelism problem that can occur when streaming data. The OpenGL specification permits an implementation to delay the execution of drawing commands. This allows you to draw a lot of stuff, and then let OpenGL handle things on its own time. Because of this, it is entirely possible that, well after you called the rendering function with a buffer object, you might start trying to stream vertex data into that buffer. If this happens, the OpenGL specification requires that the thread halt until all drawing commands that could be affected by your update of the buffer object complete. This obviously misses the whole point of streaming.
+
The return value is the pointer to the buffer object's data. The parameters {{param|offset}} and {{param|length}} allow you to specify a particular range within the buffer to map; you do not have to map the entire buffer. The {{param|target}} parameter refers to the particular target that you have the buffer you want to map bound to.
  
This is going to be your main source of woe.
+
The {{param|access}} parameter is a bit complicated.
  
There is one tried-and-true method of avoiding this: manual double-buffering. That is, allocate two buffer objects of the same size. Fill one up and render with it, then switch to the other one when you need to stream some new vertices in.
+
You can tell OpenGL what you intend to do with the pointer. If you're just adding new data to the buffer, then the pointer that gets returned isn't something you need to read from. Similarly, it could be your intention to read from this pointer and not change the buffer; OpenGL could do a simple copy from the buffer's memory to scratch memory in the client address space to make reading the buffer faster (buffer memory may not be optimized for reading).
  
This is nice, and it gets around the above issue. But it has problems. Namely, that it takes up 2x the memory. Also, the STREAM hint is designed to deal with precisely this issue, so it is entirely possible that the implementation may double-buffer for you.
+
You specify this by setting bitflags in the {{param|access}} parameter. This parameter ''must'' have either the {{enum|GL_MAP_READ_BIT}} or {{enum|GL_MAP_WRITE_BIT}} set; it can have both (ie: the memory will be fit for reading and writing) but it can't have neither. There are a number of other flags that can be set.
  
Instead, you can try a variety of techniques to force the implementation to do what you need.
+
Unmapping the buffer is done when you are finished with the pointer and want to let OpenGL know that the buffer is free to be used. This is done with the function {{apifunc|glUnmapBuffer}}. This function takes only the target that the buffer in question is bound to. After calling this function, you should not use the pointer returned in the map call again.
  
<code>glMapBufferRange</code> with the GL_MAP_INVALIDATE_BUFFER_BIT set is one way to do it. Invalidating the buffer tells OpenGL that the entire buffer's contents will not be needed. This gives OpenGL the opertunity to orphan the buffer and allocate a new one. It also conveniently maps the buffer, so if you need to map the buffer to upload your data, there you are.
+
==== Buffer Corruption ====
  
If you call <code>glBufferData</code> with a NULL data pointer and the same usage hints and size, the OpenGL implementation can take this as a sign that you no longer care about the current contents of the buffer. Again, this allows OpenGL to orphan the buffer and allocate a new one.
+
There is one major gotcha when mapping a buffer.
  
Both of these can give the effect of double-buffering.
+
During normal OpenGL operations, the OpenGL specification requires that all data stored in OpenGL objects be preserved. Thus, if something in the operating system or other such things causes video memory to be trashed, the OpenGL implementation must ensure that this data is restored properly.
  
The deepest of the deep magic comes in <code>glMapBufferRange</code> with GL_MAP_UNSYNCHRONIZED_BIT. This guarantees that you will never halt due to the buffer being in use. Unfortunately, it also means that you can get a race condition, where you are updating a buffer object while it is being read from. The unsyncrhonized flag will prevent OpenGL from trying to stop this, but it won't prevent OpenGL from rendering wrong stuff when it does happen.
+
Mapping is not a normal operation. Because of its low-level nature, these protections have to be relaxed. Therefore, it is possible that, during the time a buffer is mapped, some kind of corruption happens. If this occurs, calling {{apifunc|glUnmapBuffer}} will return GL_FALSE. At that point, the contents of the buffer in question are considered undefined. It may have your data, or it may have random garbage.
  
To prevent it on your end, you can use the ARB_sync core extension (core in version 3.2). This allows you to ''ask'' whether a particular rendering command has finished by putting a fence after that command. Thus, if it has finished, you can do the streaming. If it hasn't, you can choose to do something else. That way, your thread isn't stopped.
+
How often does this happen? On Microsoft Windows 5.1 (XP) and below, video memory could get trashed anytime an application didn't have input focus. This is why alt-tabbing away from games takes a long time to recover from; the application/OpenGL has to reload all of this data back to video memory. Fortunately, on Windows 6.0 (Vista) and above, this is fixed; Windows itself manages video memory and will ensure that all video memory is retained. Thus, at least theoretically, this should never be a problem on Vista or above machines.
  
== General Use ==
+
==== Performance Concerns ====
 +
 
 +
One thing to remember about buffer mapping is this: the implementation is not obligated in any way to give you an actual pointer to the buffer object's memory. It is perfectly capable of giving you a pointer to some memory that OpenGL allocated just for the purpose of mapping, then it will do the copy on its own time.
 +
 
 +
The other thing to remember is that you should not care. OpenGL likes to give implementations flexibility to make performance optimizations. If mapping a certain buffer gives you some other pointer, and the implementation will do the copy on its own time, you should assume that this is probably the fastest way to work. It's still potentially faster than glBufferSubData, since the copy in glBufferSubData must happen before the function call returns, whereas the copy in the mapping case can happen in a thread the GL spawns. The worst case is that it's no slower than glBufferSubData.
 +
 
 +
However, you should not use the pointer you are given like any other pointer you might have. If this pointer is a pointer to non-standard memory (uncached or video memory), then writing to it haphazardly can be problematic. If you are attempting to stream data to the buffer, you should always map the buffer only for writing and you should write sequentially. You do not need to write every byte, but you should avoid going backwards or skipping around in the memory.
 +
 
 +
The purpose in writing sequentially is to be able to use write-combine memory, a feature of some processors (most x86's). It allows sequential writes to uncached memory to flow fairly quickly, compared to random writes to uncached memory.
 +
 
 +
=== Invalidation ===
 +
{{infobox feature
 +
| name = Buffer invalidation
 +
| core = 4.3
 +
| core_extension = {{extref|invalidate_subdata}}
 +
}}
 +
 
 +
{{apifunc|glMapBufferRange}} can invalidate part of a buffer or the entire thing using {{enum|GL_MAP_INVALIDATE_RANGE_BIT}} and {{enum|GL_MAP_INVALIDATE_BUFFER_BIT}}, respectively. You can force invalidation of a buffer without mapping it by using the following functions:
 +
{{clear float}}
 +
void {{apifunc|glInvalidateBufferData}}(GLuint {{param|buffer}});
 +
void {{apifunc|glInvalidateBufferSubData}}(GLuint {{param|buffer}}, GLintptr {{param|offset}}, GLsizeiptr {{param|length}});
 +
 
 +
{{apifunc|glInvalidateBufferData}} is equivalent to calling {{apifunc|glInvalidateBufferSubData}} with {{param|offset}} as 0 and {{param|length}} as the size of the buffer's storage.
 +
 
 +
When a buffer or region thereof is invalidated, it means that the contents of that buffer are now undefined. How OpenGL handles invalidation is up to it. Note that any pending operations on the buffer will still complete. Any pending reads from OpenGL will still get their original values, and any pending writes will still write their values.
 +
 
 +
The idea is that, by invalidating a buffer or range thereof, the implementation will simply grab a new piece of memory to use. Thus, while previously executed GL commands can still read the buffer's data, you can fill the invalidated buffer with new values (via mapping or {{apifunc|glBufferSubData}}) without causing [[Synchronization|synchronization]].
 +
 
 +
=== Streaming ===
 +
{{main|Buffer Object Streaming}}
 +
 
 +
Streaming is the process of frequently uploading data to a buffer object and then using that buffer object in some OpenGL process. Making this as efficient as possible is a delicate operation. Buffer objects provide a number of possible usage patterns for streaming, and which ones work best is not entirely clear. Testing should be done with the hardware of interest to make sure that you get optimal streaming performance.
 +
 
 +
The key to streaming is parallelism. The OpenGL specification permits an implementation to delay the execution of drawing commands. This allows you to draw a lot of stuff, and then let OpenGL handle things on its own time. Because of this, it is entirely possible that well after you called the rendering function with a buffer object, you might start trying to stream vertex data into that buffer. If this happens, the OpenGL specification requires that the thread halt until all drawing commands that could be affected by your update of the buffer object complete. This obviously misses the whole point of streaming.
 +
 
 +
The key to effective streaming is avoiding this [[Synchronization|synchronization]]. Or rather, avoiding it at all costs.
 +
 
 +
== General use ==
  
 
Most of the uses of buffer objects involve binding them to a certain target, then calling a function that behaves differently based on having a buffer object in that target. Usually, these functions take a pointer as one of their parameters. When a buffer object is bound to certain targets, it causes some functions that take a pointer parameter to treat that parameter as an offset into the buffer object. Thus, rather than pulling data from client memory pointers, they pull it from the bound buffer object.
 
Most of the uses of buffer objects involve binding them to a certain target, then calling a function that behaves differently based on having a buffer object in that target. Usually, these functions take a pointer as one of their parameters. When a buffer object is bound to certain targets, it causes some functions that take a pointer parameter to treat that parameter as an offset into the buffer object. Thus, rather than pulling data from client memory pointers, they pull it from the bound buffer object.
  
Indeed, in more recent versions of OpenGL, some of these functions are no longer allowed to take a regular pointer at all. They can only be used when a buffer object is bound to the proper target.
+
Here are the various targets for buffer objects and their associated uses:
 +
 
 +
; {{enum|GL_ARRAY_BUFFER}}
 +
: The buffer will be used as a [[Vertex Buffer Object|source for vertex data]], but only when {{apifunc|glVertexAttribPointer}} is called. The pointer field of this function is taken as a byte offset from the beginning of whatever buffer is currently bound to this target.
 +
; {{enum|GL_ELEMENT_ARRAY_BUFFER}}
 +
: All [[Vertex Rendering|rendering functions]] of the form {{code|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 Object]]s state, so a VAO ''must'' be bound before binding a buffer here.
 +
; {{enum|GL_COPY_READ_BUFFER}} and {{enum|GL_COPY_WRITE_BUFFER}}
 +
: These have no particular semantics. Because they have no actual meaning, they are useful targets for copying buffer object data with {{apifunc|glCopyBufferSubData}}. You do not have to use these targets when copying, but by using them, you avoid disturbing buffer targets that have actual semantics.
 +
; {{enum|GL_PIXEL_UNPACK_BUFFER}} and {{enum|GL_PIXEL_PACK_BUFFER}}
 +
: These are for performing [[Pixel Buffer Object|asynchronous pixel transfer operations.]] If a buffer is bound to {{enum|GL_PIXEL_UNPACK_BUFFER}}, {{code|glTexImage*}}, {{code|glTexSubImage*}}, {{code|glCompressedTexImage*}}, and {{code|glCompressedTexSubImage*}} are all affected. These functions will read their data from the bound buffer object instead of where a client pointer points. Similarly, if a buffer is bound to {{enum|GL_PIXEL_PACK_BUFFER}}, {{apifunc|glGetTexImage}}, and {{apifunc|glReadPixels}} will store their data to the bound buffer object instead of where a client pointer points.
 +
; {{enum|GL_TEXTURE_BUFFER}}
 +
: This target has no special semantics, but if you intend to use a buffer object for [[Buffer Texture]]s, it is a good idea to bind it here when you first create it.
 +
; {{enum|GL_TRANSFORM_FEEDBACK_BUFFER}}
 +
: An [[#Binding indexed targets|indexed buffer binding]] for buffers used in [[Transform Feedback]] operations.
 +
; {{enum|GL_UNIFORM_BUFFER}}
 +
: An [[#Binding indexed targets|indexed buffer binding]] for buffers used as [[Uniform Buffer Object|storage for uniform blocks]].
 +
; {{enum|GL_DRAW_INDIRECT_BUFFER}}
 +
: The buffer bound to this target will be used as the source for the [[Vertex Rendering#Indirect rendering|indirect data when performing indirect rendering]]. This is only available in core OpenGL 4.0 or with {{extref|draw_indirect}}.
 +
; {{enum|GL_ATOMIC_COUNTER_BUFFER}}
 +
: An [[#Binding indexed targets|indexed buffer binding]] for buffers used as storage for atomic counters. This requires OpenGL 4.2 or {{extref|shader_atomic_counters}}
 +
; {{enum|GL_DISPATCH_INDIRECT_BUFFER}}
 +
: The buffer bound to this target will be used as the source for indirect compute dispatch operations, via {{apifunc|glDispatchComputeIndirect}}. This requires OpenGL 4.3 or {{extref|compute_shader}}.
 +
; {{enum|GL_SHADER_STORAGE_BUFFER}}
 +
: An [[#Binding indexed targets|indexed buffer binding]] for buffers used as [[Shader Storage Buffer Object|storage for shader storage blocks]]. This requires OpenGL 4.3 or {{extref|shader_storage_buffer_object}}.
 +
 
 +
=== Binding indexed targets ===
 +
 
 +
Some buffer targets are indexed, as noted above. This is used for binding a number of buffers that do similar things. For example, a [[GLSL]] program can use a number of different uniform buffers.
 +
 
 +
To bind a buffer object to an indexed location, you may use this function:
 +
 
 +
  void {{apifunc|glBindBufferRange}}(GLenum {{param|target}}, GLuint {{param|index}}, GLuint {{param|buffer}}, GLintptr {{param|offset}}, GLsizeiptr {{param|size}} );
  
Easily, the most common usage for buffer objects is as vertex array data. This was the original use behind them, though other uses were expected and designed into the feature. There is a section on [[Vertex Buffer Objects]] and their use. OpenGL 3.1 and above no longer allow the use of vertex arrays without buffer objects.
+
This causes the {{param|buffer}} to be bound to the indexed location {{param|target}} at the {{param|index}} location. The only valid values for {{param|target}} are indexed targets (see below).
  
When a buffer object is bound to the GL_ARRAY_BINDING target, all <code>glVertexAttribPointer</code> commands, as well as the equivalent fixed function commands (<code>glNormalPointer</code>, <code>glTexCoordPointer</code>, etc) will use the pointer value as an absolute offset from the beginning of the buffer object. More details are available on the page on [[Vertex Buffer Objects]].
+
The valid values for {{param|index}} depend on the kind of {{param|target}} being bound. The valid {{param|target}} values, and their associated index limits, are:
  
Similarly, when a buffer object is bound to GL_ELEMENT_ARRAY_BINDING, all functions of the form <code>glDraw*Elements</code> will use the pointer value as an absolute offset from the beginning of the bound buffer object. The indices will be taken from the buffer object.
+
* {{enum|GL_TRANSFORM_FEEDBACK_BUFFER}}: limit {{enum|GL_MAX_TRANSFORM_FEEDBACK_BUFFERS}}.
 +
* {{enum|GL_UNIFORM_BUFFER}}: limit {{enum|GL_MAX_UNIFORM_BUFFER_BINDINGS}}.
 +
* {{enum|GL_ATOMIC_COUNTER_BUFFER}}: limit {{enum|GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS}}.
 +
* {{enum|GL_SHADER_STORAGE_BUFFER}}: limit {{enum|GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS}}.
  
In GL 3.1 and above (without compatibility), none of these functions will work in the absence of a buffer object. You simply are not allowed to use client memory for drawing in these versions of OpenGL.
+
The {{param|offset}} is the byte offset into {{param|buffer}} that the should be used for the binding, and the {{param|size}} is how many bytes after this are valid for this use of the buffer object. This allows you to bind subsections of a buffer object. If {{param|buffer}} is zero, then this index is unbound.
  
The GL_COPY_READ_BUFFER and GL_COPY_WRITE_BUFFER (core extension GL_ARB_copy_buffer, core in version 3.1 and above) are used for copying buffer objects. The function <code>glCopyBufferSubData</code> is used to copy data between buffers.
+
Do note that this does not ''replace'' standard buffer binding with {{apifunc|glBindBuffer}}. It does in fact bind the buffer to the {{param|target}} parameter, thus unbinding whatever was bound to that target. But usually when you use {{apifunc|glBindBufferRange}}, you are serious about wanting to ''use'' the buffer rather than just modify it.
  
The GL_PIXEL_PACK_BUFFER and GL_PIXEL_UNPACK_BUFFER (extension GL_ARB_pixel_buffer_object, core in versions 2.1 and above) are used to store or read pixel data. If a buffer is bound to GL_PIXEL_PACK_BUFFER, <code>glTexImage*</code>, <code>glTexSubImage*</code>, and <code>glDrawPixels</code> are all affected. These functions will read their data from the bound buffer object instead of a client pointer. Similarly, if a buffer is bound to GL_PIXEL_UNPACK_BUFFER, <code>glGetTexImage*</code>, <code>glGetTexSubImage*</code>, and <code>glReadPixels</code>.
+
Think of {{apifunc|glBindBufferRange}} as binding the buffer to two places: the particular index and the {{param|target}}. {{apifunc|glBindBuffer}} only binds to the {{param|target}}, not the index.
  
The pack and unpack bindings are best used for asynchronous transfers of data to/from the GPU. When these functions read/write from/to client memory, they must block for a period of time. By having their source/destinations be buffer objects, which have a very controlled access scheme, it allows these commands to work asynchronously.
+
There is a more limited form of this function, {{apifunc|glBindBufferBase}}, that binds the entire buffer to an index. It simply omits the {{param|offset}} and {{param|size}} fields.
  
The GL_TEXTURE_BUFFER (core extension GL_ARB_texture_buffer_object, core in versions 3.0 and above) binding allows a special 1D texture to have its storage be a buffer object. This binding point is how the buffer gets attached to the texture object.
+
== Reference ==
  
The GL_TRANSFORM_FEEDBACK_BUFFER (core in versions 3.0 and above) binding is used to implement storing the results of the vertex (and geometry, where available) shader in a buffer object. This binding point is the buffer that gets written into.
+
* [[:Category:Core API Ref Buffer Objects]]: Reference documentation for functions that manage buffer objects.
  
The GL_UNIFORM_BUFFER_BINDING (core extension GL_ARB_uniform_buffer_object, core in versions 3.1 and above) binding is used to allow buffer objects to store uniforms for shader programs. This binding point is used to attach buffers containing uniforms to program objects.
+
[[Category:Objects]]
 +
[[Category:Buffer Objects]]

Revision as of 18:20, 16 October 2012

Buffer Objects is the general term for unformatted linear memory allocated by the OpenGL context. These can be used to store vertex data, pixel data retrieved from images or the framebuffer, and a variety of other things.

Versioning

Buffer objects were initially introduced in the ARB_vertex_buffer_object extension. They have been part of core OpenGL since version 1.5. This discussion will pertain specifically to the core version of buffer objects, though it is essentially identical to the extension version.

While buffer objects themselves are relatively old, some of the uses of them are much more recent.

Creation

Buffer Objects are OpenGL Objects; they therefore follow all of the rules of regular OpenGL objects. To create a buffer object, you call glGenBuffers. Deleting them uses glDeleteBuffers. These use the standard Gen/Delete paradigm as most OpenGL objects.

As with the standard OpenGL object paradigm, this only creates the object's name, the reference to the object. To actually create the object itself, you must bind it to the context. You do this using the following API:

 void glBindBuffer(enum target, uint bufferName)

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. It matters more when you intend to tell OpenGL to use the data in the buffer in some way.

Performance Note: In the technical sense, the target a buffer is bound to does not matter for the purposes of creating the memory storage for it. However, OpenGL implementations are allowed to make judgments about your intended use of the buffer object based on the first target you bind it to. So if you intend for your buffer object to be used as a vertex array buffer, you should bind that buffer to GL_ARRAY_BUFFER first. You may later use it as a GL_TRANSFORM_FEEDBACK buffer for readback or whatever, but binding it to GL_ARRAY_BUFFER gives the implementation important information about how you plan to use it overall.

To create the actual memory storage for a buffer object, you use this API:

 void glBufferData(enum target, sizeiptr size, const void *data, enum usage)

The target parameter is just like the one for glBindBuffer; it says which bound buffer to modify. size represents how many bytes you want to allocate in this buffer object.

The data parameter is a pointer to user memory that will be copied into the buffer object's data store. If this value is NULL, then no copying will occur, and the buffer object's data will be undefined.

The usage parameter can be very confusing.

Buffer Object Usage

Buffer objects are general purpose memory storage blocks allocated by OpenGL. They are intended to be used in a great many ways. To give the implementation great flexibility in exactly what a particular buffer object's data store will be, so as to better optimize performance, the user is required to give usage hints. These provide a general description as to how exactly the user will be using the buffer object.

There are two independent parts to the usage pattern: how the user will be reading/writing from/to the buffer, and how often the user will be changing it relative to the use of the data.

There are two ways for data to cause a change in the data contents of a buffer object. One way is for the user to explicitly upload some binary data. The other way is for the user to issue GL commands that cause the buffer to be filled in. For example, if you want to have a buffer store the results of a vertex shader computation through the use of transform feedback, the user is not directly changing the buffer information. So this is the latter kind of change.

Similarly, the user can read a buffer's data, using a variety of commands. Or, the user can execute an OpenGL command that causes the GL to read the contents of the buffer and do something based on it. Buffers storing vertex data are read by the GL when rendering.

There are three hints that the user can specify the data. They are all based on what the user will be doing with the buffer. That is, whether the user will be directly reading or writing the buffer's data.

  • DRAW: The user will be writing data to the buffer, but the user will not read it.
  • READ: The user will not be writing data, but the user will be reading it back.
  • COPY: The user will be neither writing nor reading the data.

DRAW is useful for, as the name suggests, drawing. The user is uploading data, but only the GL is reading it. Buffer objects holding vertex data are generally specified as DRAW, though there can be exceptions.

READ is used when a buffer object is used as the destination for OpenGL commands. This could be rendering to a Buffer Texture, using arbitrary writes to buffer textures, doing a pixel transfer into a buffer object, using Transform Feedback, or any other OpenGL operation that writes to buffer objects.

COPY is used when a buffer object is used to pass data from one place in OpenGL to another. For example, you can read image data into a buffer, then use that image data as vertex data in a draw call. Your code never actually sends data to the buffer directly, nor does it read data back. You can also use Transform Feedback to achieve the same thing in a more direct way. You have the feedback data go to a buffer object, then use that buffer object as vertex data. And while the user is causing the buffer to be updated via rendering commands, at no time is the user directly either reading from or writing to the buffer's storage.

There are three hints for how frequently the user will be changing the buffer's data.

  • STATIC: The user will set the data once.
  • DYNAMIC: The user will set the data occasionally.
  • STREAM: The user will be changing the data after every use. Or almost every use.

STREAM is pretty easy to understand: the buffer object's storage will be updated after almost every use. STATIC is pretty easy to understand too. The buffer object's contents will be updated once and never changed.

What is unclear is when DYNAMIC becomes STREAM or STATIC. These are only hints, after all. It is perfectly legal OpenGL code to modify a STATIC buffer after it has been created, or to never modify a STREAM buffer.

Is it better to use STATIC for buffers that are updated very infrequently? Is it better to use DYNAMIC for buffers that get updated frequently, but not at STREAM speed? Is it better to use DYNAMIC for buffers that get partially updated? These are questions that can only be answered with careful profiling. And even then, the answer will only be accurate for that particular driver version from that particular hardware vendor.

In any case, STREAM, STATIC, and DYNAMIC can be matched with READ, DRAW, and COPY in any combination. STREAM_COPY means that you will be doing transform feedback writes (or other kinds of GL-based writes) into the buffer after almost every use; it will not be updated with glBufferSubData or similar functions. STATIC_READ means that you will fill the buffer up from the GL, but you will only do this once.

Data Specification

We have seen that glBufferData can be used to update the data in a buffer object. However, this also reallocates the buffer object's storage. This is not usually what one wants, as recreating the buffer can often be a heavyweight operation.

Instead, one can use the following API:

 void glBufferSubData(enum target, intptr offset, sizeiptr size, const void *data)

The offset parameter is an integer offset into the buffer object where we should begin updating. The size parameter is the number of bytes we should copy out of data. For obvious reasons, data cannot be NULL.

Clearing

Buffer Object
Core in version 4.5
Core since version 4.3
Core ARB extension ARB_clear_buffer_object

A buffer object's storage can be cleared, in part or in full, to a specific value. These functions work in a similar fashion to Pixel Transfer operations, though with some significant differences:

void glClearBufferData(GLenum internalformat​, GLenum format​, GLenum type​, const void * data​);
void glClearBufferSubData(GLenum internalformat​, GLintptr offset​, GLsizeiptr size​, GLenum format​, GLenum type​, const void * data​);

glClearBufferData works as glClearBufferSubData, except it operates on the entire buffer's contents. It does not respecify the storage for the buffer.

internalformat​ must be a sized Image Format, but only of the kind that can be used for buffer textures. This defines how OpenGL will store the data in the buffer object. format​ and type​ operate as normal for Pixel Transfer operations.

data​ is a pointer to a single pixel's worth of data, rather than the rows that are used in actual pixel transfers. So if format​ is GL_RG and type​ is GL_UNSIGNED_BYTE, then data​ should be a pointer to an array of two GLubyte​s.

This function will copy the given data repeatedly throughout the specified range of the buffer. offset​ must be a multiple of the byte size defined by the internalformat​, as must size​.

Copying

Data can be copied from one buffer object to another. To do this, first bind the source and destination buffers to different target​s. These could be any target, but GL_COPY_READ_BUFFER​ and GL_COPY_WRITE_BUFFER have no special semantics, so they make useful targets for this purpose.

Once both are bound, use this function:

void glCopyBufferSubData(GLenum readtarget​, GLenum writetarget​, GLintptr readoffset​, GLintptr writeoffset​, GLsizeiptr size​);

readtarget​ is the buffer you bound the source buffer to. So this is where you get the data to copy from. writetarget​ is the buffer you bound the destination buffer to. readoffset​ is the byte offset from the beginning of the source buffer to start reading. writeoffset​ is the byte offset from the beginning of the destination buffer to start writing to. size​ is the number of bytes to read.

Errors will be given if the offset/sizes would cause reading to or writing from locations outside of the respective buffer objects' storage.

Mapping

glBufferSubData is a nice way to present data to a buffer object. But it can be wasteful in performance, depending on your use patterns.

For example, if you have an algorithm that generates data that you want to store in the buffer object, you must first allocate some temporary memory to store that data in. Then you can use glBufferSubData to transfer it to OpenGL's memory. Similarly, if you want to read data back, glGetBufferSubData is perhaps not what you need, though this is less likely. It would be really nice if you could just get a pointer to the buffer object's storage and write directly to it.

You can. To do this, you must map the buffer. This gives you a pointer to memory that you can write to or read from, theoretically, just like any other. When you unmap the buffer, this invalidates the pointer (don't use it again), and the buffer object will be updated with the changes you made to it.

While a buffer is mapped, you can freely unbind the buffer. However, you cannot call any function that would cause OpenGL to read, modify, or write to that buffer while it is mapped. Thus, calling glBufferData is out, as is using any function that would cause OpenGL to read from it (rendering with a VAO that uses it, etc).

To map a buffer, you call glMapBufferRange. The signature of this function is this:

 void *glMapBufferRange(GLenum target​, GLintptr offset​, GLsizeiptr length​, GLbitfield access​);

The return value is the pointer to the buffer object's data. The parameters offset​ and length​ allow you to specify a particular range within the buffer to map; you do not have to map the entire buffer. The target​ parameter refers to the particular target that you have the buffer you want to map bound to.

The access​ parameter is a bit complicated.

You can tell OpenGL what you intend to do with the pointer. If you're just adding new data to the buffer, then the pointer that gets returned isn't something you need to read from. Similarly, it could be your intention to read from this pointer and not change the buffer; OpenGL could do a simple copy from the buffer's memory to scratch memory in the client address space to make reading the buffer faster (buffer memory may not be optimized for reading).

You specify this by setting bitflags in the access​ parameter. This parameter must have either the GL_MAP_READ_BIT or GL_MAP_WRITE_BIT set; it can have both (ie: the memory will be fit for reading and writing) but it can't have neither. There are a number of other flags that can be set.

Unmapping the buffer is done when you are finished with the pointer and want to let OpenGL know that the buffer is free to be used. This is done with the function glUnmapBuffer. This function takes only the target that the buffer in question is bound to. After calling this function, you should not use the pointer returned in the map call again.

Buffer Corruption

There is one major gotcha when mapping a buffer.

During normal OpenGL operations, the OpenGL specification requires that all data stored in OpenGL objects be preserved. Thus, if something in the operating system or other such things causes video memory to be trashed, the OpenGL implementation must ensure that this data is restored properly.

Mapping is not a normal operation. Because of its low-level nature, these protections have to be relaxed. Therefore, it is possible that, during the time a buffer is mapped, some kind of corruption happens. If this occurs, calling glUnmapBuffer will return GL_FALSE. At that point, the contents of the buffer in question are considered undefined. It may have your data, or it may have random garbage.

How often does this happen? On Microsoft Windows 5.1 (XP) and below, video memory could get trashed anytime an application didn't have input focus. This is why alt-tabbing away from games takes a long time to recover from; the application/OpenGL has to reload all of this data back to video memory. Fortunately, on Windows 6.0 (Vista) and above, this is fixed; Windows itself manages video memory and will ensure that all video memory is retained. Thus, at least theoretically, this should never be a problem on Vista or above machines.

Performance Concerns

One thing to remember about buffer mapping is this: the implementation is not obligated in any way to give you an actual pointer to the buffer object's memory. It is perfectly capable of giving you a pointer to some memory that OpenGL allocated just for the purpose of mapping, then it will do the copy on its own time.

The other thing to remember is that you should not care. OpenGL likes to give implementations flexibility to make performance optimizations. If mapping a certain buffer gives you some other pointer, and the implementation will do the copy on its own time, you should assume that this is probably the fastest way to work. It's still potentially faster than glBufferSubData, since the copy in glBufferSubData must happen before the function call returns, whereas the copy in the mapping case can happen in a thread the GL spawns. The worst case is that it's no slower than glBufferSubData.

However, you should not use the pointer you are given like any other pointer you might have. If this pointer is a pointer to non-standard memory (uncached or video memory), then writing to it haphazardly can be problematic. If you are attempting to stream data to the buffer, you should always map the buffer only for writing and you should write sequentially. You do not need to write every byte, but you should avoid going backwards or skipping around in the memory.

The purpose in writing sequentially is to be able to use write-combine memory, a feature of some processors (most x86's). It allows sequential writes to uncached memory to flow fairly quickly, compared to random writes to uncached memory.

Invalidation

Buffer invalidation
Core in version 4.5
Core since version 4.3
Core ARB extension ARB_invalidate_subdata

glMapBufferRange can invalidate part of a buffer or the entire thing using GL_MAP_INVALIDATE_RANGE_BIT and GL_MAP_INVALIDATE_BUFFER_BIT, respectively. You can force invalidation of a buffer without mapping it by using the following functions:

void glInvalidateBufferData(GLuint buffer​);
void glInvalidateBufferSubData(GLuint buffer​, GLintptr offset​, GLsizeiptr length​);

glInvalidateBufferData is equivalent to calling glInvalidateBufferSubData with offset​ as 0 and length​ as the size of the buffer's storage.

When a buffer or region thereof is invalidated, it means that the contents of that buffer are now undefined. How OpenGL handles invalidation is up to it. Note that any pending operations on the buffer will still complete. Any pending reads from OpenGL will still get their original values, and any pending writes will still write their values.

The idea is that, by invalidating a buffer or range thereof, the implementation will simply grab a new piece of memory to use. Thus, while previously executed GL commands can still read the buffer's data, you can fill the invalidated buffer with new values (via mapping or glBufferSubData) without causing synchronization.

Streaming

Streaming is the process of frequently uploading data to a buffer object and then using that buffer object in some OpenGL process. Making this as efficient as possible is a delicate operation. Buffer objects provide a number of possible usage patterns for streaming, and which ones work best is not entirely clear. Testing should be done with the hardware of interest to make sure that you get optimal streaming performance.

The key to streaming is parallelism. The OpenGL specification permits an implementation to delay the execution of drawing commands. This allows you to draw a lot of stuff, and then let OpenGL handle things on its own time. Because of this, it is entirely possible that well after you called the rendering function with a buffer object, you might start trying to stream vertex data into that buffer. If this happens, the OpenGL specification requires that the thread halt until all drawing commands that could be affected by your update of the buffer object complete. This obviously misses the whole point of streaming.

The key to effective streaming is avoiding this synchronization. Or rather, avoiding it at all costs.

General use

Most of the uses of buffer objects involve binding them to a certain target, then calling a function that behaves differently based on having a buffer object in that target. Usually, these functions take a pointer as one of their parameters. When a buffer object is bound to certain targets, it causes some functions that take a pointer parameter to treat that parameter as an offset into the buffer object. Thus, rather than pulling data from client memory pointers, they pull it from the bound buffer object.

Here are the various targets for buffer objects and their associated uses:

GL_ARRAY_BUFFER
The buffer will be used as a source for vertex data, but only when glVertexAttribPointer is called. The pointer field of this function is taken as a byte offset from the beginning of whatever buffer is currently bound to this target.
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.
GL_COPY_READ_BUFFER and GL_COPY_WRITE_BUFFER
These have no particular semantics. Because they have no actual meaning, they are useful targets for copying buffer object data with glCopyBufferSubData. You do not have to use these targets when copying, but by using them, you avoid disturbing buffer targets that have actual semantics.
GL_PIXEL_UNPACK_BUFFER and GL_PIXEL_PACK_BUFFER
These are for performing asynchronous pixel transfer operations. If a buffer is bound to GL_PIXEL_UNPACK_BUFFER, glTexImage*​, glTexSubImage*​, glCompressedTexImage*​, and glCompressedTexSubImage*​ are all affected. These functions will read their data from the bound buffer object instead of where a client pointer points. Similarly, if a buffer is bound to GL_PIXEL_PACK_BUFFER, glGetTexImage, and glReadPixels will store their data to the bound buffer object instead of where a client pointer points.
GL_TEXTURE_BUFFER
This target has no special semantics, but if you intend to use a buffer object for Buffer Textures, it is a good idea to bind it here when you first create it.
GL_TRANSFORM_FEEDBACK_BUFFER
An indexed buffer binding for buffers used in Transform Feedback operations.
GL_UNIFORM_BUFFER
An indexed buffer binding for buffers used as storage for uniform blocks.
GL_DRAW_INDIRECT_BUFFER
The buffer bound to this target will be used as the source for the indirect data when performing indirect rendering. This is only available in core OpenGL 4.0 or with ARB_draw_indirect.
GL_ATOMIC_COUNTER_BUFFER
An indexed buffer binding for buffers used as storage for atomic counters. This requires OpenGL 4.2 or ARB_shader_atomic_counters
GL_DISPATCH_INDIRECT_BUFFER
The buffer bound to this target will be used as the source for indirect compute dispatch operations, via glDispatchComputeIndirect. This requires OpenGL 4.3 or ARB_compute_shader.
GL_SHADER_STORAGE_BUFFER
An indexed buffer binding for buffers used as storage for shader storage blocks. This requires OpenGL 4.3 or ARB_shader_storage_buffer_object.

Binding indexed targets

Some buffer targets are indexed, as noted above. This is used for binding a number of buffers that do similar things. For example, a GLSL program can use a number of different uniform buffers.

To bind a buffer object to an indexed location, you may use this function:

 void glBindBufferRange(GLenum target​, GLuint index​, GLuint buffer​, GLintptr offset​, GLsizeiptr size​ );

This causes the buffer​ to be bound to the indexed location target​ at the index​ location. The only valid values for target​ are indexed targets (see below).

The valid values for index​ depend on the kind of target​ being bound. The valid target​ values, and their associated index limits, are:

  • GL_TRANSFORM_FEEDBACK_BUFFER: limit GL_MAX_TRANSFORM_FEEDBACK_BUFFERS.
  • GL_UNIFORM_BUFFER: limit GL_MAX_UNIFORM_BUFFER_BINDINGS.
  • GL_ATOMIC_COUNTER_BUFFER: limit GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS.
  • GL_SHADER_STORAGE_BUFFER: limit GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS.

The offset​ is the byte offset into buffer​ that the should be used for the binding, and the size​ is how many bytes after this are valid for this use of the buffer object. This allows you to bind subsections of a buffer object. If buffer​ is zero, then this index is unbound.

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.

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.

There is a more limited form of this function, glBindBufferBase, that binds the entire buffer to an index. It simply omits the offset​ and size​ fields.

Reference