Back to the OpenGL extension cross reference

GL_ARB_vertex_buffer_object


Name


    ARB_vertex_buffer_object

Name Strings


    GL_ARB_vertex_buffer_object

Contributors


    Ben Ashbaugh
Bob Beretta
Pat Brown
Cass Everitt
John Kessenich
Dale Kirkland
Jon Leech
Bill Licea-Kane
Barthold Lichtenbelt
Bimal Poddar
Thomas Roell
Ian Romanick
Jeremy Sandmel
Jon Paul Schelter
John Stauffer
Nick Triantos
Daniel Vogel

Contact


    Rick Hammerstone, ATI Research (rhammers 'at' ati.com)
Matt Craighead, NVIDIA Corporation (mcraighead 'at' nvidia.com)
Kurt Akeley, NVIDIA Corporation (kakeley 'at' nvidia.com)

IP Status


    None.

Status


    Complete. Approved by ARB on February 12, 2003.

Version


    Last Modified Date: January 21, 2003
Revision: 0.91

Number


    ARB Extension #28

Dependencies


    Written based on the wording of the OpenGL 1.4 specification.

GL_ARB_vertex_blend affects the definition of this extension.

GL_ARB_vertex_program affects the definition of this extension.

GL_EXT_vertex_shader affects the definition of this extension.

Overview


    This extension defines an interface that allows various types of data
(especially vertex array data) to be cached in high-performance
graphics memory on the server, thereby increasing the rate of data
transfers.

Chunks of data are encapsulated within "buffer objects", which
conceptually are nothing more than arrays of bytes, just like any
chunk of memory. An API is provided whereby applications can read
from or write to buffers, either via the GL itself (glBufferData,
glBufferSubData, glGetBufferSubData) or via a pointer to the memory.

The latter technique is known as "mapping" a buffer. When an
application maps a buffer, it is given a pointer to the memory. When
the application finishes reading from or writing to the memory, it is
required to "unmap" the buffer before it is once again permitted to
use that buffer as a GL data source or sink. Mapping often allows
applications to eliminate an extra data copy otherwise required to
access the buffer, thereby enhancing performance. In addition,
requiring that applications unmap the buffer to use it as a data
source or sink ensures that certain classes of latent synchronization
bugs cannot occur.

Although this extension only defines hooks for buffer objects to be
used with OpenGL's vertex array APIs, the API defined in this
extension permits buffer objects to be used as either data sources or
sinks for any GL command that takes a pointer as an argument.
Normally, in the absence of this extension, a pointer passed into the
GL is simply a pointer to the user's data. This extension defines
a mechanism whereby this pointer is used not as a pointer to the data
itself, but as an offset into a currently bound buffer object. The
buffer object ID zero is reserved, and when buffer object zero is
bound to a given target, the commands affected by that buffer binding
behave normally. When a nonzero buffer ID is bound, then the pointer
represents an offset.

In the case of vertex arrays, this extension defines not merely one
binding for all attributes, but a separate binding for each
individual attribute. As a result, applications can source their
attributes from multiple buffers. An application might, for example,
have a model with constant texture coordinates and variable geometry.
The texture coordinates might be retrieved from a buffer object with
the usage mode "STATIC_DRAW", indicating to the GL that the
application does not expect to update the contents of the buffer
frequently or even at all, while the vertices might be retrieved from
a buffer object with the usage mode "STREAM_DRAW", indicating that
the vertices will be updated on a regular basis.

In addition, a binding is defined by which applications can source
index data (as used by DrawElements, DrawRangeElements, and
MultiDrawElements) from a buffer object. On some platforms, this
enables very large models to be rendered with no more than a few
small commands to the graphics device.

It is expected that a future extension will allow sourcing pixel data
from and writing pixel data to a buffer object.

Issues


    What should this extension be called?

RESOLVED: By unanimous consent among the working group members,
the name was chosen to be "ARB_vertex_buffer_object". A large
number of other names were considered throughout the lifetime of
the proposal, especially "vertex_array_object" (originally),
"buffer_object" (later on), and "memory_object" (near the end),
but the name "vertex_buffer_object" was ultimately chosen.

In particular, this name emphasizes not only that we have created
a new type of object that encapsulates arbitrary data (buffer
objects), but also, in particular, that these objects are used in
this extension to source vertex data. The name also is
intentionally similar to "vertex buffers", although it should be
emphasized that there is no such thing as a "vertex buffer" in
the terminology of this extension. The term "buffer object" is
the correct noun.

How is this extension different from ATI_vertex_array_object plus
ATI_map_object_buffer?

The following summarizes the major differences.
- VAOs renamed to "buffer objects", to signify that they can be
used for more than just vertex data. Other renaming and API
changes to try to better match OpenGL conventions.
- The standard GL pointer APIs have been overloaded to be able to
refer to offsets within these buffers, rather than adding new
entry points.
- The usage modes permitted for buffers have been augmented
significantly, to reflect a broader class of application
behaviors.
- A new entry point allows reading back the contents of a buffer
object.

How is this extension different from NV_vertex_array_range?

The following summarizes the major differences.
- Applications are no longer responsible for memory management
and synchronization.
- Applications may still access high-performance memory, but
this is optional, and such access is more restricted.
- Buffer changes (glBindBufferARB) are generally expected to
be very lightweight, rather than extremely heavyweight
(glVertexArrayRangeNV).
- A platform-specific allocator such as wgl/glXAllocateMemoryNV
is no longer required.

How does this extension relate to NV_pixel_data_range?

A future extension could be created based on the framework
created here that would support analogous functionality to that
provided by NV_pixel_data_range. Presumably, this extension
would require little more than two new targets for BindBuffer,
named (say) UNPACK_PIXELS and PACK_PIXELS. The lists of commands
affected by these bindings could easily be taken verbatim out of
the NV_pixel_data_range specification.

Should this extension include support for allowing vertex indices
to be stored in buffer objects?

RESOLVED: YES. It is easily and cleanly added with just the
addition of a binding point for the index buffer object. Since
our approach of overloading pointers works for any pointer in GL,
no additional APIs need be defined, unlike in the various
*_element_array extensions.

Note that it is expected that implementations may have different
memory type requirements for efficient storage of indices and
vertices. For example, some systems may prefer indices in AGP
memory and vertices in video memory, or vice versa; or, on
systems where DMA of index data is not supported, index data must
be stored in (cacheable) system memory for acceptable
performance. As a result, applications are strongly urged to
put their models' vertex and index data in separate buffers, to
assist drivers in choosing the most efficient locations.

Should the layout of an array store be defined at array store
creation time?

RESOLVED: NO. This could provide better performance if the
client specifies a data type that the hardware doesn't support,
but this isn't a performance path anyways, and it adds a
cumbersome interface on top of the extension.

Should there be some sort of scheme for allowing applications to
stream vertex data efficiently?

RESOLVED: YES. Applications that generate their data on the
fly end up doing an extra data copy unless they are given a
pointer into memory that the graphics hardware can DMA from. The
performance win from doing this can be significant.

