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_LUMINANCEtoSDR_MAX_LUMINANCE - HDR luminance range:
HDR_MIN_LUMINANCEtoHDR_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:
eotfvalues:0for SDR,2for PQ,3for HLG- Primaries and white point converted to 16-bit values
- Mastering luminance range, max CLL, and max FALL
Summary
- Surface Detection:
CColorManagementSurfaceidentifies HDR content viaSImageDescriptionand transfer function analysis (PQ/HLG/scRGB) insrc/protocols/ColorManagement.cpp. - Monitor Validation:
CMonitor::supportsHDR()parses EDID data to confirm HDR capability usinghdrMetadatainsrc/output/Monitor.cpp. - Runtime Switching:
handleFullscreenSettings()coordinates HDR activation usingcreateHDRMetadata()to build kernel DRM structures insrc/render/Renderer.cpp. - Configuration:
render:cm_auto_hdrenables automatic fullscreen HDR switching, whilerender:non_shader_cmoptimizes performance when shader conversion is unnecessary. - Metadata Transmission: The
hdr_output_metadatastruct communicates EOTF, primaries, and luminance data to the kernel viasetHDRMetadata().
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →