20/07/2015 Texture swizzling in OpenGL, OpenGL ES and WebGL

When targeting a large amount of platform, by coincidence OpenGL 3.2 to 4.5, OpenGL ES 2.0 to ES 3.1+ and WebGL 1.0 and 2.0, it takes quite some investigations to implement a feature optimally. The difference between doing this investigation and not doing it is basically shipping a buggy engine. As an example, let's study texture swizzle and how it's exposed in OpenGL, OpenGL ES and WebGL.

1. Configurable texture swizzling

GL_EXT_texture swizzle, promoted to OpenGL 3.3 core specifiction through GL_ARB_texture_swizzle extension, introduced a functionality to handle texture with arbitrary ordering or the components without requiring CPU reordering. For example, it allows loading BGRA8 or ARGB8 source textures to OpenGL RGBA8 texture object.

With OpenGL 3.3 and OpenGL ES 3.0, loading a BGRA8 texture can be done using the following approach:

OpenGL 3.3 and OpenGL ES 3.0 BGRA texture swizzling, a channel at a time:
  • GLint const Swizzle[] = {GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA};
  • glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, Swizzle[0]);
  • glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, Swizzle[1]);
  • glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, Swizzle[2]);
  • glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, Swizzle[3]);
  • glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Data);

OpenGL 3.3, GL_ARB_texture_swizzle and GL_EXT_texture swizzle provides a slightly different approach that is not available with OpenGL ES 3.0:

OpenGL 3.3 BGRA texture swizzling, all channels at once:
  • GLint const Swizzle[] = {GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA};
  • glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, Swizzle);
  • glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Data);

Unfortunately, neither WebGL 1.0 or WebGL 2.0 support texture swizzle due to performance issue of implementation such feature on top of Direct3D which doesn't have any equivalent functionality.

Known driver bugs:
  • NVIDIA ES drivers (353.12) won't generate an invalid enum error if GL_TEXTURE_SWIZZLE_RGBA is used
  • Intel ES drivers (4222) won't generate an invalid enum error if GL_TEXTURE_SWIZZLE_RGBA is used

2. BGRA texture swizzling using texture formats

OpenGL supports GL_BGRA external format to load BGRA8 source textures without requiring the application to swizzle the source data. This is done using the following code:

OpenGL core and compatibility profiles BGRA swizzling with texture image:
  • glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_BGRA, GL_UNSIGNED_BYTE, Data);
OpenGL core and compatibility profiles BGRA swizzling with texture storage:
  • glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, Width, Height);
  • glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, Width, Height, GL_BGRA, GL_UNSIGNED_BYTE, Data);

However, such functionnality isn't available with OpenGL ES. While, it's not useful for OpenGL ES 3.0 that has texture swizzling support, OpenGL ES 2.0 relies on some extensions to expose this feature but it does it differently than OpenGL.

Using the GL_EXT_texture_format_BGRA8888 or GL_APPLE_texture_format_BGRA8888 extensions, loading BGRA textures is done with the following code:

OpenGL core and compatibility profiles BGRA swizzling with texture image:
  • glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, Width, Height, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, Data);

When GL_EXT_texture_storage (ES2) is supported, BGRA texture loading is perform with the following code.

OpenGL core and compatibility profiles BGRA swizzling with texture image:
  • glTexStorage2D(GL_TEXTURE_2D, 1, GL_BGRA8_EXT, Width, Height);
  • glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, Width, Height, GL_BGRA, GL_UNSIGNED_BYTE, Data);

To understand the difference between OpenGL, OpenGL ES and OpenGL ES with texture storage the reasoning is the following: On the contrary to OpenGL, OpenGL ES doesn't support external format to internal format conversion of any kind, including texture component swizzling. Additionally, OpenGL ES 2.0 requires unsized format for the internal format while OpenGL ES 3.0 and texture storage requires sized internal format.

3. Texture alpha swizzling

In this section, we call a texture alpha, a texture we using the alpha channel (.a, .w, .q) in a shader. With OpenGL ES and WebGL, this can be done by creating a texture with an alpha format as shown with the following code samples.

OpenGL ES 2.0 texture alpha:
  • glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, Width, Height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, Data);
OpenGL ES 3.0 texture alpha:
  • glTexStorage2D(GL_TEXTURE_2D, 1, GL_ALPHA8, Width, Height);
  • glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, Width, Height, GL_ALPHA, GL_UNSIGNED_BYTE, Data);

Texture alpha format is also available in OpenGL compatibility profile and WebGL but was removed in OpenGL core profile. An alternative is to rely on texture red format and texture swizzle as shown with the following code samples.

On one hand, both OpenGL ES and OpenGL compatibility profile supports texture alpha and luminance alpha. However, OpenGL core profile doesn't. On other hand, OpenGL 3.0 and OpenGL ES 3.0 support texture red and texture red green.

OpenGL 3.3 and OpenGL ES 3.0 texture alpha:
  • glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ZERO);
  • glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ZERO);
  • glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ZERO);
  • glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
  • glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, Width, Height, 0, GL_RED, GL_UNSIGNED_BYTE, Data);
OpenGL 4.2 and OpenGL ES 3.0 texture alpha with texture storage:
  • glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ZERO);
  • glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ZERO);
  • glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ZERO);
  • glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
  • glTexStorage2D(GL_TEXTURE_2D, 1, GL_R8, Width, Height);
  • glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, Width, Height, GL_RED, GL_UNSIGNED_BYTE, Data);

Texture red format was introduced on desktop with OpenGL 3.0 and GL_ARB_texture_rg. On OpenGL ES, it was introduced with OpenGL ES 3.0 and GL_EXT_texture_rg.

Unfortunately, OpenGL 3.2 core profile doesn't support either texture alpha format or texture swizzling. A possible workaround is to expend the source data to RGBA8 which consumes 4 times the memory which might be necessary to support texture alpha on MacOSX 10.7.

Enjoy!

  • GL_ARB_texture_swizzle support on Windows and Linux
  • GL_EXT_texture_swizzle support on Windows and Linux
  • GL_ARB_texture_rg support on Windows and Linux
  • GL_EXT_texture_rg support on Android
  • GL_EXT_texture_format_BGRA8888 support on Android
  • GL_APPLE_texture_format_BGRA8888 support on Android
  • OSX OpenGL extensions
  • iOS OpenGL extensions
  • GLM 0.9.7.0 released >
    < GLI 0.6.1.1 released
    Copyright Christophe Riccio 2002-2016 all rights reserved
    Designed for Chrome 9, Firefox 4, Opera 11 and Safari 5