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: April 27th, 2020 Revision: 3.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 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 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); 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 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 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 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 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 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 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 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: " 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), is an offset into the pixel unpack buffer and the pixels are unpacked from the buffer relative to this offset; otherwise, 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 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 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 ) 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: " 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), is an offset into the pixel unpack buffer and the compressed data is read from the buffer relative to this offset; otherwise, 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 ubytes relative to . 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), is an offset into the pixel pack buffer and the pixels are packed into the buffer relative to this offset; otherwise, 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 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 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 , 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: " is ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER, PIXEL_PACK_BUFFER_NV, or PIXEL_UNPACK_BUFFER_NV." Errors INVALID_ENUM is generated if the 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_DRAW); glBindBuffer(GL_PIXEL_PACK_BUFFER_NV, imageBuffers[1]); glBufferData(GL_PIXEL_PACK_BUFFER_NV, imageSize / 2, NULL, GL_STREAM_DRAW); // 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 = glMapBufferRangeEXT(GL_PIXEL_PACK_BUFFER_NV, 0, imageSize/2, GL_MAP_READ_BIT_EXT); processImage(pboMemory1); glBindBuffer(GL_PIXEL_PACK_BUFFER_NV, imageBuffers[1]); pboMemory2 = glMapBufferRangeEXT(GL_PIXEL_PACK_BUFFER_NV, 0, imageSize/2, GL_MAP_READ_BIT_EXT); 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 3 04/27/2020 fix example code: GL_STREAM_READ is not available in ES2.0 glMapBufferOES does not allow reading from the mapped pointer. 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.