Name

    NV_pixel_buffer_object

Name Strings

    GL_NV_pixel_buffer_object

Contributors

    Contributors to ARB_pixel_buffer_object
    Greg Roth, NVIDIA

Contact

    Mathias Heyer, NVIDIA Corporation (mheyer 'at' nvidia.com) 

Status

    Complete.

Version

    Last Modified Date: October 23rd, 2012
    Revision: 2.0

Number

    OpenGL ES Extension #134

Dependencies

    Written based on the wording of the OpenGL ES 2.0 specification.
    
    OES_mapbuffer affects the definition of this specification
    EXT_map_buffer_range affects the definition of this specification 

Overview

    This extension permits buffer objects to be used not only with vertex
    array data, but also with pixel data.  The intent is to provide more
    acceleration opportunities for OpenGL pixel commands.

    While a single buffer object can be bound for both vertex arrays and
    pixel commands, we use the designations vertex buffer object (VBO)
    and pixel buffer object (PBO) to indicate their particular usage in
    a given situation.

    This extension does not add any new functionality to buffer objects
    themselves.  It simply adds two new targets to which buffer objects
    can be bound: GL_PIXEL_PACK_BUFFER_NV and GL_PIXEL_UNPACK_BUFFER_NV.
    When a buffer object is bound to the GL_PIXEL_PACK_BUFFER_NV target,
    commands such as glReadPixels pack (write) their data into a buffer
    object. When a buffer object is bound to the GL_PIXEL_UNPACK_BUFFER_NV
    target, commands such as glTexImage2D unpack (read) their
    data from a buffer object.

    There are a several approaches to improve graphics performance
    with PBOs.  Some of the most interesting approaches are:

    - Streaming texture updates:  If the application uses
      glMapBufferOES/glMapBufferRangeEXT/glUnmapBufferOES to write
      its data for glTexSubImage into a buffer object, at least one of
      the data copies usually required to download a texture can be
      eliminated, significantly increasing texture download performance.

    - Asynchronous glReadPixels:  If an application needs to read back a
      number of images and process them with the CPU, the existing GL
      interface makes it nearly impossible to pipeline this operation.
      The driver will typically send the hardware a readback command
      when glReadPixels is called, and then wait for all of the data to
      be available before returning control to the application.  Then,
      the application can either process the data immediately or call
      glReadPixels again; in neither case will the readback overlap with
      the processing.  If the application issues several readbacks
      into several buffer objects, however, and then maps each one to
      process its data, then the readbacks can proceed in parallel with
      the data processing.

    - Render to vertex array:  The application can use a fragment
      program to render some image into one of its buffers, then read
      this image out into a buffer object via glReadPixels.  Then, it can
      use this buffer object as a source of vertex data.


New Procedures and Functions

    None.


New Tokens

    Accepted by the <target> parameters of BindBuffer, BufferData,
    BufferSubData, MapBufferOES, MapBufferRangeEXT, UnmapBufferOES,
    FlushMappedBufferRangeEXT, GetBufferParameteriv, and
    GetBufferPointervOES:

        PIXEL_PACK_BUFFER_NV                        0x88EB
        PIXEL_UNPACK_BUFFER_NV                      0x88EC

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

        PIXEL_PACK_BUFFER_BINDING_NV                0x88ED
        PIXEL_UNPACK_BUFFER_BINDING_NV              0x88EF


