sRGB and the Screen

Thus far, we have seen how to use sRGB textures to store gamma-corrected images, such that they are automatically linearized upon being fetched from a shader. Since the sRGB colorspace closely approximates a gamma of 2.2, if we could use an sRGB image as the image we render to, we would automatically get gamma correction without having to put it into our shaders. But this would require two things: the ability to specify that the screen image is sRGB, and the ability to state that we are outputting linear values and want them converted to the sRGB colorspace when stored.

Naturally, OpenGL provides both of these. To see how they work, load up the last project, Gamma Landscape. This shows off some textured terrain with a day/night cycle and a few lights running around.

Figure 16.5. Gamma Landscape

Gamma Landscape

It uses the standard mouse-based controls to move around. As before, the 1 and 2 keys respectively select linear mipmap filtering and anisotropic filtering. The main feature is the non-shader-based gamma correction. This is enabled by default and can be toggled by pressing the SpaceBar.

sRGB Screen Image.  The process for setting this up is a bit confusing, but is ultimately quite simple for our tutorials. The OpenGL specification specifies how to use the OpenGL rendering system, but it does not specify how to create the OpenGL rendering system. That is relegated to platform-specific APIs. Therefore, while code that uses OpenGL is platform-neutral, that code is ultimately dependent on platform-specific initialization code to create the OpenGL context.

These tutorials rely on FreeGLUT for setting up the OpenGL context and managing the platform-specific APIs. The framework.cpp file is responsible for doing the initialization setup work, telling FreeGLUT exactly how we want our screen image set up. In order to allow different tutorials to adjust how we set up our FreeGLUT screen image, the framework calls the defaults function.

Example 16.4. Gamma Landscape defaults Function

unsigned int defaults(unsigned int displayMode, int &width, int &height)
{
    return displayMode | GLUT_SRGB;
}

The displayMode argument is a bitfield that contains the standard FreeGLUT display mode flags set up by the framework. This function must return that bitfield, and all of our prior tutorials have returned it unchanged. Here, we change it to include the GLUT_SRGB flag. That flag tells FreeGLUT that we want the screen image to be in the sRGB colorspace.

Linear to sRGB Conversion.  This alone is insufficient. We must also tell OpenGL that our shaders will be writing linear colorspace values and that these values should be converted to sRGB before being written to the screen. This is done with a simple glEnable command:

Example 16.5. Enable sRGB Conversion

if(g_useGammaDisplay)
    glEnable(GL_FRAMEBUFFER_SRGB);
else
    glDisable(GL_FRAMEBUFFER_SRGB);

The need for this is not entirely obvious, especially since we cannot manually turn off sRGB-to-linear conversion when reading from textures. The ability to disable linear-to-sRGB conversion for screen rendering is useful when we are drawing something directly in the sRGB colorspace. For example, it is often useful to have parts of the interface drawn directly in the sRGB colorspace, while the actual scene being rendered uses color conversion.

Note that the color conversion is just as free in terms of performance as it is for texture reads. So you should not fear using this as much and as often as reasonable.

Having this automatic gamma correction is better than manual gamma correction because it covers everything that is written to the screen. In prior tutorials, we had to manually gamma correct the clear color and certain other colors used to render solid objects. Here, we simply enable the conversion and everything is affected.

The process of ensuring a linear pipeline from texture creation, through lighting, through to the screen is commonly called gamma-correct texturing. The name is a bit of a misnomer, as texturing is not a requirement; we have been gamma-correct since Tutorial 12's introduction of that concept (except for Tutorial 15, where we looked at filtering). However, textures are the primary source of potential failures to maintain a linear pipeline, as many image formats on disc have no way of saying if the image data is in sRGB or linear. So the name still makes some sense.

Fork me on GitHub