Should the client be able to retrieve a pointer to a buffer object?

RESOLVED: YES. This solves the previous problem. Since GL
vertex array formats are already user-visible, this does not
suffer from the sorts of formatting issues that would arise if
the GL allowed applications to retrieve pointers to texture
objects or to the framebuffer. Synchronization can be a concern,
but proper usage of this extension will minimize its overhead.

Should this extension sit on top of the existing vertex array
implementation, instead of introducing a new set of API calls?

RESOLVED: YES. This simplifies the API, and separating out the
buffer binding from the offset/stride within the buffer leads to
an elegant "BindBufferARB" command that can be used for other
parts of GL like the pixel path.

Should buffer object state overlap with existing vertex array pointer
state, or should there be new drawing commands, e.g.,
DrawArrayObject?

RESOLVED: OVERLAP. The exponential growth in drawing commands
is problematic. Even without this, there is already
ArrayElement, DrawArrays, DrawElements, DrawRangeElements,
MultiDrawArrays, and MultiDrawElements.

Does the buffer binding state push/pop?

RESOLVED: YES. It pushes/pops on the client with the rest of
the vertex array state. Some revisions of the ATI VAO spec
listed a push/pop attrib "objbuf", but no new bit was defined;
all this has been moved into the standard "vertex-array" bit.

Note that both the user-controlled binding ARRAY_BUFFER_ARB
binding point and the per-array bindings push and pop.

Note that additional binding points, such as ones for pixel or
texture transfers, would not be part of the vertex array state,
and thus would likely push and pop as part of the pixel store
(client) state when they are defined.

How is the decision whether to use the array pointer as an offset or
as a real pointer made?

RESOLVED: When the default buffer object (object zero) is
bound, all pointers behave as real pointers. When any other
object is bound, all pointers are treated as offsets.
Conceptually, one can imagine that buffer object zero is a buffer
object sitting at base NULL and with an extent large enough that
it covers all of the system's virtual address space.

Note that this approach essentially requires that binding points
be client (not server) state.

Can buffer objects be shared between contexts in the same way that
display lists are?

RESOLVED: YES. All potentially large OpenGL objects, such as
display lists and textures, can be shared, and this is an
important capability. Note, however, that sharing requires that
buffer objects be server (not client) state, since it is not
possible to share client state.

Should buffer objects be client state or server state?

RESOLVED: Server state. Arguments for client state include:

- Buffer data are stored in client-side format, making server
storage complex when client and server endianness differ.
- Vertex arrays are client state.

These arguments are outweighed by the significant advantages
of server state, including:

- Server state can be shared between contexts, and this is
expected to be an important capability (sharing of texture
objects is very common).
- In the case of indirect rendering, performance may be
very significantly greater for data stored on the server
side of the wire.

How is synchronization enforced when buffer objects are shared by
multiple OpenGL contexts?

RESOLVED: It is generally the clients' responsibility to
synchronize modifications made to shared buffer objects. GL
implementations will make some effort to avoid deletion of in-use
buffer objects, but may not be able to ensure this handling.

What happens if a currently bound buffer object is deleted?

RESOLVED: Orphan. To avoid chasing invalid pointers OpenGL
implementations will attempt to defer the deletion of any buffer
object until that object is not bound by any client in the share
list. It should be possible to implement this behavior
efficiently in the direct rendering case, but the implementation
may be difficult/impossible in the indirect rendering case.
Since synchronization during sharing is a client responsibility,
this behavior is acceptable.

Should there be a way to query the data in a buffer object?

RESOLVED: YES. Almost all objects in OpenGL are fully
queriable, and since these objects are simply byte arrays, there
does not seem to be any reason to do things otherwise here. The
primary exceptions to GL queriability are cases where such
functionality would be extremely burdensome to provide, as is the
case with display lists.

Do buffer objects survive screen resolution changes, etc.?

RESOLVED: YES. This is not mentioned in the spec, so by
default they behave just like other OpenGL state, like texture
objects -- the data is unmodified by external events like
modeswitches, switching the system into standby or hibernate
mode, etc.

What happens to a mapped buffer when a screen resolution change or
other such window-system-specific system event occurs?

RESOLVED: The buffer's contents may become undefined. The
application will then be notified at Unmap time that the buffer's
contents have been destroyed. However, for the remaining
duration of the map, the pointer returned from Map must continue
to point to valid memory, in order to ensure that the application
cannot crash if it continues to read or write after the system
event has been handled.

What happens to the pointer returned by MapBufferARB after a call to
UnmapBufferARB?

RESOLVED: The pointer becomes totally invalid. Note that
drivers are free to move the underlying buffer or even unmap the
memory, leaving the virtual addresses in question pointing at
nothing. Such flexibility is necessary to enable efficient
implementations on systems with no virtual memory; with limited
control over virtual memory from graphics drivers; or where
virtual address space is at a premium.

How does indirect rendering work?

It is not currently specified, but the basic planned outline is
as follows.

All of the object management commands -- Gen, Is, Delete -- go
to the server immediately with normal protocol. So does Bind.
However, when someone does an implicit bind via one of the
pointer commands (e.g. VertexPointer), the server may not
necessarily be notified immediately of the new object bound to
the (in this case) VERTEX_ARRAY_BUFFER_BINDING.

BufferData and BufferSubData are sent over the wire just as
TexImage2D and TexSubImage2D, and GetBufferSubData does a round
trip, just like GetTexImage. MapBuffer goes over the wire with
a request to map; the server replies to tell the client whether
the map succeeded or failed, and the client returns a pointer to
a system memory buffer in the event of success. If the map is
readable, the server passes back the contents of the buffer,
while if the map is writeable, at Unmap time, the client passes
back the new contents. Unmap would always return TRUE.

Both GetBufferParameteriv and GetBufferPointerv go to the server.

Whenever the application sources data from a buffer object,
several new protocols are defined to specify where to obtain the
data from. One new command might be called "BindArray", which
would have arguments <array>, <buffer>, offset>, <type>, <size>,
<stride>, and <normalized>. <array> might be VERTEX_ARRAY,
NORMAL_ARRAY, etc. <buffer> would be the ID of the buffer
object to be used as source, or zero if no buffer object.
<offset> would be a 64-bit (?) integer. <type>, <size>,
<stride>, and <normalized> would all be the same as the various
arguments to the *Pointer commands. Another new command might
be "ArrayElementServer", which would dereference all arrays with
a nonzero <buffer> on the server side, just as if immediate mode
had been used. If only some arrays were coming from buffer
objects and some from user memory, the client would dereference
the ones in user memory and pass them in as immediate mode
protocol.

If all arrays came from the server, additional optimized APIs
could be provided. A "DrawArraysServer" and "DrawElementsServer"
would be cheaper than a sequence of "ArrayElementServer"
commands. For indices coming from a buffer object, a
"DrawElementArrayServer" might be added.

At initialization time, the client and server would exchange a
handshake to see if the server can understand the client's
storage of the various GL data types. It is expected that nearly
all clients and servers would use just two data type
representations, namely, "standard little endian with IEEE
floats" and "standard big endian with IEEE floats".

Are any of these commands allowed inside Begin/End?

RESOLVED: NO, with the possible exception of BindBuffer, which
should not be used inside a Begin/End but will have undefined
error behavior, like most vertex array commands.

What happens when an attempt is made to access data outside the
bounds of the buffer object with a command that dereferences the
arrays?

RESOLVED: ALLOW PROGRAM TERMINATION. In the event of a
software fallback, bounds checking can become impractical. Since
applications don't know the actual address of the buffer object
and only provide an offset, they can't ever guarantee that
out-of-bounds offsets will fall on valid memory. So it's hard to
do any better than this.

Of course, such an event should not be able to bring down the
system, only terminate the program.

What type should <offset> and <size> arguments use?

RESOLVED: We define new types that will work well on 64-bit
systems, analogous to C's "intptr_t". The new type "GLintptrARB"
should be used in place of GLint whenever it is expected that
values might exceed 2 billion. The new type "GLsizeiptrARB"
should be used in place of GLsizei whenever it is expected
that counts might exceed 2 billion. Both types are defined as
signed integers large enough to contain any pointer value. As a
result, they naturally scale to larger numbers of bits on systems
with 64-bit or even larger pointers.

The offsets introduced in this extension are typed GLintptrARB,
consistent with other GL parameters that must be non-negative,
but are arithmetic in nature (not uint), and are not sizes; for
example, the xoffset argument to TexSubImage*D is of type GLint.
Buffer sizes are typed GLsizeiptrARB.

The idea of making these types unsigned was considered, but was
ultimately rejected on the grounds that supporting buffers larger
than 2 GB was not deemed important on 32-bit systems.

Should buffer maps be client or server state?

RESOLVED: Server. If a buffer is being shared by multiple
clients, it will also be desirable to share the mappings of that
buffer. In cases where the mapping cannot shared (for example,
in the case of indirect rendering) queries of the map pointer by
clients other than the one that created the map will return a
null pointer.

Should "Unmap" be treated as one word or two?

RESOLVED: One word.

Should "usage" be a parameter to BufferDataARB, or specified
separately using a parameter specification command, e.g.,
BufferParameteriARB?

RESOLVED: Parameter to BufferDataARB. It is desirable for the
implementation to know the usage when the buffer is initialized,
so including it in the initialization command makes sense. This
avoids manpage notes such as "Please specify the usage before you
initialize the buffer".

Should it be possible to change the usage of an initialized buffer?

RESOLVED: NO. Unless it is shown that this flexibility is
necessary, it will be easier for implementations to be efficient
if usage cannot be changed. (Except by re-initializing the
buffer completely.)

Should we allow for the possibility of multiple simultaneous maps for
a single buffer?

RESOLVED: NO. If multiple maps are allowed, the mapping
semantics become very difficult to understand and to specify.
It is also unclear that there are any benefits to offering such
functionality. Therefore, only one map per buffer is permitted.

Note: the limit of one map per buffer eliminates any need for
"sub-region" mapping. The single map always maps the entire
data store of the buffer.

Should it be an error to render from a currently mapped buffer?

RESOLVED: YES. Making this an error rather than undefined makes
the API much more bulletproof.

Should it be possible for the application to query the "viability" of
the data store of a buffer?

RESOLVED: NO. UnmapBuffer can return FALSE to indicate this, but
there is no additional query to check whether the data has been
lost. In general, most/all GL state is queriable, unless there
is a compelling reason otherwise. However, on examination, it
appears that there are several compelling reasons otherwise in
this case. In particular, the default for this state variable is
non-obvious (is the data "valid" when no data has been specified
yet?), and it's unclear when it should be reset (BufferData only?
BufferSubData? A successful UnmapBuffer?). After these issues
came to light, the query was removed from the spec.

What should the error behavior of BufferDataARB and MapBufferARB be?

RESOLVED: BufferDataARB returns no value and sets OUT_OF_MEMORY
if the buffer could not be created, whereas MapBufferARB returns
NULL and also sets OUT_OF_MEMORY if the buffer could not be
mapped.

Should UnmapBufferARB return a boolean indicating data integrity?

RESOLVED: YES, since the Unmap is precisely the point at which
the buffer can no longer be lost.

How is unaligned data handled?

RESOLVED: All client restrictions on data alignment must be met,
and in addition to that, all offsets must be multiples of the
size of the underlying data type. So, for example, float data in
a buffer object must have an offset that is (typically) a
multiple of 4. This should make the server implementation
easier, since this additional rule will guarantee that no
alignment checking is required on most platforms.

Should MapBufferARB return the pointer to the map, or should there be
a separate call to ask for the pointer?

RESOLVED: BOTH. For convenience, MapBufferARB returns a pointer
or NULL in the event of failure; but since most/all GL state is
queriable, you can also query the pointer at a later point in
time. If the buffer is not mapped, querying the pointer should
return NULL.

Should there be one binding point for all arrays or several binding
points, one for each array?

RESOLVED: One binding point for all arrays. Index data uses a
separate target.

Should there be a PRESERVE/DISCARD option on BufferSubDataARB? On
MapBufferARB?

RESOLVED: NO, NO. ATI_vertex_array_object had this option for
UpdateObjectBufferATI, which is the equivalent of
BufferSubDataARB, but it's unclear whether this has any utility.
There might be some utility for MapBufferARB, but forcing the
user to call BufferDataARB again with a NULL data pointer has
some advantages of its own, such as forcing the user to respecify
the size.

Should there be an option for MapBufferARB that guarantees
nonvolatile memory?

RESOLVED: NO. On systems where volatile memory spaces are a
concern, there is little or no way to supply nonvolatile memory
without crippling performance badly. In some cases, it might
not even be possible to implement Map except by returning system
memory. Systems that do not have problems with volatility are,
of course, welcome to return TRUE from UnmapBufferARB all the
time. If applications want the ease of use that results from not
having to check for lost data, they can still use BufferDataARB
and BufferSubDataARB, so the burden is not too great.

What new usages do we need to add?

RESOLVED. We have defined a 3x3 matrix of usages. The
pixel-related terms draw, read, and copy are used to distinguish
between three basic data paths: application to GL (draw), GL to
application (read), and GL to GL (copy). The terms stream,
static, and dynamic are used to identify three data access
patterns: specify once and use once or perhaps only a few times
(stream), specify once and use many times (static), and specify
and use repeatedly (dynamic).

Note that the "copy" and "read" usage token values will become
meaningful only when pixel transfer capability is added to
buffer objects by a (presumed) subsequent extension.

Note that the data paths "draw", "read", and "copy" are analogous
in both name and meaning to the GL commands DrawPixels,
ReadPixels, and CopyPixels, respectively.

Is it legal C to use pointers as offsets?

We haven't come to any definitive conclusion about this. The
proposal is to convert to pointer as:

pointer = (char *)NULL + offset;

And convert back to offset as:

offset = (char *)pointer - (char *)NULL;

Varying opinions have been expressed as to whether this is legal,
although no one could provide an example of a real system where
any problems would occur.

Should we add new Offset commands, e.g., VertexOffset, if the pointer
approach has some compatibility concerns?

RESOLVED: NO. The working group voted that the existing pointer-
as-offset approach is acceptable.

Which commands are compiled into display lists?

RESOLVED: None of the commands in this extension are compiled
into display lists. The reasoning is that the server may not
have up-to-date buffer bindings, since BindBuffer is a client
command.

Just as without this extension, vertex data is dereferenced
when ArrayElement, etc. are compiled into a display list.

Should there be a new command "DiscardAndMapBuffer" that is
equivalent to BufferDataARB with NULL pointer followed by
MapBufferARB?

RESOLVED: NO, no one has come up with a clearly superior proposal
that everyone can agree on.

Are any GL commands disallowed when at least one buffer object is
mapped?

RESOLVED: NO. In general, applications may use whatever GL
commands they wish when a buffer is mapped. However, several
other restrictions on the application do apply: the application
must not attempt to source data out of, or sink data into, a
currently mapped buffer. Furthermore, the application may not
use the pointer returned by Map as an argument to a GL command.
(Note that this last restriction is unlikely to be enforced in
practice, but it violates reasonable expectations about how the
extension should be used, and it doesn't seem to be a very
interesting usage model anyhow. Maps are for the user, not for
the GL.)