Additions to Chapter 2 of the OpenGL ES 2.0 Specification (OpenGL Operation)

 -- Section 2.9 "Buffer Objects"

    Replace the first two paragraphs with:

    "The vertex data arrays described in section 2.8 are stored in
    client memory.  It is sometimes desirable to store frequently accessed
    client data, such as vertex array and pixel data, in high-performance
    server memory.  GL buffer objects provide a mechanism for clients to
    use to allocate, initialize, and access such memory."

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

       void BindBuffer(enum target, uint buffer);

    <target> must be one of ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER,
    PIXEL_UNPACK_BUFFER_NV, or PIXEL_PACK_BUFFER_NV.  The ARRAY_BUFFER
    target is discussed in section 2.9.1  The ELEMENT_ARRAY_BUFFER target
    is discussed in section 2.9.2.  The PIXEL_UNPACK_BUFFER_NV and
    PIXEL_PACK_BUFFER_NV targets are discussed later in sections 3.7.1 and
    4.3.  If the buffer object named <buffer> has not been
    previously bound or has been deleted since the last binding, the
    GL creates a new state vector, initialized with a zero-sized memory
    buffer and comprising the state values listed in table 2.5."

    Replace the 5th paragraph with:

    "Initially, each buffer object target is bound to zero.  There is
    no buffer object corresponding to the name zero so client attempts
    to modify or query buffer object state for a target bound to zero
    generate an INVALID_OPERATION error."

    Replace the phrase listing the valid targets for BufferData in the
    9th paragraph with:

    "with <target> set to one of ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER,
    PIXEL_UNPACK_BUFFER_NV, or PIXEL_PACK_BUFFER_NV,"

    In the 10th paragraph describing buffer object usage modes, replace
    the phrase "specified once" with "specified once per repetition of
    the usage pattern" for the STREAM_* and STATIC_* usage values.

    Also in the 10th paragraph describing buffer object usage modes,
    replace the phrases "of a GL drawing command." and "for GL drawing
    commands." with "for GL drawing and image specification commands." for
    the *_DRAW usage values.

    Replace the phrase listing the valid targets for BufferSubData with:

    "with <target> set to one of ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER,
    PIXEL_UNPACK_BUFFER_NV, or PIXEL_PACK_BUFFER_NV."

    Replace the phrase listing the valid targets for MapBufferOES with:

    "with <target> set to one of ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER,
    PIXEL_UNPACK_BUFFER_NV, or PIXEL_PACK_BUFFER_NV."

    Replace the phrase listing the valid targets for UnmapBufferOES with:

    "with <target> set to one of ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER,
    PIXEL_UNPACK_BUFFER_NV, or PIXEL_PACK_BUFFER_NV."

    Replace the phrase listing the valid targets for MapBufferRangeEXT
    with:

    "with <target> set to one of ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER,
    PIXEL_UNPACK_BUFFER_NV, or PIXEL_PACK_BUFFER_NV."

    Replace the phrase listing the valid targets for
    FlushMappedBufferRangeEXT with:

    "with <target> set to one of ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER,
    PIXEL_UNPACK_BUFFER_NV, or PIXEL_PACK_BUFFER_NV."

 -- Section 2.9.2 "Array Indices in Buffer Objects"

    Delete the 3rd paragraph that explains how the ELEMENT_ARRAY_BUFFER
    target is acceptable for the commands specified in section 2.9.
    The updated section 2.9 language already says this.

