Home > Articles > Programming > Graphic Programming

  • Print
  • + Share This
This chapter is from the book

Texture Compression

Texture mapping can add incredible realism to any 3D rendered scene, with a minimal cost in vertex processing. One drawback to using textures, however, is that they require a lot of memory to store and process. Early attempts at texture compression were crudely storing textures as JPG files and decompressing the textures when loaded before calling glTexImage. These attempts saved disk space or reduced the amount of time required to transmit the image over the network (such as the Internet), but did nothing to alleviate the storage requirements of texture images loaded into graphics hardware memory.

Native support for texture compression was added to OpenGL with version 1.3. Earlier versions of OpenGL may also support texture compression via extension functions of the same name. You can test for this extension by using the GL_ARB_texture_compression string.

Texture compression support in OpenGL hardware can go beyond simply allowing you to load a compressed texture; in most implementations, the texture data stays compressed even in the graphics hardware memory. This allows you to load more texture into less memory and can significantly improve texturing performance due to fewer texture swaps (moving textures around) and fewer memory accesses during texture filtering.

Compressing Textures

Texture data does not have to be initially compressed to take advantage of OpenGL support for compressed textures. You can request that OpenGL compress a texture image when loaded by using one of the values in Table 9.1 for the internalFormat parameter of any of the glTexImage functions.

Table 9.1. Compressed Texture Formats

Compressed Format

Base Internal Format

GL_COMPRESSED_ALPHA

GL_ALPHA

GL_COMPRESSED_LUMINANCE

GL_LUMINANCE

GL_COMPRESSED_LUMINANCE_ALPHA

GL_LUMINANCE_ALPHA

GL_COMPRESSED_INTENSITY

GL_INTENSITY

GL_COMPRESSED_RGB

GL_RGB

GL_COMPRESSED_RGBA

GL_RGBA

Compressing images this way adds a bit of overhead to texture loads but can increase texture performance due to the more efficient usage of texture memory. If, for some reason, the texture cannot be compressed, OpenGL uses the base internal format listed instead and loads the texture uncompressed.

When you attempt to load and compress a texture in this way, you can find out whether the texture was successfully compressed by using glGetTexLevelParameteriv with GL_TEXTURE_COMPRESSED as the parameter name:

GLint compFlag;
. . .
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED, &compFlag);

The glGetTexLevelParameteriv function accepts a number of new parameter names pertaining to compressed textures. These parameters are listed in Table 9.2.

Table 9.2. Compressed Texture Parameters Retrieved with glGetTexLevelParameter

Parameter

Returns

GL_TEXTURE_COMPRESSED

The value 1 if the texture is compressed, 0 if not

GL_TEXTURE_COMPRESSED_IMAGE_SIZE

The size in bytes of the compressed texture

GL_TEXTURE_INTERNAL_FORMAT

The compression format used

GL_NUM_COMPRESSED_TEXTURE_FORMATS

The number of supported compressed texture formats

GL_COMPRESSED_TEXTURE_FORMATS

An array of constant values corresponding to each supported compressed texture format

GL_TEXTURE_COMPRESSION_HINT

The value of the texture compression hint (GL_NICEST/GL_FASTEST)

When textures are compressed using the values listed in Table 9.1, OpenGL chooses the most appropriate texture compression format. You can use glHint to specify whether you want OpenGL to choose based on the fastest or highest quality algorithm:

glHint(GL_TEXTURE_COMPRESSION_HINT, GL_FASTEST);
glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
glHint(GL_TEXTURE_COMPRESSION_HINT, GL_DONT_CARE);

The exact compression format varies from implementation to implementation. You can obtain a count of compression formats and a list of the values by using GL_NUM_COMPRESSED_TEXTURE_FORMATS and GL_COMPRESSED_TEXTURE_FORMATS. To check for support for a specific set of compressed texture formats, you need to check for a specific extension for those formats. For example, nearly all implementations support the GL_EXT_texture_compression_s3tc texture compression format. If this extension is supported, the compressed texture formats listed in Table 9.3 are all supported, but only for two-dimensional textures.

Table 9.3. Compression Formats for GL_EXT_texture_compression_s3tc

Format

Description

GL_COMPRESSED_RGB_S3TC_DXT1

RGB data is compressed; alpha is always 1.0.

GL_COMPRESSED_RGBA_S3TC_DXT1

RGB data is compressed; alpha is either 1.0 or 0.0.

GL_COMPRESSED_RGBA_S3TC_DXT3

RGB data is compressed; alpha is stored as 4 bits.

GL_COMPRESSED_RGBA_S3TC_DXT5

RGB data is compressed; alpha is a weighted average of 8-bit values.

Loading Compressed Textures

Using the functions in the preceding section, you can have OpenGL compress textures in a natively supported format, retrieve the compressed data with the glGetCompressedTexImage function (identical to the glGetTexImage function for uncompressed textures), and save it to disk. On subsequent loads, the raw compressed data can be used, resulting in substantially faster texture loads. Be advised, however, that some vendors may cheat a little when it comes to texture loading in order to optimize texture storage or filtering operations. This technique will work only on fully conformant hardware implementations.

To load precompressed texture data, use one of the following functions:

void glCompressedTexImage1D(GLenum target, GLint level, GLenum internalFormat,
                        GLsizei width,
                        GLint border, GLsizei imageSize, void *data);
void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalFormat,
                        GLsizei width, GLsizei height,
                        GLint border, GLsizei imageSize, void *data);
void glCompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat,
                        GLsizei width, GLsizei height, GLsizei depth,
                        GLint border, Glsizei imageSize, GLvoid *data);

These functions are virtually identical to the glTexImage functions from the preceding chapter. The only difference is that the internalFormat parameter must specify a supported compressed texture image. If the implementation supports the GL_EXT_texture_compression_s3tc extension, this would be one of the values from Table 9.3. There is also a corresponding set of glCompressedTexSubImage functions for updating a portion or all of an already-loaded texture that mirrors the glTexSubImage functionality from the preceding chapter.

Texture compression is a very popular texture feature. Smaller textures take up less storage, transmit faster over networks, load faster off disk, copy faster to graphics memory, allow for substantially more texture to be loaded onto hardware, and generally texture slightly faster to boot! Don't forget, though, as with so many things in life, there is no such thing as a free lunch. Something may be lost in the compression. The GL_EXT_texture_compression_s3tc method, for example, works by stripping color data out of each texel. For some textures, this results in substantial image quality loss (particularly for textures that contain smooth color gradients). Other times, textures with a great deal of detail are visually nearly identical to the original uncompressed version. The choice of texture compression method (or indeed no compression) can vary greatly depending on the nature of the underlying image.

  • + Share This
  • 🔖 Save To Your Account