| Name |
| |
| EXT_pixel_buffer_object |
| |
| Name Strings |
| |
| GL_EXT_pixel_buffer_object |
| |
| Status |
| |
| Implemented by NVIDIA drivers (Release 55). |
| |
| Contributors |
| |
| Ralf Biermann |
| Derek Cornish |
| Matt Craighead |
| Bill Licea-Kane |
| Brian Paul |
| |
| Contact |
| |
| Ralf Biermann, NVIDIA Corporation (rbiermann 'at' nvidia.com) |
| Derek Cornish, NVIDIA Corporation (dcornish 'at' nvidia.com) |
| |
| IP Status |
| |
| Unknown. |
| |
| Version |
| |
| NVIDIA Date: March 29, 2004 (version 1.0) |
| |
| Number |
| |
| 302 |
| |
| Status |
| |
| NVIDIA Release 55 (early 2004) drivers support this extension. |
| |
| Dependencies |
| |
| Written based on the wording of the OpenGL 1.5 specification. |
| |
| GL_NV_pixel_data_range affects the definition of this extension. |
| |
| Overview |
| |
| This extension expands on the interface provided by buffer objects. |
| It is intended to permit buffer objects to be used not only with |
| vertex array data, but also with pixel data. |
| Buffer objects were promoted from the ARB_vertex_buffer_object |
| extension in OpenGL 1.5. |
| |
| Recall that buffer objects conceptually are nothing more than arrays |
| of bytes, just like any chunk of memory. Buffer objects allow GL |
| commands to source data from a buffer object by binding the buffer |
| object to a given target and then overloading a certain set of GL |
| commands' pointer arguments to refer to offsets inside the buffer, |
| rather than pointers to user memory. An offset is encoded in a |
| pointer by adding the offset to a null pointer. |
| |
| 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: PIXEL_PACK_BUFFER and PIXEL_UNPACK_BUFFER. |
| When a buffer object is bound to the PIXEL_PACK_BUFFER target, |
| commands such as ReadPixels write their data into a buffer object. |
| When a buffer object is bound to the PIXEL_UNPACK_BUFFER target, |
| commands such as DrawPixels read their data from a buffer object. |
| |
| There are a wide variety of applications for such functionality. |
| Some of the most interesting ones are: |
| |
| - "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 ReadPixels. Then, it can |
| use this buffer object as a source of vertex data. |
| |
| - Streaming textures. If the application uses MapBuffer/UnmapBuffer |
| to write its data for TexSubImage 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 ReadPixels. 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 ReadPixels 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 |
| ReadPixels 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. |
| |
| Issues |
| |
| How does this extension relate to ARB_vertex_buffer_object? |
| |
| It builds on the ARB_vertex_buffer_object framework by adding |
| two new targets that buffers can be bound to. |
| |
| How does this extension relate to NV_pixel_data_range? |
| |
| This extension relates to NV_pixel_data_range in the same way that |
| ARB_vertex_buffer_object relates to NV_vertex_array_range. To |
| paraphrase the ARB_vertex_buffer_object spec, here are the main |
| differences: |
| |
| - Applications are no longer responsible for memory management |
| and synchronization. |
| |
| - Applications may still access high-performance memory directly, |
| but this is optional, and such access is more restricted. |
| |
| - Buffer changes (BindBuffer) are generally expected to |
| be very lightweight, rather than extremely heavyweight |
| (PixelDataRangeNV). |
| |
| - A platform-specific allocator such as wgl/glXAllocateMemoryNV |
| is no longer required. |
| |
| 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. |
| |
| 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, for example, |
| that they would rather stream vertex data from write-combined |
| system memory, element (or index) data from video memory, and |
| pixel data from video memory. |
| |
| 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 ARRAY_BUFFER and loading it with data, then using it with |
| the PIXEL_UNPACK_BUFFER_EXT or PIXEL_PACK_BUFFER_EXT 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 |
| write-combined system 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 slower system memory. |
| |
| Should all pixel path commands be supported, or just a subset of |
| them? |
| |
| RESOLVED: ALL. While there is little reason to believe that, |
| say, ConvolutionFilter2D would benefit from this extension, there |
| is no reason _not_ to support it. The full list of commands |
| affected by this extension is listed in the spec. |
| |
| Should PixelMap and GetPixelMap be supported? |
| |
| RESOLVED: YES. They're not really pixel path operations, but, |
| again, there is no good reason to omit operations, and they _are_ |
| operations that pass around big chunks of pixel-related data. |
| If we support PolygonStipple, surely we should support this. |
| |
| How does the buffer binding state push/pop? |
| |
| RESOLVED: As part of the pixel store client state. This is |
| analogous to how the vertex buffer object bindings pushed/popped |
| as part of the vertex array client state. |
| |
| Should NV_pixel_data_range (PDR) be used concurrently with pixel |
| buffer objects ? |
| |
| RESOLVED: NO. While it would be possible to allocate a memory |
| range for PDR, using a pointer into this memory range with one |
| of the commands affected by EXT_pixel_buffer_object will not |
| work if a pixel buffer object other than zero is bound to the |
| buffer binding point affecting the command. Pixel buffer objects |
| always have higher precedence than PDR. |
| |
| Do the null pointer rules for glTexImage1D, glTexImage2D |
| and glTexImage3D for allocating textures with undefined |
| content also apply when a non-zero buffer object is bound to |
| PIXEL_UNPACK_BUFFER_BINDING_EXT ? |
| |
| RESOLVED: NO. The null pointer is interpreted as a non-zero |
| pointer to the data storage whose contents may be still |
| undefined. This data will be used to create the texture array. |
| If the null pointer rule is required, no non-zero buffer object |
| should be bound to PIXEL_UNPACK_BUFFER_BINDING_EXT. |
| |
| New Procedures and Functions |
| |
| None. |
| |
| New Tokens |
| |
| Accepted by the <target> parameters of BindBuffer, BufferData, |
| BufferSubData, MapBuffer, UnmapBuffer, GetBufferSubData, |
| GetBufferParameteriv, and GetBufferPointerv: |
| |
| PIXEL_PACK_BUFFER_EXT 0x88EB |
| PIXEL_UNPACK_BUFFER_EXT 0x88EC |
| |
| Accepted by the <pname> parameter of GetBooleanv, GetIntegerv, |
| GetFloatv, and GetDoublev: |
| |
| PIXEL_PACK_BUFFER_BINDING_EXT 0x88ED |
| PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF |
| |
| |
| Additions to Chapter 2 of the GL Specification (OpenGL Operation) |
| |
| None |
| |
| Additions to Chapter 3 of the 1.2.1 Specification (Rasterization) |
| |
| Additions to subsection 3.8.1 of the 1.2.1 Specification (Texture |
| Image Specification) |
| |
| The extension EXT_pixel_buffer_object makes an exception to this |
| rule of passing a null pointer to glTexImage1D, glTexImage2D and |
| glTexImage3D. If PIXEL_UNPACK_BUFFER_BINDING_EXT is non-zero |
| and a null pointer is passed to these functions, the texture |
| array is created and the image contents are sourced from the |
| data store of the bound buffer object. |
| |
| Additions to Chapter 4 of the 1.2.1 Specification (Per-Fragment |
| Operations and the Frame Buffer) |
| |
| Added a subsection 4.3.5 (Pixel Buffer Object unpack operation) |
| in section 4.3 (Drawing, Reading and copying Pixels) |
| |
| The extension EXT_pixel_buffer_object affects the operation of |
| several OpenGL commands described in section 3.6 (Pixel Rectangles), |
| section 3.7 (Bitmaps), and section 3.8 (Texturing). |
| |
| In unextended OpenGL 1.3 with ARB_imaging support, the commands |
| glBitmap, glColorSubTable, glColorTable, glCompressedTexImage1D, |
| glCompressedTexImage2D, glCompressedTexImage3D, |
| glCompressedTexSubImage1D, glCompressedTexSubImage2D, |
| glCompressedTexSubImage3D, glConvolutionFilter1D, |
| glConvolutionFilter2D, glDrawPixels, glPixelMapfv, glPixelMapuiv, |
| glPixelMapusv, glPolygonStipple, glSeparableFilter2D, glTexImage1D, |
| glTexImage2D, glTexImage3D, glTexSubImage1D, glTexSubImage2D |
| and glTexSubImage3D operate as previously defined, except |
| that pixel data is sourced from a buffer object's data store if |
| PIXEL_UNPACK_BUFFER_BINDING_EXT is non-zero. When the data is sourced |
| from a buffer object, the pointer value passed in as an argument to |
| the command 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. |
| |
| Additions to Chapter 5 of the 1.2.1 Specification (Special Functions) |
| |
| None |
| |
| Additions to Chapter 6 of the 1.2.1 Specification (State and State |
| Requests) |
| |
| Additions to subsection 6.1.13 (Buffer Object Queries) in chapter 6 |
| |
| In unextended OpenGL 1.5 with ARB_imaging support, the commands |
| glGetColorTable, glGetCompressedTexImage, glGetConvolutionFilter, |
| glGetHistogram, glGetMinmax, glGetPixelMapfv, glGetPixelMapuiv, |
| glGetPixelMapusv, glGetPolygonStipple, glGetSeparableFilter, |
| glGetTexImage and glReadPixels operate as previously defined, |
| except that pixel data is stored in a buffer object's data store if |
| PIXEL_PACK_BUFFER_BINDING_EXT is non-zero. When a buffer object is |
| the target of the pixel data, the target pointer value passed in as |
| an argument to the command 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. |
| |
| Errors |
| |
| None |
| |
| New State |
| |
| (table 6.20, Pixels, p. 235) |
| |
| Get Value Type Get Command Initial Value Sec Attribute |
| --------- ---- ----------- ------------- --- --------- |
| PIXEL_PACK_BUFFER_BINDING_EXT Z+ GetIntegerv 0 4.3.5 pixel-store |
| PIXEL_UNPACK_BUFFER_BINDING_EXT Z+ GetIntegerv 0 6.1.13 pixel-store |
| |
| New Implementation Dependent State |
| |
| (none) |
| |
| |
| Usage Examples |
| |
| Convenient macro definition for specifying buffer offsets: |
| |
| #define BUFFER_OFFSET(i) ((char *)NULL + (i)) |
| |
| Example 1: Render to vertex array |
| |
| // create a buffer object for a number of vertices consisting of |
| // 4 float values per vertex |
| GenBuffers(1, vertexBuffer); |
| BindBuffer(PIXEL_PACK_BUFFER_EXT, vertexBuffer); |
| BufferData(PIXEL_PACK_BUFFER_EXT, numberVertices*4, NULL, DYNAMIC_DRAW); |
| |
| // render vertex data into framebuffer using a fragment program |
| BindProgramARB(FRAGMENT_PROGRAM_ARB, fragmentProgram); |
| DrawBuffer(GL_BACK); |
| renderVertexData(); |
| BindProgramARB(FRAGMENT_PROGRAM_ARB, 0); |
| |
| // read the vertex data back from framebuffer |
| ReadBuffer(GL_BACK); |
| ReadPixels(0, 0, numberVertices*4, height/2, |
| GL_BGRA, GL_FLOAT, BUFFER_OFFSET(0)); |
| |
| // change the binding point of the buffer object to |
| // the vertex array binding point |
| BindBuffer(GL_ARRAY_BUFFER, vertexBuffer); |
| |
| EnableClientState(VERTEX_ARRAY); |
| VertexPointer(4, FLOAT, 0, BUFFER_OFFSET(0)); |
| DrawArrays(TRIANGLE_STRIP, 0, numberVertices); |
| |
| Example 2: Streaming textures |
| |
| streaming textures using NV_pixel_data_range |
| |
| void *pdrMemory, *texData; |
| |
| pdrMemory = AllocateMemoryNV(texsize, 0.0, 1.0, 1.0); |
| |
| PixelDataRangeNV(GL_WRITE_PIXEL_DATA_RANGE_NV, texsize, pdrMemory); |
| |
| EnableClientState(GL_WRITE_PIXEL_DATA_RANGE_NV); |
| |
| // setup texture environment |
| ... |
| |
| texData = getNextImage(); |
| |
| while (texData) { |
| |
| memcpy(pdrMemory, texData, texsize); |
| |
| FlushPixelDataRangeNV(GL_WRITE_PIXEL_DATA_RANGE_NV); |
| |
| TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, |
| texWidth, texHeight, GL_BGRA, GL_UNSIGNED_BYTE, pdrMemory); |
| |
| // draw textured geometry |
| Begin(GL_QUADS); |
| ... |
| End(); |
| |
| texData = getNextImage(); |
| } |
| |
| DisableClientState(GL_WRITE_PIXEL_DATA_RANGE_NV); |
| |
| FreeMemoryNV(pdrMemory); |
| |
| streaming textures using EXT_pixel_buffer_object: |
| |
| void *pboMemory, *texData; |
| |
| // create and bind texture image buffer object |
| GenBuffers(1, &texBuffer); |
| BindBuffer(PIXEL_UNPACK_BUFFER_EXT, texBuffer); |
| BufferData(PIXEL_UNPACK_BUFFER_EXT, texSize, NULL, STREAM_DRAW); |
| |
| texData = getNextImage(); |
| |
| while (texData) { |
| |
| // map the texture image buffer |
| pboMemory = MapBuffer(PIXEL_UNPACK_BUFFER_EXT, WRITE_ONLY); |
| |
| // modify (sub-)buffer data |
| memcpy(pboMemory, texData, texsize); |
| |
| // unmap the texture image buffer |
| if (!UnmapBuffer(PIXEL_UNPACK_BUFFER_EXT)) { |
| // Handle error case |
| } |
| |
| // update (sub-)teximage from texture image buffer |
| TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texWidth, texHeight, |
| GL_BGRA, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)); |
| |
| // draw textured geometry |
| Begin(GL_QUADS); |
| ... |
| End(); |
| |
| texData = getNextImage(); |
| } |
| |
| BindBuffer(PIXEL_UNPACK_BUFFER_EXT, 0); |
| |
| Example 3: Asynchronous ReadPixels |
| |
| traditional ReadPixels |
| |
| unsigned int readBuffer[imagewidth*imageheight*4]; |
| |
| // render to framebuffer |
| DrawBuffer(GL_BACK); |
| renderScene() |
| |
| // read image from framebuffer |
| ReadBuffer(GL_BACK); |
| ReadPixels(); |
| |
| // process image when ReadPixels returns after reading the whole buffer |
| processImage(readBuffer); |
| |
| asynchronous ReadPixels |
| |
| GenBuffers(2, imageBuffers); |
| |
| BindBuffer(PIXEL_PACK_BUFFER_EXT, imageBuffers[0]); |
| BufferData(PIXEL_PACK_BUFFER_EXT, imageSize / 2, NULL, STATIC_READ); |
| |
| BindBuffer(PIXEL_PACK_BUFFER_EXT, imageBuffers[1]); |
| BufferData(PIXEL_PACK_BUFFER_EXT, imageSize / 2, NULL, STATIC_READ); |
| |
| // render to framebuffer |
| DrawBuffer(GL_BACK); |
| renderScene(); |
| |
| // Bind two different buffer objects and start the ReadPixels |
| // asynchronously. Each call will return directly after starting the |
| // DMA transfer. |
| BindBuffer(PIXEL_PACK_BUFFER_EXT, imageBuffers[0]); |
| ReadPixels(0, 0, width, height/2, |
| GL_BGRA, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)); |
| |
| BindBuffer(PIXEL_PACK_BUFFER_EXT, imageBuffers[1]); |
| ReadPixels(0, height/2, width, height/2, GL_BGRA, GL_UNSIGNED_BYTE, |
| BUFFER_OFFSET(0)); |
| |
| // process partial images |
| pboMemory1 = MapBuffer(PIXEL_PACK_BUFFER_EXT, READ_ONLY); |
| processImage(pboMemory1); |
| pboMemory2 = MapBuffer(PIXEL_PACK_BUFFER_EXT, READ_ONLY); |
| processImage(pboMemory2); |
| |
| // unmap the image buffers |
| BindBuffer(PIXEL_PACK_BUFFER_EXT, imageBuffers[0]); |
| if (!UnmapBuffer(PIXEL_PACK_BUFFER_EXT)) { |
| // Handle error case |
| } |
| BindBuffer(PIXEL_PACK_BUFFER_EXT, imageBuffers[1]); |
| if (!UnmapBuffer(PIXEL_PACK_BUFFER_EXT)) { |
| // Handle error case |
| } |