Additions to Chapter 3 of the OpenGL ES 2.0 Specification (Rasterization)

 -- Section 3.6 "Pixel Rectangles"

    Replace the last two paragraphs with:

    "This section describes only how these rectangles are defined in
     buffer object and client memory, and the steps involved in
     transferring pixel rectangles from buffer object or client memory
     to the GL or vice-versa.
     Parameters controlling the encoding of pixels in buffer object or
     client memory (for reading and writing) are set with the command
     PixelStorei."

 -- Rename Section 3.6.1 "Pixel Storage Modes and Pixel Buffer Objects"

    Add to the end of the section:

    "In addition to storing pixel data in client memory, pixel data
    may also be stored in buffer objects (described in section 2.9).
    The current pixel unpack and pack buffer objects are designated
    by the PIXEL_UNPACK_BUFFER_NV and PIXEL_PACK_BUFFER_NV targets
    respectively.

    Initially, zero is bound for the PIXEL_UNPACK_BUFFER_NV, indicating
    that image specification commands such as TexImage*D source their
    pixels from client memory pointer parameters.  However, if a non-zero
    buffer object is bound as the current pixel unpack buffer, then
    the pointer parameter is treated as an offset into the designated
    buffer object."


 -- Section 3.6.2 "Transfer of Pixel Rectangles", page 61.

    Change the 1st sentence of the 1st paragraph to read:

    "The process of transferring pixels encoded in buffer object
     or client memory is diagrammed in figure 3.5."

    Change the 4th sentence of the 2nd paragraph to read:

    "<data> refers to the data to be transferred."

    [data is no longer necessarily a pointer.]

    Change the initial phrase in the 1st sentence of the 1st paragraph
    in subsection "Unpacking" to read:

    "Data are taken from the currently bound pixel unpack buffer or
    client memory as a sequence of..."

    Insert this paragraph after the 1st paragraph in subsection 
    "Unpacking":

    "If a pixel unpack buffer is bound (as indicated by a non-zero
    value of PIXEL_UNPACK_BUFFER_BINDING_NV), <data> is an offset
    into the pixel unpack buffer and the pixels are unpacked from the
    buffer relative to this offset; otherwise, <data> is a pointer to
    a block client memory and the pixels are unpacked from the client
    memory relative to the pointer.  If a pixel unpack buffer object
    is bound and unpacking the pixel data according to the process
    described below would access memory beyond the size of the pixel
    unpack buffer's memory size, INVALID_OPERATION results.  If a pixel
    unpack buffer object is bound and <data> is not evenly divisible
    into the number of basic machine units needed to store in memory the
    corresponding GL data type from table 3.4 for the <type> parameter,
    INVALID_OPERATION results."

 -- Section 3.7.1 "Texture Image Specification", page 66.

    Replace the last phrase in the 2nd to last sentence in the 1st
    paragraph with:

    "and a reference to the image data in the currently bound pixel unpack
    buffer or client memory, as described in section 3.6.2."

    Replace the 1st sentence in the 9th paragraph with:

    "The image itself (referred to by <data>) is a sequence of groups
    of values."

    Replace the last paragraph with:

    "If the data argument of TexImage2D is a NULL pointer, and the
     pixel unpack buffer object is zero, a two- or three-dimensional
     texel array is created with the specified target, level, internalformat,
     border, width, height, and depth, but with unspecified image contents.
     In this case no pixel values are accessed in client memory, and no pixel
     processing is performed. Errors are generated, however, exactly as though
     the data pointer were valid. Otherwise if the pixel unpack buffer object
     is non-zero, the data argument is treatedly normally to refer to the
     beginning of the pixel unpack buffer object's data."

 -- Section 3.7.3 "Compressed Texture Images", page 73.

    Replace the 3rd sentence of the 2nd paragraph with:

    "<data> refers to compressed image data stored in the compressed
    image format corresponding to internalformat.  If a pixel
    unpack buffer is bound (as indicated by a non-zero value of
    PIXEL_UNPACK_BUFFER_BINDING_NV), <data> is an offset into the
    pixel unpack buffer and the compressed data is read from the buffer
    relative to this offset; otherwise, <data> is a pointer to a block
    client memory and the compressed data is read from the client memory
    relative to the pointer."
    
    Replace the 2nd sentence in the 3rd paragraph with:

    "Compressed texture images are treated as an array of <imageSize>
    ubytes relative to <data>.  If a pixel unpack buffer object is bound
    and data+imageSize is greater than the size of the pixel buffer,
    INVALID_OPERATION results."

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

 -- Section 4.3 "Reading Pixels", page 104.

    Replace the first paragraph with:
    
    "Pixels may be read from the framebuffer to pixel pack buffer or 
     client memory using the ReadPixels commands, as described below.
     Pixels may also be copied from pixel unpack buffer, client memory or
     the framebuffer to texture images in the GL using the TexImage2D and
     CopyTexImage2D commands, as described in section 3.7.1.

 -- Section 4.3.1 "Reading Pixels", page 104.

    Replace 1st sentence of the 1st paragraph with:

    "The method for reading pixels from the framebuffer and placing them in
    pixel pack buffer or client memory is diagrammed in figure 4.2."

    Add this paragraph after the 1st paragraph:

    "Initially, zero is bound for the PIXEL_PACK_BUFFER_NV, indicating
    that image read and query commands such as ReadPixels return
    pixels results into client memory pointer parameters.  However, if
    a non-zero buffer object is bound as the current pixel pack buffer,
    then the pointer parameter is treated as an offset into the designated
    buffer object."

    Rename "Placement in Client Memory" to "Placement in Pixel Pack
    Buffer or Client Memory".

    Insert this paragraph at the start of the newly renamed
    subsection "Placement in Pixel Pack Buffer or Client Memory":

    "If a pixel pack buffer is bound (as indicated by a non-zero value
    of PIXEL_PACK_BUFFER_BINDING_NV), <data> is an offset into the
    pixel pack buffer and the pixels are packed into the
    buffer relative to this offset; otherwise, <data> is a pointer to a
    block client memory and the pixels are packed into the client memory
    relative to the pointer.  If a pixel pack buffer object is bound and
    packing the pixel data according to the pixel pack storage state
    would access memory beyond the size of the pixel pack buffer's
    memory size, INVALID_OPERATION results.  If a pixel pack buffer object
    is bound and <data> is not evenly divisible into the number of basic
    machine units needed to store in memory the corresponding GL data type
    from table 3.5 for the <type> parameter, INVALID_OPERATION results."


Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special Functions)

    None


Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and State
Requests)

