Linear Space Rendering Pipeline

Linear Space Rendering Pipeline

With version 1.42, Gameface becomes capable of handling SRGB textures passed as a user render target (RT) (the texture given to cohtml::ViewRenderer::SetRenderTarget). If the given user RT is an SRGB texture, the Renoir rendering library will linearize all incoming colors and do all color math and blending in linear space instead of gamma-corrected SRGB color space.

Renoir uses the standard formula for converting from gamma-encoded SRGB space to linear space:

static float SrgbToLinear(float srgb)
{
	float linear = srgb;
	if (linear <= 0.04045f)
	{
		linear = linear / 12.92f;
	}
	else
	{
		linear = std::powf((linear + 0.055f) / 1.055f, 2.4f);
	}
	return linear;
}

where the used gamma value is 2.4.

Note that this has no bearing on how the colors are given in the HTML/CSS. From the frontend’s perspective, all colors in the CSS are defined in a standard gamma-corrected sRGB space. This means that there are no changes required to the CSS/HTML to make the linear rendering pipeline work. The linearization in the rendering library is enabled as long as the provided user RT is an SRGB texture with the new renoir::PF_R8G8B8A8_SRGB pixel format or a floating point texture with renoir::PF_R16G16B16A16 or renoir::PF_R32G32B32A32 format.

When the linear pipeline is in use, all intermediate render targets that Renoir allocates will also be SRGB textures. The linearized colors will be used for blending but ultimately the textures will contain gamma-corrected SRGB values. The encoding (on texture write) and the decoding (on texture read) are handled by the graphics API.

The Advantage of using a linear rendering pipeline is that the blending operations as well as interpolations between colors (like for gradients) can be done more accurately.

The following diagram illustrates the new rendering flow visually:

Defining linear space colors in CSS

As a part of the ability to use the linear pipeline, Gameface now also allows the definition of linear space colors straight into the CSS. The standard syntax of doing that is through the color(srgb-linear <color-values>). This tells Gameface to interpret the <color-values> as a linear color. This is useful when front-end developers want to define a color in an alternative color space rather than using gamma-corrected SRGB.

For example

<html>

<head>
<style>
#rect {
	width: 100px;
	height: 100px;
	background-color: color(srgb-linear 0.21 0.0 0.0 1.0)
}
</style>
</head>

<body>
<div id="rect"></div>
</body>

</html>

tells Gameface to interpret the given color as a color in linear space.

It is important to note however, that no matter how the color is being specified in the CSS, the rendering library of Gameface will get the gamma-corrected version of the color. This ensures that all colors given by Cohtml to Renoir are in the same gamma-corrected SRGB space. Those colors are linearized only if the corresponding user RT for the cohtml::View is an SRGB texture. This prevents users from accidentally using colors in different color spaces while drawing on the same render target.

This is in contrast to the behavior in Chrome. For example, in Chrome one would get different results if they are drawing two gradients with colors given in different color spaces. This is not the case in Gameface where all colors used by the rendering library will be consistently in a single color space.

Handling of images

All images decoded and allocated on the GPU by Gameface are in renoir::PF_R8G8B8A8. Renoir will never allocate those images as SRGB textures. This is due to Gameface sharing resources (including images) between views and we don’t want to introduce some confusing logic of how the user RT of one view can affect how the images are allocated for all other views. Hence, for consistency Renoir always uses the renoir::PF_R8G8B8A8 format when possible when decoding images from .png files. Texture container formats like DDS and KTX have information about the format of the contained texture and when Renoir loads images from such formats, it will use the given format.

As a consequence, it is important to keep in mind that when using the linear rendering pipeline, some images might be loaded as simple renoir::PF_R8G8B8A8 textures even though the appropriate thing to do would be to load them as renoir::PF_R8G8B8A8_SRGB. When using the linear rendering pipeline, Renoir will automatically convert from SRGB to linear format when the texture is not in an SRGB format. If the image contains linear values, IMP_LinearColorValues can be used to avoid the conversion.

Switching between linear and SRGB space rendering

You can choose the color space in the Unity Editor’s Project Settings. The active color space at the time of playing will be the one configured in our rendering library.

To switch between Linear and Gamma color space:

  1. Go to Edit and open the “Project Settings”.
  2. Select “Player” and navigate to the “Other Settings” menu.
  3. Open the Color Space drop-down option and select the desired color space.