blob: b1ec911681779b3b6dc77558f59a00a5504143af [file] [log] [blame]
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
}