Name

    ARB_buffer_storage

Name Strings

    GL_ARB_buffer_storage

Contact

    Graham Sellers (graham.sellers 'at' amd.com)

Contributors

    Jeff Bolz, NVIDIA
    Daniel Koch, NVIDIA
    Jon Leech
    Mark Kilgard, NVIDIA

Notice

    Copyright (c) 2013 The Khronos Group Inc. Copyright terms at
        http://www.khronos.org/registry/speccopyright.html

Status

    Complete. Approved by the ARB on June 3, 2013.
    Ratified by the Khronos Board of Promoters on July 19, 2013.

Version

    Last Modified Date: April 20, 2015
    Revision: 25

Number

    ARB Extension #144

Dependencies

    This extension is written against version 4.3 of the Core Profile OpenGL
    Specification, dated August 6, 2012.

    The definition of this extension is affected by the presence of
    GL_EXT_direct_state_access.

Overview

    OpenGL has long supported buffer objects as a means of storing data
    that may be used to source vertex attributes, pixel data for textures,
    uniforms and other elements. In un-extended GL, buffer data stores
    are mutable - that is, they may be de-allocated or resized while they
    are in use. The GL_ARB_texture_storage extension added immutable storage
    for texture object (and was subsequently incorporated into OpenGL 4.2).
    This extension further applies the concept of immutable storage to
    buffer objects. If an implementation is aware of a buffer's immutability,
    it may be able to make certain assumptions or apply particular
    optimizations in order to increase performance or reliability.

    Furthermore, this extension allows applications to pass additional
    information about a requested allocation to the implementation which it
    may use to select memory heaps, caching behavior or allocation strategies.

    Finally, this extension introduces the concept of persistent client
    mappings of buffer objects, which allow clients to retain pointers to a
    buffer's data store returned as the result of a mapping, and to issue
    drawing commands while those mappings are in place.

New Procedures and Functions

    void BufferStorage(enum target,
                       sizeiptr size,
                       const void * data,
                       bitfield flags);

    When EXT_direct_state_access is present:

    void NamedBufferStorageEXT(uint buffer,
                               sizeiptr size,
                               const void * data,
                               bitfield flags);

New Tokens

    Accepted in the <flags> parameter of BufferStorage and
    NamedBufferStorageEXT:

        MAP_READ_BIT                                0x0001 (existing)
        MAP_WRITE_BIT                               0x0002 (existing)
        MAP_PERSISTENT_BIT                          0x0040
        MAP_COHERENT_BIT                            0x0080
        DYNAMIC_STORAGE_BIT                         0x0100
        CLIENT_STORAGE_BIT                          0x0200

    Accepted as part of the <access> parameter to MapBufferRange:

        MAP_PERSISTENT_BIT                          0x00000040
        MAP_COHERENT_BIT                            0x00000080

    Accepted by the <pname> parameter of GetBufferParameter{i|i64}v:

        BUFFER_IMMUTABLE_STORAGE                    0x821F
        BUFFER_STORAGE_FLAGS                        0x8220

    Accepted by the <barriers> parameter of MemoryBarrier:

        CLIENT_MAPPED_BUFFER_BARRIER_BIT            0x00004000

IP Status

    No known IP claims.

Additions to Chapter 2 of the OpenGL Core Profile Specification, Version 4.3,
"OpenGL Fundamentals"

    Insert before the last line of Section 2.5.2, "Buffer Objects", p. 26:

    Under certain circumstances, the data store of a buffer object may
    be shared between the client and server and accessed simultaneously
    by both.

Additions to Chapter 6 of the OpenGL Core Profile Specification, Version 4.3,
"Buffer Objects"

    Modify Section 6.2, "Creating and Modifying Buffer Object Data Stores",
    p. 57 as follows:

    The data store of a buffer object is created by calling

        void BufferStorage(enum target,
                           sizeiptr size,
                           const void * data,
                           bitfield flags);

    with <target> set to one of the targets listed in Table 6.1, <size> set to
    the size of the data store in basic machine units and <flags> containing
    a bit-field describing the intended usage of the data store. The data
    store of the buffer object bound to <target> is allocated as a result of
    a call to this function and cannot be de-allocated until the buffer is
    deleted with a call to DeleteBuffers. Such a store may not be
    re-allocated through further calls to BufferStorage or BufferData.

    <data> specifies the address in client memory of the data that should
    be used to initialize the buffer's data store. If <data> is NULL, the
    data store of the buffer is created, but contains undefined data.
    Otherwise, <data> should point to an array of at least <size> basic
    machine units.

    <flags> is the bitwise OR of flags describing the intended usage
    of the buffer object's data store by the application. Valid flags and
    their meanings are as follows:

        DYNAMIC_STORAGE_BIT   The contents of the data store may be
    updated after creation through calls to BufferSubData. If this bit is not
    set, the buffer content may not be directly updated by the client. The
    <data> argument may be used to specify the initial content of the buffer's
    data store regardless of the presence of the DYNAMIC_STORAGE_BIT.
    Regardless of the presence of this bit, buffers may always be updated
    with server-side calls such as CopyBufferSubData and ClearBufferSubData.

        MAP_READ_BIT  The buffer's data store may be mapped by the client for
    read access and a pointer in the client's address space obtained that may
    be read from.

        MAP_WRITE_BIT  The buffer's data store may be mapped by the client for
    write access and a pointer in the client's address space obtained that may
    be written to.

        MAP_PERSISTENT_BIT  The client may request that the server read from
    or write to the buffer while it is mapped. The client's pointer to the
    data store remains valid so long as the data store is mapped, even during
    execution of drawing or dispatch commands.

        MAP_COHERENT_BIT  Shared access to buffers that are simultaneously
    mapped for client access and are used by the server will be coherent, so
    long as that mapping is performed using MapBufferRange. That is, data
    written to the store by either the client or server will be immediately
    visible to the other with no further action taken by the application. In
    particular:

        - If MAP_COHERENT_BIT is not set and the client performs a write
          followed by a call to one of the FlushMapped*BufferRange commands
          with a range including the written range, then in subsequent
          commands the server will see the writes.

        - If MAP_COHERENT_BIT is set and the client performs a write, then in
          subsequent commands the server will see the writes.

        - If MAP_COHERENT_BIT is not set and the server performs a write, the
          application must call MemoryBarrier with the
          CLIENT_MAPPED_BUFFER_BARRIER_BIT set and then call FenceSync with
          SYNC_GPU_COMMANDS_COMPLETE (or Finish). Then the CPU will see the
          writes after the sync is complete.

        - If MAP_COHERENT_BIT is set and the server does a write, the app must
          call FenceSync with SYNC_GPU_COMMANDS_COMPLETE (or Finish). Then the
          CPU will see the writes after the sync is complete.

        CLIENT_STORAGE_BIT  When all other criteria for the buffer storage
    allocation are met, this bit may be used by an implementation to determine
    whether to use storage that is local to the server or to the client to
    serve as the backing store for the buffer.

    If <flags> contains MAP_PERSISTENT_BIT, it must also contain at least one
    of MAP_READ_BIT or MAP_WRITE_BIT.

    It is an error to specify MAP_COHERENT_BIT without also specifying
    MAP_PERSISTENT_BIT.

    BufferStorage deletes any existing data store, and sets the values of
    the buffer object's state variables as shown in table 6.3.

    If any portion of the buffer object is mapped in the current context or
    any context current to another thread, it is as though UnmapBuffer (see
    section 6.3.1) is executed in each such context prior to deleting the
    existing data store.

    Name                     | Value for             | Value for
                             | BufferData            | BufferStorage
    -------------------------+-----------------------+---------------
    BUFFER_SIZE              | <size>                | <size>
    BUFFER_USAGE             | <usage>               | DYNAMIC_DRAW
    BUFFER_ACCESS            | READ_WRITE            | READ_WRITE
    BUFFER_ACCESS_FLAGS      | 0                     | 0
    BUFFER_IMMUTABLE_STORAGE | FALSE                 | TRUE
    BUFFER_MAPPED            | FALSE                 | FALSE
    BUFFER_MAP_POINTER       | NULL                  | NULL
    BUFFER_MAP_OFFSET        | 0                     | 0
    BUFFER_MAP_LENGTH        | 0                     | 0
    BUFFER_STORAGE_FLAGS     | MAP_READ_BIT |        | <flags>
                             | MAP_WRITE_BIT |       |
                             | DYNAMIC_STORAGE_BIT   |
        Table 6.3: Buffer object state after calling BufferData or
        BufferStorage.

    A mutable data store may be allocated for a buffer object by calling

        void BufferData(...)

        <include the remainder of Section 6.2 as written, and then append>.

    Calling BufferData is equivalent to calling BufferStorage with
    <target>, <size> and <data> as specified, and <flags> set to the logical
    OR of DYNAMIC_STORAGE_BIT, MAP_READ_BIT and MAP_WRITE_BIT. The GL will
    use the value of <usage> parameter to BufferData as a hint to further
    determine the intended use of the buffer. However, BufferStorage allocates
    immutable storage whereas BufferData allocates mutable storage. Thus, when
    a buffer's data store is allocated through a call to BufferData, the
    buffer's BUFFER_IMMUTABLE_STORAGE flags is set to FALSE.

    Add the following errors:

    An INVALID_OPERATION error is generated by BufferData and BufferStorage
    if the BUFFER_IMMUTABLE_STORAGE flag of the buffer bound to <target> is
    set to TRUE.

    An INVALID_OPERATION error is generated by BufferSubData if the
    BUFFER_IMMUTABLE_STORAGE flag of the buffer bound to <target> is TRUE
    and the value of BUFFER_STORAGE_FLAGS for the buffer does not have
    the DYNAMIC_STORAGE_BIT set.

    The command:

        void NamedBufferStorageEXT(uint buffer,
                                   sizeiptr size,
                                   const void * data,
                                   bitfield flags);

    behaves similarly to BufferStorage, except that the buffer whose storage
    is to be defined is specified by <buffer> rather than by the current
    binding to <target>.

    Add the following error:

    An INVALID_OPERATION error is generated by NamedBufferStorageEXT if
    the BUFFER_IMMUTABLE_STORAGE flag of <buffer> is set to TRUE.

    Append to Table 6.2, "Buffer object parameters and their values":

        +---------------------------+---------+-----------+------------------+
        |                           |         | Initial   | Legal            |
        | Name                      | Type    | Value     | Values           |
        +---------------------------+---------+-----------+------------------+
        | BUFFER_IMMUTABLE_STORAGE  | boolean | FALSE     | TRUE, FALSE      |
        | BUFFER_STORAGE_FLAGS      | int     | 0         | See section 6.2  |
        +---------------------------+---------+-----------+------------------+

    Append to Table 6.3, "Buffer object initial state":

        +---------------------------+-------------------------------------- +
        | Name                      | Value                                 |
        +---------------------------+---------------------------------------+
        | BUFFER_IMMUTABLE_STORAGE  | TRUE if the buffer's storage is       |
        |                           | immutable, FALSE otherwise            |
        | BUFFER_STORAGE_FLAGS      | 0                                     |
        +---------------------------+---------------------------------------+

    Modify Section 6.3, "Mapping and Unmapping Buffer Data"

    Add to the bulleted list describing flags that modify buffer mappings,
    p.62.

        * MAP_PERSISTENT_BIT indicates that it is not an error for the GL to
          read data from or write data to the buffer while it is mapped (see
          section 6.3.2). If this bit is set, the value of
          BUFFER_STORAGE_FLAGS for the buffer being mapped must include
          MAP_PERSISTENT_BIT.

        * MAP_COHERENT_BIT indicates that the mapping should be performed
          coherently. That is, such a mapping follows the rules set forth in
          section 6.2, "Creating and Modifying Buffer Object Data Stores".
          If the MAP_COHERENT_BIT is set and the buffer's BUFFER_STORAGE_FLAGS
          does not include MAP_COHERENT_BIT, the error INVALID_OPERATION is
          generated.

    Modify Section 6.3.2, "Effects of Mapping Buffers on Other GL Commands"
    to read:

    An INVALID_OPERATION error is generated by most, but not all GL
    commands when an attempt is detected by such a command to read data from
    or write data to a mapped buffer object unless it was allocated with the
    by a call to BufferStorage with MAP_PERSISTENT_BIT set in
    <flags>.

    Any command which does not detect these attempts, and performs such an
    invalid read or write, has undefined results and may result in GL
    interruption or termination.

    Add the following to the description of FlushMappedBufferRange:

    If a buffer range is mapped with both the MAP_PERSISTENT_BIT and
    MAP_FLUSH_EXPLICIT_BIT set, then FlushMappedBufferRange may be called to
    ensure that data written by the client into the flushed region becomes
    visible to the server. Data written to a coherent store will always
    become visible to the server after an unspecified period of time.

    Modify Section 6.8, "Buffer Object State", p. 70:

        Add the following required state to a buffer object:

        ..., a boolean indicating whether or not buffer storage is
    immutable, an unsigned integer storing the flags with which it was
    allocated, ...

Additions to Chapter 7 of the OpenGL Core Profile Specification, Version 4.3,
"Programs and Shaders"

    Add to the list of flags accepted by the <barriers> parameter to
    MemoryBarrier in Section 7.12.2, "Shader Memory Access Synchronization":

        * CLIENT_MAPPED_BUFFER_BARRIER_BIT: Access by the client to persistent
          mapped regions of buffer objects will reflect data written by shaders
          prior to the barrier. Note that this may cause additional
          synchronization operations.

New State

    Append to Table 23.6, "Buffer Object State", p. 511:

    +---------------------------+-----------+----------------------+-------------------+---------------------------------+------------+
    | Get Value                 | Type      | Get Command          | Initial Value     | Description                     | Sec.       |
    +---------------------------+-----------+----------------------+-------------------+---------------------------------+------------+
    | BUFFER_IMMUTABLE_STORAGE  | B         | GetBufferParameteriv | FALSE             | TRUE if buffer's data store is  | 6          |
    |                           |           |                      |                   | immutable, FALSE otherwise      |            |
    | BUFFER_STORAGE_FLAGS      | Z+        | GetBufferParameteriv | 0                 | The buffer object's storage     | 6          |
    |                           |           |                      |                   | flags.                          |            |
    +---------------------------+-----------+----------------------+-------------------+---------------------------------+------------+

New Implementation Dependent State

    None.

Errors

    INVALID_OPERATION is generated by BufferStorage if zero is bound to
    <target>.

    INVALID_OPERATION is generated by BufferStorage, NamedBufferStorageEXT
    and BufferData if the buffer object already owns an immutable data
    store.

    INVALID_VALUE is generated by BufferStorage and NamedBufferStorageEXT
    if <size> is less than or equal to zero.

    INVALID_VALUE is generated by BufferStorage and NamedBufferStorageEXT if
    <flags> contains MAP_PERSISTENT_BIT but does not contain
    at least one of MAP_READ_BIT or
    MAP_WRITE_BIT.

    INVALID_VALUE is generated by BufferStorage and NamedBufferStorageEXT if
    <flags> contains MAP_COHERENT_BIT, but does not also
    contain MAP_PERSISTENT_BIT.

    INVALID_OPERATION is generated by MapBufferRange if any of MAP_READ_BIT,
    MAP_WRITE_BIT, MAP_PERSISTENT_BIT, or MAP_COHERENT_BIT are included in
    <access>, but the same bit is not included in the buffer's storage
    flags.

    INVALID_OPERATION is generated by MapBufferRange if MAP_PERSISTENT_BIT
    is included in <access> but MAP_PERSISTENT_BIT is not
    included in the buffer's storage flags, or if MAP_COHERENT_BIT is included
    in <access> but

    OUT_OF_MEMORY is generated by BufferStorage and NamedBufferStorageEXT if
    the GL is not able to allocate a data store with the properties requested
    in <flags>.

    *REMOVE* all errors generated by any command should they detect access to
    a mapped buffer and replace with language such as:

    INVALID_OPERATION is generated by <command> if the buffer is currently
    mapped by MapBuffer{Range} unless it was mapped with the
    MAP_PERSISTENT_BIT included in <access>.

Dependencies on GL_EXT_direct_state_access

    If GL_EXT_direct_state_access is not supported, remove all references to
    NamedBufferStorageEXT.

Conformance Tests

    TBD

Usage Examples

    Example 1: Updating the content of a buffer which does not have the
    DYNAMIC flag set:

    // Allocate two buffers, one of which will be our 'staging buffer'.
    GLuint bufs[2];
    glGenBuffers(2, &bufs[0]);

    // Client can map this buffer for write.
    // One could possibly make this mapping persistent.
    glBindBuffer(GL_COPY_READ_BUFFER, bufs[0]);
    glBufferStorage(GL_COPY_READ_BUFFER, size, NULL,
                    GL_MAP_WRITE_BIT);

    // Client cannot read or write this buffer, server can do both.
    glBindBuffer(GL_COPY_WRITE_BUFFER, bufs[1]);
    glBufferStorage(GL_COPY_WRITE_BUFFER, size, NULL, 0);

    // Now, map the staging buffer to put data into it.
    void * data = glMapBufferRange(GL_COPY_READ_BUFFER, 0, size,
                                   GL_MAP_WRITE_BIT |
                                   GL_MAP_INVALIDATE_BUFFER_BIT);
    memcpy(data, source_data, size);
    glUnmapBuffer(GL_COPY_READ_BUFFER);

    // Copy from the staging buffer to the server-side buffer.
    glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, size);

    Example 2: Read from framebuffer into a buffer mapped into client's
    address space:

    // Create buffer, allocate storage, and create a persistent map.
    GLuint pbo;
    glGenBuffers(1, &pbo);
    glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
    glBufferStorage(GL_PIXEL_PACK_BUFFER, size, NULL,
                    GL_MAP_READ_BIT |
                    GL_MAP_PERSISTENT_BIT);

    void * data = glMapBufferRange(GL_PIXEL_PACK_BUFFER,
                                   GL_MAP_READ_BIT |
                                   GL_MAP_PERSISTENT_BIT);

    glReadPixels(0, 0, width, height, format, type, NULL);
    glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT);
    GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);

    // Do stuff to use time...
    ReallyExpensiveFunction();

    glClientWaitSync(fence);

    // Use the data written to the buffer
    UseDataInMemory(data);

    XXX TODO::: MORE EXAMPLES HERE

Issues

    1) What is the best strategy to allow 'render while mapped'? Options I
       can think of right now are (a) Allow the application to render when a
       buffer is mapped, so long as the MAP_PERSISTENT_BIT
       was set when it was allocated; (b) Continue to disallow 'render while
       mapped', but say that a client pointer obtained from MapBuffer{Range}
       remains valid even when the buffer is not mapped, so long as it has
       not been destroyed; (c) add a flag to glMapBufferRange's <access>
       parameter to indicate the desire to render with it.

       RESOLVED: We choose a combination of (a) and (c). The application must
       both create the data store with MAP_PERSISTENT_BIT set
       _and_ map it with MAP_PERSISTENT_BIT set in <access>. Did the same
       for coherency too.

    2) The new flags don't directly map to the <usage> parameter for
       glBufferData and one cannot be expressed in terms of the other. Does
       that matter?

       RESOLVED: Most applications get <usage> wrong and they're only hints
       anyway. The flags are hard and fast rules that must be followed. They
       serve a different purpose. The idea here is to allow the
       implementation to not have to second guess the application and to
       perform less tracking, and for the application to have more control.
       We define BufferData in terms of BufferStorage with the most liberal
       allowed flags (essentially, anything goes), but still pass the
       <usage> hint to the implementation to allow it to continue to second
       guess the application.

    3) Do we have all the flags we want? Are any problematic?

       RESOLVED: We don't want any more flags. We don't believe any are
       problematic.

    4) Should we include MULTI_TARGET_BIT? There are legitimate use cases where
       a buffer could be used on two or three targets. However, this bit is an
       'all or nothing' kind of thing.

       RESOLVED: No, not at this time.

    5) How do you get data into a non-dynamic buffer if you can't write to it
       from the client?

       RESOLVED: The server is capable of writing to buffers that were not
       allocated with the DYNAMIC flag set. Therefore, it is possible to
       use CopyBufferSubData to copy from a dynamic buffer to a non-dynamic
       buffer. It's also possible to write to it with any other server-side
       mechanism such as transform feedback, image stores and so on.

    6) If a buffer is allocated without the GL_BUFFER_STORAGE_SERVER_READ_BIT
       (or GL_BUFFER_STORAGE_SERVER_WRITE_BIT), what happens if an attempt is
       made use the buffer in a way that may cause the server to read
       (or write) to the buffer?

       RESOLVED: Nuked the SERVER_READ and SERVER_WRITE bits. They didn't
       serve the purpose for which they were intended.

    7) Which operations are able to update buffers that are not dynamic?

       Non-dynamic buffers effectively don't allow direct transfer of data
       from client to server (i.e., glBufferSubData). Examples of operations
       that may write to non-dynamic buffers are transform feedback, image
       stores, ReadPixels, GetTexImage (PBO), CopyBufferSubData,
       ClearBufferSubData - essentially anything that doesn't transfer
       arbitrary amounts of data from client to server.

    8) Are there any restrictions on calling GetBufferSubData on a buffer
       allocated using BufferStorage?

       RESOLVED: No, there are not.

    9) What is the meaning of CLIENT_STORAGE_BIT? Is it one of those
       silly hint things?

       DISCUSSION: Unfortunately, yes, it is. For some platforms, such as UMA
       systems, it's irrelevant and all memory is both server and client
       accessible. The issue is, that on some platforms and for certain
       combinations of flags, there may be multiple regions of memory that
       can satisfy the request (visible to both server and client and coherent
       to both, for example), but may have substantially different performance
       characteristics for access from either. This bit essentially serves
       as a hint to say that that an application will access the store more
       frequently from the client than from the server. In practice,
       applications will still get it wrong (like setting it all the time or
       never setting it at all, for example), implementations will still have
       to second guess applications and end up full of heuristics to figure out
       where to put data and gobs of code to move things around based on what
       applications do, and eventually it'll make no difference whether
       applications set it or not. But hey, we tried.

    10) Do we want to add flags for MapBufferRange for PERSISTENT and/or
        COHERENT mapping? In their absence, implementations must assume that
        any mapping performed on a buffer whose storage flags include the
        PERSISTENT or COHERENT flags must behave appropriately.

        RESOLVED. Added.

    11) Do we need language to explicitly say that flushes of non-coherent
        mapped buffers need to occur on buffers mapped with the FLUSH_EXPLICIT
        bit?

        RESOLVED: No. The language already states that FlushMappedBufferRange
        should be used to perform the flush, and this command requires that
        the mapping be established with the FLUSH_EXPLICIT bit set.

    12) Which functions can/cannot be used to update the content of a
        non-DYNAMIC buffer? Can the buffer be the target of an update
        operation at all?

        RESOLVED: BufferSubData is only allowed for DYNAMIC buffers. Updates
        through mappings are allowed so long as the STORAGE_MAP_WRITE_BIT is
        set. Server side commands, including CopyBufferSubData,
        ClearBufferSubData, ReadPixels, GetTexImage are allowed. Further,
        shader writes such as image stores, SSBO, atomic counters, transform
        feedback and so on are also allowed.

    13) Why is there a gap between the MAP_WRITE_BIT and MAP_PERSISTENT_BIT
        token values?

        RESOLVED: MAP_PERSISTENT_BIT and MAP_COHERENT_BIT are allocated from
        the bitfield used for MapBufferRange, which include values that
        aren't relevant for BufferStorage. This allows the same tokens
        to be used as flags for BufferStorage and MapBufferRange, hopefully
        reducing confusion.

Revision History

    Rev.    Date      Author    Changes
    ----  --------    --------  -----------------------------------------

     1    01/16/2013  gsellers  Initial draft

     2    01/21/2013  gsellers  Updates

     3    01/22/2013  gsellers  Change static->dynamic. Remove target
                                restrictions. Get a little closer to expressing
                                BufferData in terms of BufferStorage.

     4    04/22/2013  gsellers  Add CLIENT_MAPPED_BUFFER_ACCESS_BIT for
                                MemoryBarrier.
                                Add BUFFER_STORAGE_{READ|WRITE}_BIT and issue 6.
                                Add example usage for non-dynamic buffers.
                                Add issue 7.

     5    04/23/2013  gsellers  Nuked the BUFFER_STORAGE_{READ|WRITE}_BIT
                                flags again.
                                Make DYNAMIC and MAP_WRITE_BIT
                                orthogonal.
                                Rename CLIENT_MAPPED_BUFFER_ACCESS_BIT to
                                CLIENT_MAPPED_BUFFER_BARRIER_BIT.
                                Add another example.
                                Update values of tokens.
                                Add (and resolve) issue 8.

     6    05/14/2013  gsellers  Add BUFFER_STORAGE_SERVER_BIT.
                                Define value of <usage> for buffers allocated
                                with BufferStorage. Issue 9.

     7    05/22/2013  gsellers  Address several issues from bug 10246.

     8    05/23/2013  gsellers  Address issues from bug 10288.
                                * Change BUFFER_STORAGE_SERVER_BIT to
                                  CLIENT_STORAGE_BIT (inverting its
                                  sense), which makes 0 'fast'.
                                * Clarify that DYNAMIC_BIT only affects
                                  BufferSubData (i.e., direct, arbitrary
                                  client->server transfers).
                                * Add issues 11 + 12.

     9    05/28/2013  Jon Leech Fix various typos resulting from changes
                                in token names, tweak language to match API
                                spec, some paragraph reflowing, insert some
                                questions marked by '**' inline.

    10    05/29/2013  gsellers  Remove <target> parameter from
                                NamedBufferStorageEXT.
                                Incorporate new rules for coherency.
                                Add COHERENT_MAP_BIT for MapBufferRange.

    11    05/30/2013  Jon Leech Fix typos including COHERENT_MAP_BIT
                                -> MAP_COHERENT_BIT and PERSISTENT_MAP_BIT
                                -> MAP_PERSISTENT_BIT.

    12    05/30/2013  gsellers  Resolve issues 3 and 10. Fix typos.
                                Resolve issues from bug 10326.
                                Add (and resolve) issue 13.

    13    05/30/2013  gsellers  Change names of flags (again).
                                Use same values for MapBufferRange flags
                                and BufferStorage flags.

    14    05/30/2013  Jon Leech Clean up language describing flags and
                                some indentation issues.

    15    05/31/2013  Jon Leech Add BUFFER_IMMUTABLE_STORAGE to table
                                6.2 (Bug 10288).

    16    06/06/2013  Jon Leech Change default BUFFER_IMMUTABLE_STORAGE
                                value in table 6.2 to FALSE, matching API
                                spec, since these are values when created
                                with BindBuffer. Fix typo from bug 10326.

    17    06/27/2013  Jon Leech Add error for BufferSubData and fix
                                example code (Bug 10326)

    18    07/03/2013  gsellers  Fix language describing DYNAMIC_STORAGE_BIT
                                (mutated -> updated), and typo in description
                                of usage parameter when storage is allocated
                                with BufferStorage. (Bug 10471)

    19    07/18/2013  gsellers  Added missing values for MAP_PERSISTENT_BIT
                                and MAP_COHERENT_BIT.

    20    07/18/2013  Jon Leech Add BufferStorage initial state to table
                                6.3 and add error when zero is bound to
                                <target> (Bug 10335).

    21    07/19/2013  Jon Leech Clean up table 6.3 captions to match
                                API spec (Bug 10335).

    22    08/15/2013  Jon Leech Remove error for BufferStorage and
                                NamedBufferStorageEXT if <flags> contains
                                MAP_WRITE_BIT but does not contain
                                DYNAMIC_STORAGE_BIT (Bug 10561, public Bug
                                925).

    23    08/16/2013  mjk       Better indicate DSA entrypoints

    24    06/09/2014  Jon Leech Change query commands for buffer storage
                                state to GetBufferParameteriv (Bug 12307).

    25    04/20/2015  Jon Leech Change description of MAP_COHERENT_BIT for
                                buffer storage so that barriers with
                                CLIENT_MAPPED_BUFFER_BARRIER_BIT do not need
                                to make CPU writes visible to the GPU in
                                this case without an explicit flush (Bug
                                13578).
