How Hyprland Implements Color Management and HDR Support: Technical Architecture

Hyprland implements color management and HDR support through a Wayland protocol-based pipeline that detects HDR content via surface image descriptions, validates monitor capabilities through EDID parsing, and dynamically switches HDR modes at runtime by submitting metadata to the kernel DRM subsystem.

Hyprland, the dynamic tiling Wayland compositor from the hyprwm organization, provides sophisticated color management that automatically adapts to HDR content and display capabilities. The implementation spans protocol handlers, output management, and the rendering pipeline to deliver accurate color reproduction and HDR10/HLG output. This article examines the source code architecture behind Hyprland's color management system.

The Three-Stage Color Management Pipeline

Hyprland’s color management operates through a three-stage workflow that bridges Wayland protocol objects to kernel DRM outputs.

Stage 1: Surface Image Description

Every surface in Hyprland can expose a color-management image description (SImageDescription) that defines its color space characteristics. This structure stores primaries, transfer function, luminance range, and optional HDR metadata. The CColorManagementSurface class creates and manages these descriptions, accessible via CColorManagementSurface::imageDescription().

HDR detection occurs when the transfer function is CM_TRANSFER_FUNCTION_ST2084_PQ (PQ) or CM_TRANSFER_FUNCTION_HLG, or when the surface uses Windows scRGB (isWindowsScRGB()). This logic resides in src/protocols/ColorManagement.cpp.

Stage 2: Monitor Capability Detection

Each monitor reports HDR support through EDID parsing. The CMonitor class provides supportsHDR(), which returns true only if the monitor advertises wide-color (BT2020) and contains HDR metadata (hdrMetadata.has_value()). The current HDR state is read from the DRM hdr_output_metadata sent to the kernel via inHDR(). These capabilities are implemented in src/output/Monitor.cpp.

Stage 3: Runtime HDR Activation

When a fullscreen window appears, IHyprRenderer::handleFullscreenSettings() decides whether to enable HDR. It checks the monitor’s capability, the surface’s description (surfaceIsHDR), and the user-configurable render:cm_auto_hdr. If HDR is required, createHDRMetadata() builds an hdr_output_metadata structure containing EOTF, primaries, and mastering luminances, which is pushed to the monitor via pMonitor->m_output->state->setHDRMetadata(). When HDR is not needed, the compositor falls back to zeroed metadata (NO_HDR_METADATA). This logic lives in src/render/Renderer.cpp.

Core Color Management Architecture

Color Space Definitions and Constants

The foundation of Hyprland's color system is defined in src/helpers/cm/ColorManagement.hpp. Key constants include:

  • SDR luminance range: SDR_MIN_LUMINANCE to SDR_MAX_LUMINANCE
  • HDR luminance range: HDR_MIN_LUMINANCE to HDR_MAX_LUMINANCE
  • Supported primaries: CM_PRIMARIES_* enums
  • Transfer functions: CM_TRANSFER_FUNCTION_* enums

Helper functions convert between internal enums and Wayland protocol values.

HDR Detection Logic

A surface reports HDR content through CColorManagementSurface::isHDR(). This method returns true when the image description specifies PQ (ST 2084), HLG transfer functions, or when isWindowsScRGB() indicates linear extended-range content.

Automatic HDR Configuration

The render:cm_auto_hdr configuration option enables automatic switching. When enabled and an HDR surface enters fullscreen, Hyprland sets the monitor’s color-management type to CM_HDR (or CM_HDR_EDID when the monitor provides its own HDR metadata).

No-Shader Color Conversion Optimization

For cases where only primaries differ, Hyprland can skip shader-based conversion using render:non_shader_cm. The decision occurs in CMonitor::canNoShaderCM(), which checks transfer-function compatibility and whether the surface and monitor share identical image descriptions.

Source Code Reference

Detecting HDR Surfaces

To check if a surface provides HDR content in src/protocols/ColorManagement.cpp:

if (surface->m_colorManagement->isHDR()) {
    // surface provides HDR content (PQ/HLG or Windows scRGB)
}

Validating Monitor HDR Support

In src/output/Monitor.cpp, verify monitor capabilities:

bool monitorCanHDR = monitor->supportsHDR();   // true only if EDID advertises HDR
bool monitorWantsHDR = monitor->wantsHDR();   // HDR is supported and currently enabled

Triggering Automatic HDR Mode

The renderer checks configuration and surface state in src/render/Renderer.cpp:

static auto PAUTOHDR = CConfigValue<Config::INTEGER>("render:cm_auto_hdr");
if (*PAUTOHDR && surface->m_colorManagement->isHDR())
    wantHDR = true;   // trigger monitor HDR mode

Constructing HDR Metadata

Create and apply metadata structures in src/render/Renderer.cpp:

hdr_output_metadata md = createHDRMetadata(
    surface->m_colorManagement->imageDescription(),
    monitor
);
monitor->m_output->state->setHDRMetadata(md);

The createHDRMetadata() function fills the hdr_output_metadata struct with:

  • eotf values: 0 for SDR, 2 for PQ, 3 for HLG
  • Primaries and white point converted to 16-bit values
  • Mastering luminance range, max CLL, and max FALL

Summary

  • Surface Detection: CColorManagementSurface identifies HDR content via SImageDescription and transfer function analysis (PQ/HLG/scRGB) in src/protocols/ColorManagement.cpp.
  • Monitor Validation: CMonitor::supportsHDR() parses EDID data to confirm HDR capability using hdrMetadata in src/output/Monitor.cpp.
  • Runtime Switching: handleFullscreenSettings() coordinates HDR activation using createHDRMetadata() to build kernel DRM structures in src/render/Renderer.cpp.
  • Configuration: render:cm_auto_hdr enables automatic fullscreen HDR switching, while render:non_shader_cm optimizes performance when shader conversion is unnecessary.
  • Metadata Transmission: The hdr_output_metadata struct communicates EOTF, primaries, and luminance data to the kernel via setHDRMetadata().

Frequently Asked Questions

What triggers HDR mode in Hyprland?

HDR mode activates when a fullscreen window presents content with PQ, HLG, or scRGB transfer functions, provided render:cm_auto_hdr is enabled and the monitor reports HDR support via EDID. The handleFullscreenSettings() function evaluates these conditions during the rendering loop.

How does Hyprland detect if a monitor supports HDR?

Hyprland parses the monitor's EDID metadata in src/output/Monitor.cpp. The supportsHDR() method checks for the presence of HDR metadata and BT2020 primaries, returning true only when the hardware explicitly advertises HDR capability.

What is the difference between cm_auto_hdr and non_shader_cm?

The render:cm_auto_hdr setting automatically switches monitors into HDR mode for fullscreen HDR content, while render:non_shader_cm allows the compositor to skip shader-based color conversion when surfaces and monitors share compatible primaries and transfer functions, reducing GPU load.

Does Hyprland support Windows scRGB content?

Yes. Hyprland recognizes Windows scRGB (linear extended-range) content through CColorManagementSurface::isWindowsScRGB(), which returns true for such surfaces and treats them as HDR content requiring appropriate color management and output metadata.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →