blob: 4d2f03f28a9ecce6a877553654ee9d719a14a3b2 [file] [log] [blame]
Name
NV_pixel_data_range
Name Strings
GL_NV_pixel_data_range
Contact
Matt Craighead, NVIDIA Corporation (mcraighead 'at' nvidia.com)
Notice
Copyright NVIDIA Corporation, 2000, 2001, 2002.
IP Status
NVIDIA Proprietary.
Status
Shipping (version 1.0)
Version
NVIDIA Date: November 7, 2002 (version 1.0)
Number
284
Dependencies
Written based on the wording of the OpenGL 1.3 specification.
If this extension is implemented, the WGL or GLX memory allocator
interface specified in NV_vertex_array_range must also be
implemented. Please refer to the NV_vertex_array_range specification
for further information on this interface.
Overview
The vertex array range extension is intended to improve the
efficiency of OpenGL vertex arrays. OpenGL vertex arrays' coherency
model and ability to access memory from arbitrary locations in memory
prevented implementations from using DMA (Direct Memory Access)
operations.
Many image-intensive applications, such as those that use dynamically
generated textures, face similar problems. These applications would
like to be able to sustain throughputs of hundreds of millions of
pixels per second through DrawPixels and hundreds of millions of
texels per second through TexSubImage.
However, the same restrictions that limited vertex throughput also
limit pixel throughput.
By the time that any pixel operation that reads data from user memory
returns, OpenGL requires that it must be safe for the application to
start using that memory for a different purpose. This coherency
model prevents asynchronous DMA transfers directly out of the user's
buffer.
There are also no restrictions on the pointer provided to pixel
operations or on the size of the data. To facilitate DMA
implementations, the driver needs to know in advance what region of
the address space to lock down.
Vertex arrays faced both of these restrictions already, but pixel
operations have one additional complicating factor -- they are
bidirectional. Vertex array data is always being transfered from the
application to the driver and the HW, whereas pixel operations
sometimes transfer data to the application from the driver and HW.
Note that the types of memory that are suitable for DMA for reading
and writing purposes are often different. For example, on many PC
platforms, DMA pulling is best accomplished with write-combined
(uncached) AGP memory, while pushing data should use cached memory so
that the application can read the data efficiently once it has been
read back over the AGP bus.
This extension defines an API where an application can specify two
pixel data ranges, which are analogous to vertex array ranges, except
that one is for operations where the application is reading data
(e.g. glReadPixels) and one is for operations where the application
is writing data (e.g. glDrawPixels, glTexSubImage2D, etc.). Each
pixel data range has a pointer to its start and a length in bytes.
When the pixel data range is enabled, and if the pointer specified
as the argument to a pixel operation is inside the corresponding
pixel data range, the implementation may choose to asynchronously
pull data from the pixel data range or push data to the pixel data
range. Data pulled from outside the pixel data range is undefined,
while pushing data to outside the pixel data range produces undefined
results.
The application may synchronize with the hardware in one of two ways:
by flushing the pixel data range (or causing an implicit flush) or by
using the NV_fence extension to insert fences in the command stream.
Issues
* The vertex array range extension required that all active vertex
arrays must be located inside the vertex array range. Should
this extension be equally strict?
RESOLVED: No, because a user may want to use the pixel data range
for one type of operation (say, texture downloads) but still be
able to use standard non-PDR pixel operations for everything
else. Requiring that apps disable PDR every time such an
operation occurs would be burdensome and make it difficult to
integrate this extension into a larger app with minimal changes.
So, for each pixel operation, we will look at the pointer
provided by the application. If it's inside the PDR, the PDR
rules apply, and if it's not inside the PDR, it's a standard GL
pixel operation, even if some of the data is actually inside the
PDR.
* Reads and writes may require different types of memory. How do
we handle this?
RESOLVED: The allocator interface already provides the ability to
specify different read and write frequencies. A buffer for a
write PDR should probably be allocated with a high write
frequency and low read frequency, while a read PDR's buffer
should have a low write and high read frequency.
Having two PDRs is essential because a single application may
want to perform both asynchronous reads and writes
simultaneously.
* What happens if a PDR pixel operation pulls data from a location
outside the PDR?
RESOLVED: The data pulled is undefined, and program termination
may result.
* What happens if a PDR pixel operation pushes data to a location
outside the PDR?
RESOLVED: The contents of that memory location become undefined,
and program termination may result.
* What happens if the hardware can't support the operation?
RESOLVED: The operation may be slow, because we may need to, for
example, read the pixel data out of uncached memory with the CPU,
but it should still work. So this should never be a problem; in
fact, it means that a basic implementation that accelerates only,
say, one operation is quite trivial.
* Should there be any limitations to what operations should be
supported?
RESOLVED: No, in theory any pixel operation that accesses a
user's buffer can work with PDR. This includes Bitmap,
PolygonStipple, GetTexImage, ConvolutionFilter2D, etc. Many are
unlikely to be accelerated, but there is no reason to place
arbitrary restrictions. A list of possibly supported operations
is provided for OpenGL 1.2.1 with ARB_imaging support and for all
the extensions currently supported by NVIDIA. Developers should
carefully read the Implementation Details provided by their
vendor before using the extension.
* 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.
* Can the PDRs and the VAR overlap and/or be the same buffer?
RESOLVED: Yes. In fact, it is expected that one of the preferred
modes of usage for this extension will be to use the same AGP
buffer for both the write PDR and the VAR, so it can be used for
both dynamic texturing and dynamic geometry.
* Can video memory buffers be used?
RESOLVED: Yes, assuming the implementation supports using them
for PDR. On systems with AGP Fast Writes, this may be
interesting in some cases. Another possible use for this is to
treat a video memory buffer as an offscreen surface, where
DrawPixels can be thought of as a blit from offscreen memory to
a GL surface, and ReadPixels can be thought of as a blit from a
GL surface to offscreen memory. This technique should be used
with caution, because there are other alternatives, such as
pbuffers, aux buffers, and even textures.
* Do we want to support more than one read and one write PDR?
RESOLVED: No, but I could imagine uses for it. For example, an
app could use two system memory buffers (one read, one write PDR)
and a single video memory buffer (both read and write). Do we
need a scheme where an unlimited number of PDR buffers can be
specified? Ugh. I hope not. I can't think of a good reason to
use more than 3 buffers, and even that is stretching it.
* Do we want a separate enable for both the read and write PDR?
RESOLVED: Yes. In theory, they are completely independent, and
we should treat them as such.
* Is there an equivalent to the VAR validity check?
RESOLVED: No. When a vertex array call occurs, all the vertex
array state is already set. We can know in advance whether all
the pointers, strides, etc. are set up in a satisfactory way.
However, for a pixel operation, much of the state is provided on
the same function call that performs the operation. For example,
the pixel format of the data may need to match that of the
framebuffer. We can't know this without looking at the format
and type arguments.
An alternative might be some sort of "proxy" mechanism for pixel
operations, but this seems to be very complicated.
* Do we want a more generalized API? What stops us from needing a
DMA extension for every single conceivable use in the future?
RESOLVED: No, this is good enough. Since new extensions will
probably require new semantics anyhow, we'll just live with that.
Maybe if the ARB wants to create a more generic "DMA" extension,
these issues can be revisited.
* How do applications synchronize with the hardware?
RESOLVED: A new command, FlushPixelDataRangeNV, is provided, that
is analogous to FlushVertexArrayRangeNV. Applications can also
use the Finish command. The NV_fence extension is best for
applications that need fine-grained synchronization.
* Should enabling or disabling a PDR induce an implicit PDR flush?
RESOLVED: No. In the VAR extension, enabling and disabling the
VAR does induce a VAR flush, but this has proven to be more
problematic than helpful, because it makes it much more difficult
to switch between VAR and non-VAR rendering; the VAR2 extension
lifts this restriction, and there is no reason to get this wrong
a second time.
The PDR extension does not suffer from the problem of enabling
and disabling frequently, because non-PDR operations are
permitted simply by providing a pointer outside of the PDR, but
there is no clear reason why the enable or disable should cause
a quite unnecessary PDR flush.
* Should this state push/pop?
RESOLVED: Yes, but via a Push/PopClientAttrib and the
GL_CLIENT_PIXEL_STORE_BIT bit. Although this is heavyweight
state, VAR also allowed push/pop. It does fit nicely into an
existing category, too.
* Should making another context current cause a PDR flush?
RESOLVED: No. There's no fundamental reason it should. Note
that apps should be careful to not free their memory until the
hardware is not using it... note also that this decision is
inconsistent with VAR, which did guarantee a flush here.
* Is the read PDR guaranteed to give you either old or new values,
or is it truly undefined?
RESOLVED: Undefined. This may ease implementation constraints
slightly. Apps must not rely at all on the contents of the
region where the readback is occurring until it is known to be
finished.
An example of how an implementation might conceivably require
this is as follows. Suppose that a piece of hardware, for some
reason, can only write full 32-byte chunks of data. Any bytes
that were supposed to be unwritten are in fact trashed by the
hardware, filled with garbage. By careful fixups (read the
contents before the operation, restore when done), the driver may
be able to hide this fact, but a requirement that either new or
old data must show up would be violated.
Or, more trivially, you might implement certain pixel operations
as an in-place postprocess on the returned data.
It is not anticipated that NVIDIA implementations will need this
flexibility, but it is nevertheless provided.
* How should an application allocate its PDR memory?
The app should use wglAllocateMemoryNV, even for a read PDR in
system memory. Using malloc may result in suboptimal
performance, because the driver will not be able to choose an
optimal memory type. For ReadPixels to system memory, you might
set a read frequency of 1.0, a write frequency of 0.0, and a
priority of 1.0. The driver might allocate PCI memory, or
physically contiguous PCI memory, or cachable AGP memory, all
depending on the performance characteristics of the device.
While memory from malloc will work, it does not allow the driver
to make these decisions, and it will certainly never give you AGP
memory.
Write PDR memory for purposes of streaming textures, etc. works
exactly the same as VAR memory for streaming vertices. You can,
and in fact are encouraged to, use the same circular buffer for
both vertices and textures.
If you have different needs (not just streaming textures or
asynchronous readbacks), you may want your pixel data in video
memory.
New Procedures and Functions
void PixelDataRangeNV(enum target, sizei length, void *pointer)
void FlushPixelDataRangeNV(enum target)
New Tokens
Accepted by the <target> parameter of PixelDataRangeNV and
FlushPixelDataRangeNV, and by the <cap> parameter of
EnableClientState, DisableClientState, and IsEnabled:
WRITE_PIXEL_DATA_RANGE_NV 0x8878
READ_PIXEL_DATA_RANGE_NV 0x8879
Accepted by the <pname> parameter of GetBooleanv, GetIntegerv,
GetFloatv, and GetDoublev:
WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A
READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B
Accepted by the <pname> parameter of GetPointerv:
WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C
READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D
Additions to Chapter 2 of the OpenGL 1.3 Specification (OpenGL Operation)
None.
Additions to Chapter 3 of the OpenGL 1.3 Specification (Rasterization)
Add new section to Section 3.6, "Pixel Rectangles", on page 113:
"3.6.7 Write Pixel Data Range Operation
Applications can enhance the performance of DrawPixels and other
commands that transfer large amounts of pixel data by using a pixel
data range. The command
void PixelDataRangeNV(enum target, sizei length, void *pointer)
specifies one of the current pixel data ranges. When the write pixel
data range is enabled and valid, pixel data transfers from within
the pixel data range are potentially faster. The pixel data range is
a contiguous region of (virtual) address space for placing pixel
data. The "pointer" parameter is a pointer to the base of the pixel
data range. The "length" pointer is the length of the pixel data
range in basic machine units (typically unsigned bytes). For the
write pixel data range, "target" must be WRITE_PIXEL_DATA_RANGE_NV.
The pixel data range address space region extends from "pointer"
to "pointer + length - 1" inclusive.
There is some system burden associated with establishing a pixel data
range (typically, the memory range must be locked down). If either
the pixel data range pointer or size is set to zero, the previously
established pixel data range is released (typically, unlocking the
memory).
The pixel data range may not be established for operating system
dependent reasons, and therefore, not valid. Reasons that a pixel
data range cannot be established include spanning different memory
types, the memory could not be locked down, alignment restrictions
are not met, etc.
The write pixel data range is enabled or disabled by calling
EnableClientState or DisableClientState with the symbolic constant
WRITE_PIXEL_DATA_RANGE_NV.
The write pixel data range is valid when the following conditions are
met:
o WRITE_PIXEL_DATA_RANGE_NV is enabled.
o PixelDataRangeNV has been called with a non-null pointer and
non-zero size, for target WRITE_PIXEL_DATA_RANGE_NV.
o The write pixel data range has been established.
o An implementation-dependent validity check based on the
pointer alignment, size, and underlying memory type of the
write pixel data range region of memory.
Otherwise, the write pixel data range is not valid.
The commands, such as DrawPixels, that may be made faster by the
write pixel data range are listed in the Appendix.
When the write pixel data range is valid, an attempt will be made to
accelerate these commands if and only if the data pointer argument to
the command lies within the write pixel data range. No attempt will
be made to accelerate commands whose base pointer is outside this
range. Accessing data outside the write pixel data range when the
base pointer lies within the range and the range is valid will
produce undefined results and may cause program termination.
The standard OpenGL pixel data coherency model requires that pixel
data be extracted from the user's buffer immediately, before the
pixel command returns. When the write pixel data range is valid,
this model is relaxed so that changes made to pixel data until the
next "write pixel data range flush" may affect pixel commands in non-
sequential ways. That is, a call to a pixel command that precedes
a change to pixel data (without an intervening "write pixel data
range flush") may access the changed data; though a call to a pixel
command following a change to pixel data must always access the
changed data, and never the original data.
A 'write pixel data range flush' occurs when one of the following
operations occur:
o Finish returns.
o FlushPixelDataRangeNV (with target WRITE_PIXEL_DATA_RANGE_NV)
returns.
o PixelDataRangeNV (with target WRITE_PIXEL_DATA_RANGE_NV)
returns.
The client state required to implement the write pixel data range
consists of an enable bit, a memory pointer, and an integer size.
If the memory mapping of pages within the pixel data range changes,
using the pixel data range has undefined effects. To ensure that the
pixel data range reflects the address space's current state, the
application is responsible for calling PixelDataRange again after any
memory mapping changes within the pixel data range."
Additions to Chapter 4 of the OpenGL 1.3 Specification (Per-Fragment
Operations and the Frame Buffer)
Add new section to Section 4.3, "Pixel Draw/Read State", on page 180:
"4.3.5 Read Pixel Data Range Operation
The read pixel data range is similar to the write pixel data range
(see section 3.6.7), but is specified with PixelDataRangeNV with a
target READ_PIXEL_DATA_RANGE_NV. It is exactly analogous to the
write pixel data range, but applies to commands where OpenGL returns
pixel data to the caller, such as ReadPixels. The list of commands
to which the read pixel data range applies can be found in the
Appendix.
Validity checks and flushes of the read pixel data range behave in a
manner exactly analogous to those of the write pixel data range,
though any implementation-dependent checks may differ between the two
types of pixel data range.
The standard OpenGL pixel data coherency model requires that pixel
data be written into the user's buffer immediately, before the
pixel command returns. When the read pixel data range is valid,
this model is relaxed so that this data may not necessarily be
available until the next "read pixel data range flush". Until such
point in time, an attempt to read the buffer returns undefined
values.
If both the read and write pixel data ranges are valid and overlap,
then all operations involving both in the same thread are
automatically synchronized. That is, the write pixel data range
operation will automatically wait for any pending read pixel data
range results to become available before attempting to retrieve them.
However, if the operations are performed from different threads, the
user is responsible for all such synchronization.
Read pixel data range operations are also synchronized with vertex
array range operations in the same way.
The client state required to implement the read pixel data range
consists of an enable bit, a memory pointer, and an integer size."
Additions to Chapter 5 of the OpenGL 1.3 Specification (Special Functions)
Add the following to the end of Section 5.4 "Display Lists" (page
179):
"PixelDataRangeNV and FlushPixelDataRangeNV are not complied into
display lists but are executed immediately.
If a display list is compiled while WRITE_PIXEL_DATA_RANGE_NV is
enabled, all commands affected by that enable are accumulated into a
display list as if WRITE_PIXEL_DATA_RANGE_NV is disabled.
The state of the read pixel data range does not affect display list
compilation, because those commands that might be accelerated by a
read pixel data range are commands that are executed immediately
rather than being compiled into a display list (ReadPixels and
GetTexImage, for example)."
Additions to Chapter 6 of the OpenGL 1.3 Specification (State and
State Requests)
None.
Additions to the GLX Specification
"OpenGL implementations using GLX indirect rendering should fail to
set up the pixel data range and will not accelerate any pixel
operations using it. Additionally, glXAllocateMemoryNV always fails
to allocate memory (returns NULL) when used with an indirect
rendering context."
GLX Protocol
None
Errors
INVALID_OPERATION is generated if PixelDataRangeNV or
FlushPixelDataRangeNV is called between the execution of Begin and
the corresponding execution of End.
INVALID_ENUM is generated if PixelDataRangeNV or
FlushPixelDataRangeNV is called when target is not
WRITE_PIXEL_DATA_RANGE_NV or READ_PIXEL_DATA_RANGE_NV.
INVALID_VALUE is generated if PixelDataRangeNV is called when length
is negative.
New State
Initial
Get Value Get Command Type Value Attrib
--------- ----------- ---- ------- ------
WRITE_PIXEL_DATA_RANGE_NV IsEnabled B False pixel-store
READ_PIXEL_DATA_RANGE_NV IsEnabled B False pixel-store
WRITE_PIXEL_DATA_RANGE_POINTER_NV GetPointerv Z+ 0 pixel-store
READ_PIXEL_DATA_RANGE_POINTER_NV GetPointerv Z+ 0 pixel-store
WRITE_PIXEL_DATA_RANGE_LENGTH_NV GetIntegerv Z+ 0 pixel-store
READ_PIXEL_DATA_RANGE_LENGTH_NV GetIntegerv Z+ 0 pixel-store
Appendix: Operations Supported
In unextended OpenGL 1.3 with ARB_imaging support, the following
commands may take advantage of the write PDR:
glBitmap
glColorSubTable
glColorTable
glCompressedTexImage1D
glCompressedTexImage2D
glCompressedTexImage3D
glCompressedTexSubImage1D
glCompressedTexSubImage2D
glCompressedTexSubImage3D
glConvolutionFilter1D
glConvolutionFilter2D
glDrawPixels
glPixelMapfv
glPixelMapuiv
glPixelMapusv
glPolygonStipple
glSeparableFilter2D
glTexImage1D
glTexImage2D
glTexImage3D
glTexSubImage1D
glTexSubImage2D
glTexSubImage3D
In unextended OpenGL 1.3 with ARB_imaging support, the following
commands may take advantage of the read PDR:
glGetColorTable
glGetCompressedTexImage
glGetConvolutionFilter
glGetHistogram
glGetMinmax
glGetPixelMapfv
glGetPixelMapuiv
glGetPixelMapusv
glGetPolygonStipple
glGetSeparableFilter
glGetTexImage
glReadPixels
No other extensions shipping in the NVIDIA OpenGL drivers add any
other new commands that may take advantage of this extension,
although in a few cases there are new commands that alias to other
commands that may be accelerated by this extension. These commands
are:
glCompressedTexImage1DARB (ARB_texture_compression)
glCompressedTexImage2DARB (ARB_texture_compression)
glCompressedTexImage3DARB (ARB_texture_compression)
glCompressedTexSubImage1DARB (ARB_texture_compression)
glCompressedTexSubImage2DARB (ARB_texture_compression)
glCompressedTexSubImage3DARB (ARB_texture_compression)
glColorSubTableEXT (EXT_paletted_texture)
glColorTableEXT (EXT_paletted_texture)
glGetCompressedTexImageARB (ARB_texture_compression)
glTexImage3DEXT (EXT_texture3D)
glTexSubImage3DEXT (EXT_texture3D)
NVIDIA Implementation Details
In the Release 40 OpenGL drivers, the NV_pixel_data_range extension
is supported on all GeForce/Quadro-class hardware. The following
commands may potentially be accelerated in this release:
glReadPixels
glTexImage2D
glTexSubImage2D
glCompressedTexImage2D
glCompressedTexImage3D
glCompressedTexSubImage2D
The following type/format/buffer format sets are accelerated for
glReadPixels:
type format buffer format
-----------------------------------------------------------------------------------------------
GL_UNSIGNED_SHORT_5_6_5 GL_RGB 16-bit color (PCs only -- Macs use 555)
GL_UNSIGNED_INT_8_8_8_8_REV GL_BGRA 32-bit color w/ alpha
GL_UNSIGNED_BYTE GL_BGRA 32-bit color w/ alpha (little endian only)
GL_UNSIGNED_SHORT GL_DEPTH_COMPONENT 16-bit depth
GL_UNSIGNED_INT_24_8_NV GL_DEPTH_STENCIL_NV 24-bit depth, 8-bit stencil
The following internalformat/type/format sets are accelerated for
glTex[Sub]Image2D:
internalformat type format
-------------------------------------------------------------------------------
GL_RGB5 GL_UNSIGNED_SHORT_5_6_5 GL_RGB
GL_RGB8 GL_UNSIGNED_INT_8_8_8_8_REV GL_BGRA
GL_RGBA4 GL_UNSIGNED_SHORT_4_4_4_4_REV GL_BGRA
GL_RGB5_A1 GL_UNSIGNED_SHORT_1_5_5_5_REV GL_BGRA
GL_RGBA8 GL_UNSIGNED_INT_8_8_8_8_REV GL_BGRA
GL_DEPTH_COMPONENT16_SGIX GL_UNSIGNED_SHORT GL_DEPTH_COMPONENT
GL_DEPTH_COMPONENT24_SGIX GL_UNSIGNED_INT_24_8_NV GL_DEPTH_STENCIL_NV
The following internalformat/type/format sets will be accelerated for
glTex[Sub]Image2D on little-endian machines only:
internalformat type format
-------------------------------------------------------------------------------
GL_LUMINANCE8_ALPHA8 GL_UNSIGNED_BYTE GL_LUMINANCE_ALPHA
GL_RGB8 GL_UNSIGNED_BYTE GL_BGRA
GL_RGBA8 GL_UNSIGNED_BYTE GL_BGRA
All compressed texture formats are supported for
glCompressedTex[Sub]Image[2,3]D.
The following restrictions apply to all commands:
- No pixel transfer operations of any kind may be in use.
- The base address of the PDR must be aligned to a 32-byte boundary.
- The data pointer must be aligned to boundaries of the size of one
group of pixels. For example, GL_UNSIGNED_SHORT_5_6_5 data must
be aligned to 2-byte boundaries, GL_UNSIGNED_INT_24_8_NV data must
be aligned to 4-byte boundaries, and GL_BGRA/GL_UNSIGNED_BYTE data
must be aligned to 4-byte boundaries (not 1-byte boundaries).
Compressed texture data must be aligned to a block boundary.
No additional restrictions apply to glReadPixels or
glCompressedTex[Sub]Image[2,3]D.
The following additional restrictions apply to glTex[Sub]Image2D:
- The texture must fit in video memory.
- The texture must have a border size of zero.
- The stride (in bytes) between two lines of source data must not
exceed 65535.
- For non-rectangle textures, the width and height of the destination
mipmap level must not exceed 2048, nor be below 2; also, the
destination mipmap level must not be 2x2 (for 16-bit textures) or
2x2, 4x2, or 2x4 (for 8-bit textures).
Future software releases may increase the number of accelerated
commands and the number of accelerated data formats for each command.
Note also that although all of the formats and commands listed are
guaranteed to be accelerated, there may be limitations in the actual
implementation not as strict as those stated here; for example, some
data formats not listed here may turn out to be accelerated.
However, it is highly recommended that you stick to the formats and
commands listed in this section. In cases where actual restrictions
are less strict, future implementations may very well enforce the
listed restriction.
It is also possible that some of these restrictions may become _more_
strict on future chips; though at present no such additional
restrictions are known to be likely. Such restrictions would likely
take the form of more stringent pitch or alignment restrictions, if
they proved to be necessary.
In practice, you should expect that several of these restrictions
will be more lenient in a future release.
Revision History
November 7, 2002 - Updated implementation details section with most
up-to-date rules on PDR usage. Lifted rule that texture downloads
must be 2046 pixels in size or smaller. Removed support for 8-bit
texture downloads. Increased max TexSubImage pitch to 65535 from
8191.