--- Section 6.1.3 Enumerated Queries

    Change the 1st sentence of the 3rd paragraph to read:
    "The command
        void GetBufferParameteriv( enum target, enum value, T data );
    returns information about <target>, which may be one of ARRAY_BUFFER,
    ELEMENT_ARRAY_BUFFER, PIXEL_PACK_BUFFER_NV, PIXEL_UNPACK_BUFFER_NV
    indicating the currently bound vertex array, element array, pixel pack
    and pixel unpack buffer object."

 -- Section 6.1.13 "Buffer Object Queries".

    (description of glGetBufferPointervOES)  
    Change the 2nd sentence of the 2nd paragraph to read:
    "<target> is ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER, PIXEL_PACK_BUFFER_NV,
    or PIXEL_UNPACK_BUFFER_NV."


Errors

    INVALID_ENUM is generated if the <target> parameter of
    BindBuffer, BufferData, BufferSubData, MapBufferOES, UnmapBufferOES,
    GetBufferParameteriv or GetBufferPointervOES is not
    one of ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER, PIXEL_PACK_BUFFER_NV,
    or PIXEL_UNPACK_BUFFER_NV.

    INVALID_OPERATION is generated if CompressedTexImage2D, 
    CompressedTexSubImage2D, TexImage2D or TexSubImage2D would unpack
    (read) data from the currently bound PIXEL_UNPACK_BUFFER_NV buffer
    object such that the memory reads required for the command would exceed
    the memory (data store) size of the buffer object.

    INVALID_OPERATION is generated if ReadPixels or ReadnPixelsEXT 
    would pack (write) data to the currently bound PIXEL_PACK_BUFFER_NV
    buffer object such that the memory writes required for the command would
    exceed the memory (data store) size of the buffer object.

    INVALID_OPERATION is generated by ReadPixels or ReadnPixelsEXT
    if the current PIXEL_PACK_BUFFER_BINDING_NV value is non-zero and the
    table/image/values/span/img/data parameter is not evenly divisible
    into the number of basic machine units needed to store in memory a
    datum indicated by the type parameter.

    INVALID_OPERATION is generated by TexImage2D or TexSubImage2D
    if current PIXEL_UNPACK_BUFFER_BINDING_NV value is non-zero and the data
    parameter is not evenly divisible into the number of basic machine
    units needed to store in memory a datum indicated by the type
    parameter.

Dependencies on OES_mapbuffer
    
    If OES_mapbuffer is not present, references to MapBufferOES and
    UnmapBufferOES should be ignored and language referring to mapped
    buffer objects should be removed.

Dependencies on EXT_map_buffer_range
    
    If EXT_map_buffer_range is not present, references to
    MapBufferRangeEXT anf FlushMappedBufferRangeEXT should be ignored.
    
New State

(table 6.13, Pixels, p. 147)

                                                         Initial
    Get Value                        Type   Get Command  Value    Sec    
    -------------------------------  ----   -----------  -------  ------ 
    PIXEL_PACK_BUFFER_BINDING_NV    Z+     GetIntegerv  0        4.3.1  
    PIXEL_UNPACK_BUFFER_BINDING_NV  Z+     GetIntegerv  0        3.6.1  



Usage Examples

    Convenient macro definition for specifying buffer offsets:

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

    Example 1: Render to vertex array:

        const int numberVertices = 100;

        // Create a buffer object for a number of vertices consisting of
        // 4 float values per vertex
        glGenBuffers(1, vertexBuffer);
        glBindBuffer(GL_PIXEL_PACK_BUFFER_NV, vertexBuffer);
        glBufferData(GL_PIXEL_PACK_BUFFER_NV, numberVertices*4,
                     NULL, GL_DYNAMIC_DRAW);

        // Render vertex data into 100x1 strip of framebuffer using a
        // shader program
        glUseProgram(program);
        renderVertexData();
        glBindProgramARB(FRAGMENT_PROGRAM_ARB, 0);

        // Read the vertex data back from framebuffer
        glReadPixels(0, 0, numberVertices, 1, GL_BGRA, GL_UNSIGNED_BYTE,
                     BUFFER_OFFSET(0));

        // Change the binding point of the buffer object to
        // the vertex array binding point
        glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);

        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, BUFFER_OFFSET(0));
        glDrawArrays(TRIANGLE_STRIP, 0, numberVertices);


    Example 2: Streaming textures

    Streaming textures using pixel buffer objects:

        const int texWidth = 256;
        const int texHeight = 256;
        const int texsize = texWidth * texHeight * 4;
        void *pboMemory, *texData;

        // Define texture level zero (without an image); notice the
        // explicit bind to the zero pixel unpack buffer object so that
        // pass NULL for the image data leaves the texture image
        // unspecified.
        glBindBuffer(GL_PIXEL_UNPACK_BUFFER_NV, 0);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0,
                     GL_RGBA, GL_UNSIGNED_BYTE, NULL);

        // Create and bind texture image buffer object
        glGenBuffers(1, &texBuffer);
        glBindBuffer(GL_PIXEL_UNPACK_BUFFER_NV, texBuffer);

        // Setup texture environment
        ...

        texData = getNextImage();

        while (texData) {

            // Reset the contents of the texSize-sized buffer object
            glBufferData(GL_PIXEL_UNPACK_BUFFER_NV, texSize, NULL,
                         GL_STREAM_DRAW);

            // Map the texture image buffer (the contents of which
            // are undefined due to the previous glBufferData)
            pboMemory = glMapBufferOES(GL_PIXEL_UNPACK_BUFFER_NV,
                                    GL_WRITE_ONLY);

            // Modify (sub-)buffer data
            memcpy(pboMemory, texData, texsize);

            // Unmap the texture image buffer
            glUnmapBufferOES(GL_PIXEL_UNPACK_BUFFER_NV);

            // Update (sub-)teximage from texture image buffer
            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texWidth, texHeight,
                            GL_RGBA, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));

            // Draw textured geometry
            ...

            texData = getNextImage();
        }

        glBindBuffer(GL_PIXEL_UNPACK_BUFFER_NV, 0);


    Example 3: Asynchronous glReadPixels

    Traditional glReadPixels:

        const int imagewidth = 640;
        const int imageheight = 480;
        GLubyte readBuffer[imagewidth*imageheight*4];

        // Render to framebuffer
        renderScene()

        // Read image from framebuffer
        glReadPixels(0, 0, imagewidth, imageheight, GL_RGBA,
                     GL_UNSIGNED_BYTE, readBuffer);

        // Process image when glReadPixels returns after reading the
        // whole buffer
        processImage(readBuffer);


    Asynchronous glReadPixels:

        const int imagewidth = 640;
        const int imageheight = 480;
        const int imageSize = imagewidth*imageheight*4;

        glGenBuffers(2, imageBuffers);

        glBindBuffer(GL_PIXEL_PACK_BUFFER_NV, imageBuffers[0]);
        glBufferData(GL_PIXEL_PACK_BUFFER_NV, imageSize / 2, NULL,
                     GL_STREAM_READ);

        glBindBuffer(GL_PIXEL_PACK_BUFFER_NV, imageBuffers[1]);
        glBufferData(GL_PIXEL_PACK_BUFFER_NV, imageSize / 2, NULL,
                     GL_STREAM_READ);

        // Render to framebuffer
        glDrawBuffer(GL_BACK);
        renderScene();

        // Bind two different buffer objects and start the glReadPixels
        // asynchronously. Each call will return directly after
        // starting the DMA transfer.
        glBindBuffer(GL_PIXEL_PACK_BUFFER_NV, imageBuffers[0]);
        glReadPixels(0, 0, imagewidth, imageheight/2, GL_RGBA,
                     GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));

        glBindBuffer(GL_PIXEL_PACK_BUFFER_NV, imageBuffers[1]);
        glReadPixels(0, imageheight/2, imagewidth, imageheight/2, GL_RGBA,
                     GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));

        // Process partial images.  Mapping the buffer waits for
        // outstanding DMA transfers into the buffer to finish.
        glBindBuffer(GL_PIXEL_PACK_BUFFER_NV, imageBuffers[0]);
        pboMemory1 = glMapBuffer(GL_PIXEL_PACK_BUFFER_NV,
                                 GL_READ_ONLY);
        processImage(pboMemory1);
        glBindBuffer(GL_PIXEL_PACK_BUFFER_NV, imageBuffers[1]);
        pboMemory2 = glMapBuffer(GL_PIXEL_PACK_BUFFER_NV,
                                 GL_READ_ONLY);
        processImage(pboMemory2);

        // Unmap the image buffers
        glBindBuffer(GL_PIXEL_PACK_BUFFER_NV, imageBuffers[0]);
        glUnmapBuffer(GL_PIXEL_PACK_BUFFER_NV);
        glBindBuffer(GL_PIXEL_PACK_BUFFER_NV, imageBuffers[1]);
        glUnmapBuffer(GL_PIXEL_PACK_BUFFER_NV);


Issues


    1)  Can a given buffer be used for both vertex and pixel data?

        RESOLVED: YES.  All buffers can be used with all buffer bindings,
        in whatever combinations the application finds useful.  Consider
        yourself warned, however, by the following issue.

    2)  May implementations make use of the target as a hint to select
        an appropriate memory space for the buffer?

        RESOLVED: YES, as long as such behavior is transparent to the
        application. Some implementations may choose different memory 
        spaces for different targets.
        In fact, one can imagine arbitrarily complicated heuristics for
        selecting the memory space, based on factors such as the target,
        the "usage" argument, and the application's observed behavior.

        While it is entirely legal to create a buffer object by binding
        it to GL_ARRAY_BUFFER and loading it with data, then using it
        with the GL_PIXEL_UNPACK_BUFFER_NV or GL_PIXEL_PACK_BUFFER_NV
        binding, such behavior is liable to confuse the driver and may
        hurt performance.  If the driver implemented the hypothetical
        heuristic described earlier, such a buffer might have already
        been located in AGP memory, and so the driver would have to choose
        between two bad options: relocate the buffer into video memory, or
        accept lower performance caused by streaming pixel data from AGP.

    3)  Should the INVALID_OPERATION error be generated if a pixel
        command would access data outside the range of the bound PBO?

        RESOLVED:  YES.  This requires considering the command parameters
        (such as width/height/depth/format/type/pointer), the current
        pixel store (pack/unpack) state, and the command operation itself
        to determine the maximum addressed byte for the pixel command.

        This behavior should increase the reliability of using PBO and
        guard against programmer mistakes.

        This is particularly important for glReadPixels where returning
        data into a region outside the PBO could cause corruption of
        application memory.

        Such bounds checking is substantially more expensive for VBO
        accesses because bounds checking on a per-vertex element basis
        for each of multiple enabled vertex arrays prior to performing
        the command compromises the performance justification of VBO.

     4) If a pixel command with a bound PBO accesses data outside the
        range of the PBO, thereby generating a GL_INVALID_OPERATION error,
        can the pixel command end up being partially processed?

        RESOLVED:  NO.  As for all GL errors excepting GL_OUT_OF_MEMORY
        situations, "the command generating the error is ignored so that
        it has no effect on GL state or framebuffer contents."

        This means implementations must determine before the pixel command
        is performed whether the resulting read or write operations on
        the bound PBO will exceed the size of the PBO.

        This means an implementation is NOT allowed to detect out of
        bounds accesses in the middle of performing the command.
  
     5) Should an INVALID_OPERATION error be generated if the offset
        within a pixel buffer to a datum comprising of N basic machine
        units is not a multiple of N?

        RESOLVED:  YES.  This was stated for VBOs but no error was
        defined if the rule was violated.  Perhaps this needs to be
        better specified for VBO.

        For PBO, it is reasonable and cheap to enforce the alignment rule.
        For pixel commands it means making sure the offset is evenly
        divisible by the component or group size in basic machine units.

        This check is independent of the pixel store state because the
        pixel store state is specified in terms of pixels (not basic
        machine units) so pixel store addressing cannot create an
        unaligned access as long as the base offset is aligned.

        Certain commands (specifically,
        glCompressedTexImage2D, glCompressedTexSubImage2D) are not
        affected by this error because the data accessed is addressed
        at the granularity of basic machine units.

     6) Various commands do not make explicit reference to supporting
        packing or unpacking from a pixel buffer object but rather specify
        that parameters are handled in the same manner as glReadPixels,
        or the glCompressedTexImage commands.  So do such
        commands (example: glCompressedTexSubImage2D) use pixel buffers?

        RESOLVED:  YES.  Commands that have their behavior defined based
        on commands that read or write from pixel buffers will themselves
        read or write from pixel buffers.  Relying on this reduces the
        amount of specification language to be updated.

     7) What is the complete list of commands that can unpack (read)
        pixels from the current pixel unpack buffer object?

            glCompressedTexImage2D
            glCompressedTexSubImage2D
            glTexImage2D
            glTexSubImage2D

     8) What is the complete list of commands that can pack (write)
        pixels into the current pixel pack buffer object?

            glReadPixels

     9) Prior to this extension, passing zero for the data argument of
        glTexImage2D defined a texture image level without supplying an image.
        How does this behavior change with this extension?

        RESOLVED:  The "unspecified image" behavior of the glTexImage
        calls only applies when bound to a zero pixel unpack buffer
        object.

        When bound to a non-zero pixel unpack buffer object, the data
        argument to these calls is treated as an offset rather than
        a pointer so zero is a reasonable and even likely value that
        corresponds to the very beginning of the buffer object's data.

        So to create a texture image level with unspecified image data,
        you MUST bind to the zero pixel unpack buffer object.

        See the ammended language at the end of section 3.7.1.

    10) How does this extension support video frame grabbers?

        RESOLVED:  This extension extends buffer objects so they can
        operate with pixel commands, rather than just vertex array
        commands.

        We anticipate that a future extension may provide a mechanism
        for transferring video frames from video frame grabber hardware
        or vertices from motion capture hardware (or any other source
        of aquired real-time data) directly into a buffer object to
        eliminate a copy.  Ideally, such transfers would be possible
        without requiring mapping of the buffer object.  But this
        extension does not provide such functionality.

        We anticipate such functionality to involve binding a buffer
        object to a new target type, configuring a source (or sink) for
        data (video frames, motion capture vertex sets, etc.), and then
        commands to initiate data transfers to the bound buffer object.
        
    11) Is this the "right" way to expose render-to-vertex-array?

        DISCUSSION:  You can use this extension to render an image
        into a framebuffer, copy the pixels into a buffer object with
        glReadPixels, and then configure vertex arrays to source the pixel
        data as vertex attributes.  This necessarily involves a copy
        from the framebuffer to the buffer object.  Future extensions
        may provide mechanisms for copy-free render-to-vertex-array
        capabilities but that is not a design goal of this extension.
        
Revision History

    2   10/23/2012 more cleanup, interaction with EXT_map_buffer_range
    1   04/19/2012 initial revision
        - took ARB_pixel_buffer_object, stripped everything not applicable to 
          ES, changed references to tables and sections; changed all wording
          to fit ES' language.