More restrictive rules were considered (for example, "after
calling MapBuffer, all GL commands except for UnmapBuffer produce
errors"), but this was considered far too restrictive. The
expectation is that an application might map a buffer and start
filling it in a different thread, but continue to render in its
main thread (using a different buffer or no buffer at all). So
no commands are disallowed simply because a buffer happens to be
mapped.

Should the usage and data arguments to BufferDataARB be swapped?

RESOLVED: NO. This would be more consistent with other things in
GL if they were swapped, but no one seems to care. If we had
caught this earlier, maybe, but it's just too late.

How does MultiDrawElements work?

The language gets a little confusing, but I believe it is quite
clearly specified in the end. The argument <indices> to
MultiDrawElements, which is of type "const void **", is an
honest-to-goodness pointer to regular old system memory, no
matter whether a buffer is bound or not. That memory in turn
consists of an array of <primcount> pointers. If no buffer is
bound, each of those <primcount> pointers is a regular pointer.
If a buffer is bound, each of those <primcount> pointers is a
fake pointer that represents an offset in the buffer object.

If you wanted to put the array of <primcount> offsets in a buffer
object, you'd have to define a new extension with a new target.

New Procedures and Functions


    void BindBufferARB(enum target, uint buffer);
void DeleteBuffersARB(sizei n, const uint *buffers);
void GenBuffersARB(sizei n, uint *buffers);
boolean IsBufferARB(uint buffer);

void BufferDataARB(enum target, sizeiptrARB size, const void *data,
enum usage);
void BufferSubDataARB(enum target, intptrARB offset, sizeiptrARB size,
const void *data);
void GetBufferSubDataARB(enum target, intptrARB offset,
sizeiptrARB size, void *data);

void *MapBufferARB(enum target, enum access);
boolean UnmapBufferARB(enum target);

void GetBufferParameterivARB(enum target, enum pname, int *params);
void GetBufferPointervARB(enum target, enum pname, void **params);

New Tokens


    Accepted by the <target> parameters of BindBufferARB, BufferDataARB,
BufferSubDataARB, MapBufferARB, UnmapBufferARB,
GetBufferSubDataARB, GetBufferParameterivARB, and
GetBufferPointervARB:

ARRAY_BUFFER_ARB 0x8892
ELEMENT_ARRAY_BUFFER_ARB 0x8893

Accepted by the <pname> parameter of GetBooleanv, GetIntegerv,
GetFloatv, and GetDoublev:

ARRAY_BUFFER_BINDING_ARB 0x8894
ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895
VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896
NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897
COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898
INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899
TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A
EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B
SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C
FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D
WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E

Accepted by the <pname> parameter of GetVertexAttribivARB:

VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F

Accepted by the <usage> parameter of BufferDataARB:

STREAM_DRAW_ARB 0x88E0
STREAM_READ_ARB 0x88E1
STREAM_COPY_ARB 0x88E2
STATIC_DRAW_ARB 0x88E4
STATIC_READ_ARB 0x88E5
STATIC_COPY_ARB 0x88E6
DYNAMIC_DRAW_ARB 0x88E8
DYNAMIC_READ_ARB 0x88E9
DYNAMIC_COPY_ARB 0x88EA

Accepted by the <access> parameter of MapBufferARB:

READ_ONLY_ARB 0x88B8
WRITE_ONLY_ARB 0x88B9
READ_WRITE_ARB 0x88BA

Accepted by the <pname> parameter of GetBufferParameterivARB:

BUFFER_SIZE_ARB 0x8764
BUFFER_USAGE_ARB 0x8765
BUFFER_ACCESS_ARB 0x88BB
BUFFER_MAPPED_ARB 0x88BC

Accepted by the <pname> parameter of GetBufferPointervARB:

BUFFER_MAP_POINTER_ARB 0x88BD


Additions to Chapter 2 of the 1.4 Specification (OpenGL Operation)


    Add to Table 2.2:

"GL Type Minimum Description
Bit Width
-----------------------------------------------------------------
intptrARB <ptrbits> signed 2's complement binary integer
sizeiptrARB <ptrbits> Non-negative binary integer size"

Add to the paragraph under Table 2.2:

"<ptrbits> is the number of bits required to represent a pointer
type; in other words, types intptrARB and sizeiptrARB must be
sufficiently large as to store any address."

Add a new section "Buffer Objects" between sections 2.8 and 2.9:

"2.8A Buffer Objects
--------------------

The vertex data arrays described in section 2.8 are stored in client
memory. It is sometimes desirable to store frequently used client
data, such as vertex array data, in high-performance server memory.
GL buffer objects provide a mechanism that clients can use to
allocate, initialize, and render from such memory.

The name space for buffer objects is the unsigned integers, with zero
reserved for the GL. A buffer object is created by binding an unused
name to ARRAY_BUFFER_ARB. The binding is effected by calling

void BindBufferARB(enum target, uint buffer);

with <target> set to ARRAY_BUFFER_ARB and <buffer> set to the unused
name. The resulting buffer object is a new state vector, initialized
with a zero-sized memory buffer, and comprising the state values
listed in Table BufObj1.

Name Type Initial Value Legal Values
---- ---- ------------- ------------
BUFFER_SIZE_ARB integer 0 any non-negative
integer
BUFFER_USAGE_ARB enum STATIC_DRAW_ARB STREAM_DRAW_ARB,
STREAM_READ_ARB,
STREAM_COPY_ARB,
STATIC_DRAW_ARB,
STATIC_READ_ARB,
STATIC_COPY_ARB,
DYNAMIC_DRAW_ARB,
DYNAMIC_READ_ARB,
DYNAMIC_COPY_ARB
BUFFER_ACCESS_ARB enum READ_WRITE_ARB READ_ONLY_ARB,
WRITE_ONLY_ARB,
READ_WRITE_ARB
BUFFER_MAPPED_ARB boolean FALSE TRUE, FALSE
BUFFER_MAP_POINTER_ARB void* NULL address

Table BufObj1: Buffer object parameters and their values.

BindBufferARB may also be used to bind an existing buffer object.
If the bind is successful no change is made to the state of the
newly bound buffer object, and any previous binding to <target> is
broken.

While a buffer object is bound, GL operations on the target to which
it is bound affect the bound buffer object, and queries of the target
to which a buffer object is bound return state from the bound object.

In the initial state the GL-reserved name zero is bound to
ARRAY_BUFFER_ARB. There is no buffer object corresponding to the
name zero, so client attempts to modify or query buffer object state
for the target ARRAY_BUFFER_ARB while zero is bound will generate
GL errors.

Buffer objects are deleted by calling

void DeleteBuffersARB(sizei n, const uint *buffers);

<buffers> contains <n> names of buffer objects to be deleted. After
a buffer object is deleted it has no contents, and its name is again
unused. Unused names in <buffers> are silently ignored, as is the
value zero.

The command

void GenBuffersARB(sizei n, uint *buffers);

returns <n> previously unused buffer object names in <buffers>.
These names are marked as used, for the purposes of GenBuffersARB
only, but they acquire buffer state only when they are first bound,
just as if they were unused.

While a buffer object is bound, any GL operations on that object
affect any other bindings of that object. If a buffer object is
deleted while it is bound, all bindings to that object in the current
context (i.e. in the thread that called DeleteBuffers) are reset to
bindings to buffer zero. Bindings to that buffer in other contexts
and other threads are not affected, but attempting to use a deleted
buffer in another thread produces undefined results, including but
not limited to possible GL errors and rendering corruption. Using a
deleted buffer in another context or thread may not, however, result
in program termination.

The data store of a buffer object is created and initialized by
calling

void BufferDataARB(enum target, sizeiptrARB size,
const void *data, enum usage);

with <target> set to ARRAY_BUFFER_ARB, <size> set to the size of the
data store in basic machine units, and <data> pointing to the
source data in client memory. If <data> is non-null, then the source
data is copied to the buffer object's data store. If <data> is null,
then the contents of the buffer object's data store are undefined.

<usage> is specified as one of nine enumerated values, indicating
the expected application usage pattern of the data store. The
values are:

STREAM_DRAW_ARB The data store contents will be specified once
by the application, and used at most a few
times as the source of a GL (drawing) command.
STREAM_READ_ARB The data store contents will be specified once
by reading data from the GL, and queried at
most a few times by the application.
STREAM_COPY_ARB The data store contents will be specified once
by reading data from the GL, and used at most
a few times as the source of a GL (drawing)
command.
STATIC_DRAW_ARB The data store contents will be specified once
by the application, and used many times as the
source for GL (drawing) commands.
STATIC_READ_ARB The data store contents will be specified once
by reading data from the GL, and queried many
times by the application.
STATIC_COPY_ARB The data store contents will be specified once
by reading data from the GL, and used many
times as the source for GL (drawing) commands.
DYNAMIC_DRAW_ARB The data store contents will be respecified
repeatedly by the application, and used many
times as the source for GL (drawing) commands.
DYNAMIC_READ_ARB The data store contents will be respecified
repeatedly by reading data from the GL, and
queried many times by the application.
DYNAMIC_COPY_ARB The data store contents will be respecified
repeatedly by reading data from the GL, and
used many times as the source for GL (drawing)
commands.

<usage> is provided as a performance hint only. The specified usage
value does not constrain the actual usage pattern of the data store.

BufferDataARB deletes any existing data store, and sets the values of
the buffer object's state variables to:

Name Value
---- -----
BUFFER_SIZE_ARB <size>
BUFFER_USAGE_ARB <usage>
BUFFER_ACCESS_ARB READ_WRITE_ARB
BUFFER_MAPPED_ARB FALSE
BUFFER_MAP_POINTER_ARB NULL

Clients must align data elements consistent with the requirements
of the client platform, with an additional base-level requirement
that an offset within a buffer to a datum comprising N basic machine
units be a multiple of N.

If the GL is unable to create a data store of the requested size,
the error OUT_OF_MEMORY is generated.

To modify some or all of the data contained in a buffer object's data
store, the client may use the command

void BufferSubDataARB(enum target, intptrARB offset,
sizeiptrARB size, const void *data);

with <target> set to ARRAY_BUFFER_ARB. <offset> and <size> indicate
the range of data in the buffer object that is to be replaced, in
terms of basic machine units. <data> specifies a region of client
memory <size> basic machine units in length, containing the data that
replace the specified buffer range. An error is generated if
<offset> or <size> is less than zero, or if <offset> + <size> is
greater than the value of BUFFER_SIZE_ARB.

The entire data store of a buffer object can be mapped into the
client's address space by calling

void *MapBufferARB(enum target, enum access);

with <target> set to ARRAY_BUFFER_ARB. If the GL is able to map the
buffer object's data store into the client's address space,
MapBufferARB returns the pointer value to the data store. Otherwise
MapBufferARB returns NULL, and the error OUT_OF_MEMORY is generated.
<access> is specified as one of READ_ONLY_ARB, WRITE_ONLY_ARB, or
READ_WRITE_ARB, indicating the operations that the client may perform
on the data store through the pointer while the data store is mapped.

MapBufferARB sets the following buffer object state values:

Name Value
---- -----
BUFFER_ACCESS_ARB <access>
BUFFER_MAPPED_ARB TRUE
BUFFER_MAP_POINTER_ARB pointer to the data store

It is an INVALID_OPERATION error to map a buffer data store that is
in the mapped state.

Non-null pointers returned by MapBufferARB may be used by the client
to modify and query buffer object data, consistent with the access
rules of the mapping, while the mapping remains valid. No GL error
is generated if the pointer is used to attempt to modify a
READ_ONLY_ARB data store, or to attempt to read from a WRITE_ONLY_ARB
data store, but operation may be slow and system errors (possibly
including program termination) may result. Pointer values returned
by MapBufferARB may not be passed as parameter values to GL commands.
For example, they may not be used to specify array pointers, or to
specify or query pixel or texture image data; such actions produce
undefined results, although implementations may not check for such
behavior for performance reasons.

It is an INVALID_OPERATION error to call BufferSubDataARB to modify
the data store of a mapped buffer.

Mappings to the data stores of buffer objects may have nonstandard
performance characteristics. For example, such mappings may be
marked as uncacheable regions of memory, and in such cases reading
from them may be very slow. To ensure optimal performance, the
client should use the mapping in a fashion consistent with the values
of BUFFER_USAGE_ARB and BUFFER_ACCESS_ARB. Using a mapping in a
fashion inconsistent with these values is liable to be multiple
orders of magnitude slower than using normal memory.

After the client has specified the contents of a mapped data store,
and before the data in that store are dereferenced by any GL commands,
the mapping must be relinquished by calling

boolean UnmapBufferARB(enum target);

with <target> set to ARRAY_BUFFER_ARB. Unmapping a mapped buffer
object invalidates the pointers to its data store and sets the
object's BUFFER_MAPPED_ARB state to FALSE and its
BUFFER_MAP_POINTER_ARB state to NULL.

UnmapBufferARB returns TRUE unless data values in the buffer's data
store have become corrupted during the period that the buffer was
mapped. Such corruption can be the result of a screen resolution
change or other window-system-dependent event that causes system
heaps such as those for high-performance graphics memory to be
discarded. GL implementations must guarantee that such corruption
can occur only during the periods that a buffer's data store is
mapped. If such corruption has occurred, UnmapBufferARB returns
FALSE, and the contents of the buffer's data store become undefined.

It is an INVALID_OPERATION error to explicitly unmap a buffer data
store that is in the unmapped state. Unmapping that occurs as a side
effect of buffer deletion or reinitialization is not an error,
however."


2.8A.1 Vertex Arrays in Buffer Objects
--------------------------------------

Blocks of vertex array data may be stored in buffer objects with the
same format and layout options supported for client-side vertex
arrays. However, it is expected that GL implementations will (at
minimum) be optimized for data with all components represented as
floats, as well as for color data with components represented as
either floats or unsigned bytes.

A buffer object binding point is added to the client state associated
with each vertex array type. The client does not directly specify
the bindings to with these new binding points. Instead, the commands
that specify the locations and organizations of vertex arrays
copy the buffer object name that is bound to ARRAY_BUFFER_ARB to the
binding point corresponding to the vertex array of the type being
specified. For example, the NormalPointer command copies the value
of ARRAY_BUFFER_BINDING_ARB (the queriable name of the buffer binding
corresponding to the target ARRAY_BUFFER_ARB) to the client state
variable NORMAL_ARRAY_BUFFER_BINDING_ARB.

If EXT_vertex_shader is defined, then the command
VariantArrayEXT(uint id, ...) copies the value of
ARRAY_BUFFER_BINDING_ARB to the buffer object binding point
corresponding to variant array <id>.

If ARB_vertex_program is defined, then the command
VertexAttribPointerARB(int attrib, ...) copies the value of
ARRAY_BUFFER_BINDING_ARB to the buffer object binding point
corresponding to vertex attrib array <attrib>.

If ARB_vertex_blend is defined, then the command WeightPointerARB
copies the value of ARRAY_BUFFER_BINDING_ARB to
WEIGHT_ARRAY_BUFFER_BINDING_ARB.

Rendering commands ArrayElement, DrawArrays, DrawElements,
DrawRangeElements, MultiDrawArrays, and MultiDrawElements operate as
previously defined, except that data for enabled vertex, variant, and
attrib arrays are sourced from buffers if the array's buffer binding
is non-zero. When an array is sourced from a buffer object, the
pointer value of that array is used to compute an offset, in basic
machine units, into the data store of the buffer object. This offset
is computed by subtracting a null pointer from the pointer value,
where both pointers are treated as pointers to basic machine units.

It is acceptable for vertex, variant, or attrib arrays to be sourced
from any combination of client memory and various buffer objects
during a single rendering operation.

It is an INVALID_OPERATION error to source data from a buffer object
that is currently mapped.


2.8B.1 Array Indices in Buffer Objects
----------------------------------------------

Blocks of array indices may be stored in buffer objects with the
same format options that are supported for client-side index arrays.
Initially zero is bound to ELEMENT_ARRAY_BUFFER_ARB, indicating that
DrawElements and DrawRangeElements are to source their indices from
arrays passed as their <indices> parameters, and that
MultiDrawElements is to source its indices from the array of pointers
to arrays passed in as its <indices> parameter.

A buffer object is bound to ELEMENT_ARRAY_BUFFER_ARB by calling

void BindBufferARB(enum target, uint buffer);

with <target> set to ELEMENT_ARRAY_BUFFER_ARB, and <buffer> set to
the name of the buffer object. If no corresponding buffer object
exists, one is initialized as defined in Section 2.8A.

The commands BufferDataARB, BufferSubDataARB, MapBufferARB, and
UnmapBufferARB may all be used with <target> set to
ELEMENT_ARRAY_BUFFER_ARB. In such event, these commands operate in
the same fashion as described in section 2.8A, but on the buffer
currently bound to the ELEMENT_ARRAY_BUFFER_ARB target.

While a non-zero buffer object name is bound to
ELEMENT_ARRAY_BUFFER_ARB, DrawElements and DrawRangeElements source
their indices from that buffer object, using their <indices>
parameters as offsets into the buffer object in the same fashion as
described in section 2.8A1. MultiDrawElements also sources its
indices from that buffer object, using its <indices> parameter as a
pointer to an array of pointers that represent offsets into the
buffer object.

Buffer objects created by binding an unused name to ARRAY_BUFFER_ARB
and to ELEMENT_ARRAY_BUFFER_ARB are formally equivalent, but the GL
may make different choices about storage implementation based on
the initial binding. In some cases performance will be optimized
by storing indices and array data in separate buffer objects, and by
creating those buffer objects with the corresponding binding points."


Additions to Chapter 3 of the 1.4 Specification (Rasterization)


    None


Additions to Chapter 4 of the 1.4 Specification (Per-Fragment Operations and the Frame Buffer)


    None


Additions to Chapter 5 of the 1.4 Specification (Special Functions)


    Added to section 5.4, as part of the discussion of what commands
are compiled into display lists:

"Commands that are used to create, manage, and query buffer objects
are not included in display lists, but are executed immediately.
These commands are BindBufferARB, DeleteBuffersARB, GenBuffersARB,
IsBufferARB, BufferDataARB, BufferSubDataARB, MapBufferARB,
UnmapBufferARB, GetBufferParameterivARB, GetBufferSubDataARB,
and GetBufferPointervARB.

GL commands that source data from buffer objects dereference the
buffer object data in question at display list compile time, rather
than encoding the buffer ID and buffer offset into the display list.
Only GL commands that are executed immediately, rather than being
compiled into a display list, are permitted to use a buffer object as
a data sink."


Additions to Chapter 6 of the 1.4 Specification (State and State Requests)


    Added to section 6.1 in a subsection titled Buffer Object Queries:

"The command

boolean IsBufferARB(uint buffer);

returns TRUE if <buffer> is the name of an buffer object. If
<buffer> is zero, or if <buffer> is a non-zero value that is not
the name of an buffer object, IsBufferARB return FALSE.

The command

void GetBufferSubDataARB(enum target, intptrARB offset,
sizeiptrARB size, void *data);

queries the data contents of a buffer object. <target> is
ARRAY_BUFFER_ARB. <offset> and <size> indicate the range of data
in the buffer object that is to be queried, in terms of basic machine
units. <data> specifies a region of client memory, <size> basic
machine units in length, into which the data is to be retrieved.

An error is generated if GetBufferSubDataARB is executed for a buffer
object that is currently mapped.

While the data store of a buffer object is mapped, the pointer to
the data store can be queried by calling

void GetBufferPointervARB(enum target, enum pname, void **params);

with <target> set to ARRAY_BUFFER_ARB and <pname> set to
BUFFER_MAP_POINTER_ARB. The single buffer map pointer is returned
in <params>. GetBufferPointervARB returns the NULL pointer value if
the buffer's data store is not currently mapped, or if the requesting
client did not map the buffer object's data store, and the
implementation is unable to support mappings on multiple clients."

Added to the list of queries in section 6.1.3, Enumerated Queries:

"void GetBufferParameterivARB(enum target, enum pname, int *params);"


Errors


    INVALID_ENUM is generated if the <target> parameter of BindBufferARB,
BufferDataARB, BufferSubDataARB, MapBufferARB, UnmapBufferARB,
GetBufferSubDataARB, GetBufferParameterivARB, or GetBufferPointervARB
is not ARRAY_BUFFER_ARB or ELEMENT_ARRAY_BUFFER_ARB.

INVALID_VALUE is generated if the <n> parameter of DeleteBuffersARB or
GenBuffersARB is negative.

INVALID_VALUE is generated if the <size> parameter of BufferDataARB,
BufferSubDataARB, or GetBufferSubDataARB is negative.

INVALID_OPERATION is generated if BufferDataARB, BufferSubDataARB,
MapBufferARB, UnmapBufferARB, GetBufferSubDataARB,
GetBufferParameterivARB, or GetBufferPointervARB is executed while
zero is bound to the <target> parameter.

OUT_OF_MEMORY may be generated if the data store of a buffer object
cannot be allocated because the <size> argument of BufferDataARB is
too large.

OUT_OF_MEMORY may be generated when MapBufferARB is called if the
data store of the buffer object in question cannot be mapped. This
may occur for a variety of system-specific reasons, such as the
absence of sufficient remaining virtual memory.

INVALID_ENUM is generated if the <usage> parameter of BufferDataARB is
not STREAM_DRAW_ARB, STREAM_READ_ARB, STREAM_COPY_ARB, STATIC_DRAW_ARB,
STATIC_READ_ARB, STATIC_COPY_ARB, DYNAMIC_DRAW_ARB, DYNAMIC_READ_ARB,
or DYNAMIC_COPY_ARB.

INVALID_VALUE is generated if the <offset> parameter to BufferSubDataARB
or GetBufferSubDataARB is negative.

INVALID_VALUE is generated if the <offset> and <size> parameters of
BufferSubDataARB or GetBufferSubDataARB define a region of memory that
extends beyond that allocated by BufferDataARB.

INVALID_OPERATION is generated if MapBufferARB is executed for a
buffer that is already mapped.

INVALID_OPERATION is generated if UnmapBufferARB is executed for a
buffer that is not currently mapped.

INVALID_ENUM is generated if the <access> parameter of MapBufferARB
is not READ_ONLY_ARB, WRITE_ONLY_ARB, or READ_WRITE_ARB.

INVALID_ENUM is generated if the <pname> parameter of
GetBufferParameterivARB is not BUFFER_SIZE_ARB, BUFFER_USAGE_ARB,
BUFFER_ACCESS_ARB, or BUFFER_MAPPED_ARB.

INVALID_ENUM is generated if the <pname> parameter of
GetBufferPointervARB is not BUFFER_MAP_POINTER_ARB.

INVALID_OPERATION may be generated if any of the commands
defined in this extension is executed between the execution of Begin
and the corresponding execution of End.

INVALID_OPERATION is generated if a buffer object that is currently
mapped is used as a source of GL render data, or as a destination of
GL query data.

INVALID_OPERATION is generated if BufferSubDataARB is used to modify
the data store contents of a mapped buffer, or if GetBufferSubDataARB
is used to query to data store contents of a mapped buffer.


New State


(table 6.7, Vertex Array Data, p. 222)

Get Value Type Get Command Initial Value Sec Attribute
--------- ---- ----------- ------------- --- ---------
ARRAY_BUFFER_BINDING_ARB Z+ GetIntegerv 0 2.8A vertex-array
VERTEX_ARRAY_BUFFER_BINDING_ARB Z+ GetIntegerv 0 2.8A vertex-array
NORMAL_ARRAY_BUFFER_BINDING_ARB Z+ GetIntegerv 0 2.8A vertex-array
COLOR_ARRAY_BUFFER_BINDING_ARB Z+ GetIntegerv 0 2.8A vertex-array
INDEX_ARRAY_BUFFER_BINDING_ARB Z+ GetIntegerv 0 2.8A vertex-array
TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB Z+ GetIntegerv 0 2.8A vertex-array
EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB Z+ GetIntegerv 0 2.8A vertex-array
SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB Z+ GetIntegerv 0 2.8A vertex-array
FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB Z+ GetIntegerv 0 2.8A vertex-array
WEIGHT_ARRAY_BUFFER_BINDING_ARB Z+ GetIntegerv 0 2.8A vertex-array
ELEMENT_ARRAY_BUFFER_BINDING_ARB Z+ GetIntegerv 0 2.8A.2 vertex-array

VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 16+ x Z+ GetVertexAttribivARB 0 2.8A vertex-array

XXX need to add buffer state for variant arrays

(new table for buffer objects)

Get Value Type Get Command Initial Value Sec Attribute
--------- ---- ----------- ------------- --- ---------
(buffer data) BMU GetBufferSubDataARB 2.8A none
BUFFER_SIZE_ARB Z+ GetBufferParameterivARB 0 2.8A none
BUFFER_USAGE_ARB Z9 GetBufferParameterivARB STATIC_DRAW_ARB 2.8A none
BUFFER_ACCESS_ARB Z3 GetBufferParameterivARB READ_WRITE_ARB 2.8A none
BUFFER_MAPPED_ARB B GetBufferParameterivARB FALSE 2.8A none
BUFFER_MAP_POINTER_ARB Y GetBufferPointervARB NULL 2.8A none


New Implementation Dependent State


    (none)


Usage Examples


    These examples illustrate various usages.  In all cases a rendering
loop is included, and array parameters are initialized inside the
loop as would be required if multiple array rendering operations
were performed in the loops. (Though only one operation is shown.)

Convenient macro definition for specifying buffer offsets:

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

Traditional vertex arrays:

// Create system memory buffer
data = malloc(320);

// Fill system memory buffer
...

// Frame rendering loop
while (...) {

// Define arrays
VertexPointer(4, FLOAT, 0, data);
ColorPointer(4, UNSIGNED_BYTE, 0, data+256);

// Enable arrays
EnableClientState(VERTEX_ARRAY);
EnableClientState(COLOR_ARRAY);

// Draw arrays
DrawArrays(TRIANGLE_STRIP, 0, 16);

// Disable arrays
DisableClientState(VERTEX_ARRAY);
DisableClientState(COLOR_ARRAY);

// Other rendering commands
...

}

// Free system memory buffer
free(data);


Vertex arrays using a buffer object:

// Create system memory buffer
data = malloc(320);

// Fill system memory buffer
...

// Create buffer object
BindBufferARB(ARRAY_BUFFER_ARB, 1);

// Initialize data store of buffer object
BufferDataARB(ARRAY_BUFFER_ARB, 320, data, STATIC_DRAW_ARB);

// Free system memory buffer
free(data);

// Frame rendering loop
while (...) {

// Define arrays
BindBufferARB(ARRAY_BUFFER_ARB, 1);
VertexPointer(4, FLOAT, 0, BUFFER_OFFSET(0));
ColorPointer(4, UNSIGNED_BYTE, 0, BUFFER_OFFSET(256));

// Enable arrays
EnableClientState(VERTEX_ARRAY);
EnableClientState(COLOR_ARRAY);

// Draw arrays
DrawArrays(TRIANGLE_STRIP, 0, 16);

// Disable arrays
DisableClientState(VERTEX_ARRAY);
DisableClientState(COLOR_ARRAY);

// Other rendering commands
...

}

// Delete buffer object
int buffer[1] = {1};
DeleteBuffersARB(1, buffer);


Code that works with and without buffer objects:

// Create system memory buffer
data = malloc(320);

// Fill system memory buffer
...

// Initialize buffer object, and null the data pointer
#ifdef USE_BUFFER_OBJECTS
BindBufferARB(ARRAY_BUFFER_ARB, 1);
BufferDataARB(ARRAY_BUFFER_ARB, 320, data, STATIC_DRAW_ARB);
free(data);
data = NULL;
#endif

// Frame rendering loop
while (...) {

// Define arrays
#ifdef USE_BUFFER_OBJECTS
BindBufferARB(ARRAY_BUFFER_ARB, 1);
#endif
VertexPointer(4, FLOAT, 0, data);
ColorPointer(4, UNSIGNED_BYTE, 0, data+256);

// Enable arrays
EnableClientState(VERTEX_ARRAY);
EnableClientState(COLOR_ARRAY);

// Draw arrays
DrawArrays(TRIANGLE_STRIP, 0, 16);

// Disable arrays
DisableClientState(VERTEX_ARRAY);
DisableClientState(COLOR_ARRAY);

// Other rendering commands
...

}

// Delete buffer object
#ifdef USE_BUFFER_OBJECTS
int buffer[1] = {1};
DeleteBuffersARB(1, buffer);
#else
// Free system memory buffer
free(data);
#endif


Vertex arrays using a mapped buffer object:

// Frame rendering loop
while (...) {

// Define arrays (and create buffer object in first pass)
BindBufferARB(ARRAY_BUFFER_ARB, 1);
VertexPointer(4, FLOAT, 0, BUFFER_OFFSET(0));
ColorPointer(4, UNSIGNED_BYTE, 0, BUFFER_OFFSET(256));

// Enable arrays
EnableClientState(VERTEX_ARRAY);
EnableClientState(COLOR_ARRAY);

// Initialize data store of buffer object
BufferDataARB(ARRAY_BUFFER_ARB, 320, NULL, STREAM_DRAW_ARB);

// Map the buffer object
float *p = MapBufferARB(ARRAY_BUFFER_ARB, WRITE_ONLY);

// Compute and store data in mapped buffer object
...

// Unmap buffer object and draw arrays
if (UnmapBufferARB(ARRAY_BUFFER_ARB)) {
DrawArrays(TRIANGLE_STRIP, 0, 16);
}

// Disable arrays
DisableClientState(VERTEX_ARRAY);
DisableClientState(COLOR_ARRAY);

// Other rendering commands
...

}

// Delete buffer object
int buffer[1] = {1};
DeleteBuffersARB(1, buffer);


Vertex arrays using a mapped buffer object for array data and an
unmapped buffer object for indices:

// Create system memory buffer for indices
indexdata = malloc(400);

// Fill system memory buffer with 100 indices
...

// Create index buffer object
BindBufferARB(ELEMENT_ARRAY_BUFFER_ARB, 2);
BufferDataARB(ELEMENT_ARRAY_BUFFER_ARB, 400, indexdata,
STATIC_DRAW_ARB);

// Free system memory buffer
free(indexdata);

// Frame rendering loop
while (...) {

// Define arrays (and create buffer object in first pass)
BindBufferARB(ARRAY_BUFFER_ARB, 1);
VertexPointer(4, FLOAT, 0, BUFFER_OFFSET(0));
ColorPointer(4, UNSIGNED_BYTE, 0, BUFFER_OFFSET(256));
BindBufferARB(ELEMENT_ARRAY_BUFFER_ARB, 2);

// Enable arrays
EnableClientState(VERTEX_ARRAY);
EnableClientState(COLOR_ARRAY);

// Initialize data store of buffer object
BufferDataARB(ARRAY_BUFFER_ARB, 320, NULL, STREAM_DRAW_ARB);

// Map the buffer object
float *p = MapBufferARB(ARRAY_BUFFER_ARB, WRITE_ONLY);

// Compute and store data in mapped buffer object
...

// Unmap buffer object and draw arrays
if (UnmapBufferARB(ARRAY_BUFFER_ARB)) {
DrawElements(TRIANGLE_STRIP, 100, UNSIGNED_INT,
BUFFER_OFFSET(0));
}

// Disable arrays
DisableClientState(VERTEX_ARRAY);
DisableClientState(COLOR_ARRAY);

// Other rendering commands
...

}

// Delete buffer objects
int buffers[2] = {1, 2};
DeleteBuffersARB(1, buffers);


Mapping multiple buffers simultaneously:

// Map buffers
BindBuffer(ARRAY_BUFFER_ARB, 1);
float *a = MapBuffer(ARRAY_BUFFER_ARB, WRITE_ONLY);
BindBuffer(ARRAY_BUFFER_ARB, 2);
float *b = MapBuffer(ARRAY_BUFFER_ARB, WRITE_ONLY);

// Fill buffers
...

// Unmap buffers
BindBuffer(ARRAY_BUFFER_ARB, 1);
if (!UnmapBufferARB(ARRAY_BUFFER_ARB)) {
// Handle error case
}
BindBuffer(ARRAY_BUFFER_ARB, 2);
if (!UnmapBufferARB(ARRAY_BUFFER_ARB)) {
// Handle error case
}

Implementation Support


   List of OpenGL implementations supporting the GL_ARB_vertex_buffer_object extension

Original File


   Original text file for the GL_ARB_vertex_buffer_object extension


Page generated on Sun Nov 20 18:36:38 2005