Apple Developer Connection
Member Login Log In | Not a Member? Contact ADC

< Previous PageNext Page > Hide TOC

OpenGL

When defining an OpenGL image or texture, you need to provide a type that specifies to OpenGL which format the texture is in. Most of these functions (for example, glTexImage2D) take format and type_ parameters that specify how the texture is laid out on disk or in memory. OpenGL supports a number of different image types; some are endian-neutral but others are not.

Note: The advice in this section is for applications that can not reorder their pixel data because of the type of image loaders they are using.

For example, a common image format is GL_RGBA with a type of GL_UNSIGNED_BYTE. This means that the image has a byte that specifies the red color data followed by a byte that specifies the green color data, and so forth. This format is not endian-specific; the bytes are in the same order on all architectures. Another common image format is GL_BGRA, often specified by the type GL_UNSIGNED_INT_8_8_8_8_REV. This type means that every 4 bytes of image data are interpreted as an unsigned int, with the most significant 8 bits representing the alpha data, the next most significant 8 bits representing the red color data, and so forth. Because this format is specific to the integer format of the host, the format is interpreted differently on little-endian systems than on big-endian systems. When using GL_UNSIGNED_INT_8_8_8_8_REV, the OpenGL implementation expects to find data in byte order ARGB on big-endian systems, but BGRA on little-endian systems.

Because there is no explicit way in OpenGL to specify a byte order of ARGB with 32-bit or 16-bit packed pixels (which are common image formats on Macintosh PowerPC computers), many applications specify GL_BGRA with GL_UNSIGNED_INT_8_8_8_8_REV. This practice works on a big-endian system such as PowerPC, but the format is interpreted differently on a little-endian system and causes images to be rendered with incorrect colors.

Applications that have this problem are those that use the OpenGL host-order format types, but assume that the data referred to is always big-endian. These types include, but are not limited to the following:

GL_SHORT
GL_UNSIGNED_SHORT
GL_INT
GL_UNSIGNED_INT
GL_FLOAT
GL_DOUBLE
GL_UNSIGNED_BYTE_3_3_2
GL_UNSIGNED_SHORT_4_4_4_4
GL_UNSIGNED_SHORT_5_5_5_1
GL_UNSIGNED_INT_8_8_8_8
GL_UNSIGNED_INT_10_10_10_2
GL_UNSIGNED_SHORT_5_6_5
GL_UNSIGNED_BYTE_2_3_3_REV
GL_UNSIGNED_SHORT_5_6_5_REV
GL_UNSIGNED_SHORT_4_4_4_4_REV
GL_UNSIGNED_SHORT_1_5_5_5_REV
GL_UNSIGNED_INT_8_8_8_8_REV
GL_UNSIGNED_INT_2_10_10_10_REV

If your application does not use any of these types, it is unlikely to have any problems with OpenGL. Note that an application is not necessarily incorrect to use one of these types. Many applications might already present host-order data tagged with one of these formats, especially with existing cross-platform code, because the Mac OS X implementation behaves the same way as a Windows implementation.

If an application incorrectly uses one of these types, its OpenGL textures and images are rendered with incorrect colors. For example, red might appear green, or the image might appear to be tinted purple.

You can fix this problem in one of the following ways:

  1. If the images are generated or loaded algorithmically, change the code to generate the textures in host-order format that matches what OpenGL expects. For example, a JPEG decoder can be modified to store its output in 32-bit integers instead of four 8-bit bytes. The resulting data is identical on big-endian systems, but on a little-endian system, the bytes are in a different order. This matches the OpenGL expectation, and the existing OpenGL code continues to work on both architectures. This is the preferred approach.

    In many cases, rewriting the algorithms may prove a significant amount of work to implement and debug. If that’s the case, an approach that asks OpenGL to interpret the texture data differently might be a better approach for you to take.

  2. If the application uses GL_UNSIGNED_INT_8_8_8_8_REV or GL_UNSIGNED_INT_8_8_8_8, it can switch between them based on the architecture. Since these two types are exactly byte swapped versions of the same format, using GL_UNSIGNED_INT_8_8_8_8_REV on a big-endian system is equivalent to using GL_UNSIGNED_INT_8_8_8_8 on a little-endian system and vice versa. Code might look as follows:

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGRA_EXT,
    #if __BIG_ENDIAN__
                        GL_UNSIGNED_INT_8_8_8_8_REV,
    #else
                        GL_UNSIGNED_INT_8_8_8_8,
    #endif
                        data);

    If this is a common idiom, it might be easiest to define it as a macro that can be used multiple times:

    #if __BIG_ENDIAN__
    #define ARGB_IMAGE_TYPE GL_UNSIGNED_INT_8_8_8_8_REV
    #else
    #define ARGB_IMAGE_TYPE GL_UNSIGNED_INT_8_8_8_8
    #endif
    /* later on, use it like this */
    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB,
                    width, height, 0, GL_BGRA_EXT,
                    ARGB_IMAGE_TYPE, data);

    Note that switching between GL_UNSIGNED_INT_8_8_8_8_REV and GL_UNSIGNED_INT_8_8_8_8 works only for this particular 32-bit packed-pixel data type. For 16-bit ARGB data stored using GL_UNSIGNED_SHORT_1_5_5_5_REV, there is no corresponding byte swapped type. Keep in mind that GL_UNSIGNED_SHORT_5_5_5_1 is not a replacement for GL_UNSIGNED_SHORT_1_5_5_5_REV on an Intel-based Macintosh computer. The format is interpreted as bit-order arrrrrbbbbbggggg on a big-endian system, and as bit order ggrrrrrabbbbbggg on a little-endian system.

  3. If you can’t use the previous approaches, you should either generate/load your data in the native endian format of the system and use the same pixel type on both architectures or use the GL_UNPACK_SWAP_BYTES pixel store setting to instruct OpenGL to swap the bytes of any texture loaded on a little-endian system. This setting applies to all texture or image calls made with the current OpenGL context, so it needs to be set only once per OpenGL context, for example:

    #if __LITTLE_ENDIAN__
                glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
    #endif

    This method causes images that use the problematic formats to be loaded as they would be on PowerPC. You should consider this option only if no other option is available. Enabling this option causes OpenGL to use a slower rendering path than normal. Performance-sensitive OpenGL applications may be significantly slower with this option enabled than with it off. Although this method can get an OpenGL-based program up and running in as little time as possible, it is highly recommended that you use one of the other two methods.

Note: Using the GL_UNSIGNED_INT_8_8_8_8 format for GL_BGRA data is not necessarily faster than using GL_UNPACK_SWAP_BYTES. In some cases, performance decreases for rendering textures that use either of those two methods compared to using a data type such as GL_UNSIGNED_INT_8_8_8_8_REV. It’s advisable that you use Shark or other tools to analyze the performance of your OpenGL code and make sure that you are not encountering particularly bad cases.



< Previous PageNext Page > Hide TOC


Last updated: 2007-02-26




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.
Get information on Apple products.
Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Copyright © 2007 Apple Inc.
All rights reserved. | Terms of use | Privacy Notice