Color Management Drawing Pipeline¶
This page describes the color management pipeline used in Blender for drawing to the screen. It will give a bit of history, an overview of the current state and points to the relevant bits and pieces in the code.
In the past Blender used to have a fixed color management pipeline where color stored as bytes were assumed to be in sRGB and colors stored in float were assumed to be in Rec709. During Open Movie Tears of Steel a new color management pipeline was introduced based on OpenColorIO. The color space of images could now be specified. Many places in Blender still rely on the fixed color management pipeline.
With the introduction of EEVEE and the Draw module (Blender 2.80) the color management pipeline was added to the 3d viewport. The first implementation wasn't flexible enough and was rewritten for Blender 2.83. The main difference is that the color management was moved from the draw manager to the gpu viewport.
In Blender 2.91 the image editor was migrated to use the same color management pipeline as the 3d viewport. The previous image editor still used the old pipeline that integrated alphas in display space. Blender 2.91 fixes the issue that semi-transparent images didn't show correctly in the image/uv editor.
GPU Viewport has a color texture and an overlay texture. The color texture is in Linear Scene Reference Space and the overlay texture is in encoded linear display space. Encoded here means that the data is in linear display space, but is stored in an SRGB texture. The encoding increases performance and needs less space on the GPU.
Based on the needed color space you have to select the correct texture as render target. The main draw engines (Workbench, EEVEE & Grease Pencil) draw to the color texture as they work in Linear Scene Reference Space. The overlay engine renders to the overlay texture as it needs Linear Display Space. The overlay engine renders Camera background images to the color texture.
When the GPUViewport is copied to the screen the textures are merged and
transformed to display space. This is done in the OpenColorIO glsl
gpu_shader_display_transform.glsl). This shader is located
/intern/opencolorio due to old policy issues.
The shader converts the color texture to linear display space and the overlay texture is alpha blended on top of it.
GPUViewport can be used to render in stereo. The results are stored in 4 buffers:
- Right eye color
- Right eye overlay
- Left eye color
- Left eye overlay
A GPUViewport can activate one eye (left or right). When switching eyes
the textures are swapped and the new active textures are attached to the
frame buffers. The
DefaultTextureList.color contains the color
buffer for the active eye and
color_stereo for the inactive eye. The
same for the overlay buffers. (See:
Normally this is done by the window manager (during binding of a region
wm_draw_region_bind) or the draw manager (when switching views
Before the GPU Viewport is copied to the screen the left and right eye
buffers are merged. It depends on the window setting where and how this
is done. The side-by-side and top-bottom will be handled by the window
manager. The buffers are copied to the right location on the screen. The
anaglyph and interlace modes are handled in
Guide lines for developers¶
When colors are important use a GPU Viewport. Color management can be
turned on in the GPUViewport by calling
When using draw manager (
/source/blender/draw) this is done by
drw_viewport_colormanagement_set. In special cases this function
needs to be adapted to select the render settings or only apply the view
Don't use Display buffer¶
ImBuf has a display buffer. The display buffer originates from
tracking and ensured playback of a 4k movie including color management.
The display buffer caches the result after the transform to display
space (screen pixels). Nowadays it is better to use GPUViewport and draw
the movie in Linear Scene Reference Space to the color texture. This
reduces complexity and should make faster preprocessing/loading of the
movie clips. The drawing will be a bit slower, but it should be OK on
The current implementation has some short comings
- When doing a viewport rendering with overlays to an image the colors of the overlays are stamped in the image. Rendered images are always stored in Linear Scene Reference Space. The overlays are stamped into the render result what leads to different result then when viewed in the 3d viewport.
- Pure emissive colors aren't supported by some commonly used image file formats. Most noticeable is PNGs. There isn't a good way to solve this without knowing how the exported PNGs will be used.
- Currently there isn't a python API to render to the color buffer. This results that add-ons that will use BGL rely on the display space. The consequence is that add-ons aren't able use the full potential of the drawing color pipeline.
- 2d Texture painting is still done in the fixed color pipeline. But the color selection is done using OpenColorIO. This can result in unexpected behavior.
- Image empties are drawn to the overlay texture. This is a limitation that should be fixed.
- Overlay colors inside the draw manager are in linear sRGB. This should be linear display space we should transfer the colors using an OpenColorIO processor.