Summary
getDrmEdid() only parses HDR static metadata and colorimetry from top-level CTA-861 EDID extension blocks. Panels that carry that data inside a DisplayID extension (via a nested CTA-861 DisplayID Data Block) are skipped entirely, so parsedEDID.hdrMetadata stays empty and supportsPQ / supportsBT2020 come back false.
Downstream, Hyprland's CMonitor::supportsHDR() then returns false and silently downgrades any HDR request to CM_SRGB — cm = "hdr" / cm = "hdredid" are accepted with no error and simply don't take effect. HDR is unavailable to every Wayland client (mpv, Chromium/Brave, etc.) on affected hardware.
This affects modern eDP laptop panels generally, since DisplayID 2.0 is common there.
Environment
- aquamarine 0.14.0
- Hyprland 0.56.2
- Panel: Samsung
ATNA60KA02-0 (OLED, internal eDP) — Lenovo ThinkPad P1 Gen 8 / 21Q8
- Mesa/Intel Arc 140T (Arrow Lake),
libdisplay-info.so.3
Root cause
src/backend/drm/DRM.cpp, in the extension loop:
auto exts = di_edid_get_extensions(edid);
for (; *exts != nullptr; exts++) {
auto tag = di_edid_ext_get_tag(*exts);
if (tag == DI_EDID_EXT_DISPLAYID)
backend->backend->log(AQ_LOG_WARNING, "FIXME: support displayid blocks");
const auto cta = di_edid_ext_get_cta(*exts);
if (cta) {
...di_cta_data_block_get_hdr_static_metadata(...)
...di_cta_data_block_get_colorimetry(...)
}
}
The DisplayID branch logs a FIXME and falls through; only di_edid_ext_get_cta() extensions are parsed.
Evidence
The panel does advertise PQ — edid-decode shows it inside Block 1, DisplayID Extension Block, not a top-level CTA extension:
Block 0, Base EDID:
Block 1, DisplayID Extension Block:
...
CTA-861 DisplayID Data Block:
Colorimetry Data Block:
BT2020RGB
HDR Static Metadata Data Block:
Electro optical transfer functions:
Traditional gamma - SDR luminance range
SMPTE ST2084
Supported static metadata descriptors:
Static metadata type 1
Desired content max luminance: 160 (1600.000 cd/m^2)
Desired content max frame-average luminance: 119 (658.302 cd/m^2)
Desired content min luminance: 1 (0.000 cd/m^2)
Block 2, DisplayID Extension Block:
And the FIXME fires on every start:
WARN from aquamarine ]: FIXME: support displayid blocks
WARN from aquamarine ]: FIXME: support displayid blocks
With HDR unavailable, wp_color_manager_v1 advertises the output as plain SDR despite a 10bpc framebuffer:
tf_named: srgb
luminances (cd/m2): min 0.2000 max 80 reference 80
primaries: red 0.640 0.330 green 0.300 0.600 blue 0.150 0.060 white 0.3127 0.3290
so clients correctly tone-map to SDR. mpv logs transfer: srgb, max_luma=80 even with --target-colorspace-hint=yes --target-trc=pq forced.
Workaround
Hyprland's per-monitor overrides bypass the failed probe:
supports_wide_color = true
supports_hdr = true
With those set, the same output immediately advertises HDR correctly:
tf_named: st2084_pq
luminances (cd/m2): min 0.0000 max 1600 reference 203
primaries: red 0.708 0.292 green 0.170 0.797 (bt.2020)
and mpv negotiates transfer: pq, primaries: bt.2020, max_cll=1600 max_fall=650. HDR10 video then plays with real passthrough in both mpv and Brave.
Suggested fix
Parse CTA-861 data blocks nested in DisplayID extensions. libdisplay-info exposes DisplayID via di_edid_get_displayid() / the di_displayid_* API, and the high-level di_info_* interface may already surface this without walking extensions manually.
Secondary: Hyprland downgrading cm to CM_SRGB with no diagnostic makes this very hard to trace — a warning when an explicit cm = "hdr" is refused because supportsHDR() failed would help a lot.
Summary
getDrmEdid()only parses HDR static metadata and colorimetry from top-level CTA-861 EDID extension blocks. Panels that carry that data inside a DisplayID extension (via a nestedCTA-861 DisplayID Data Block) are skipped entirely, soparsedEDID.hdrMetadatastays empty andsupportsPQ/supportsBT2020come backfalse.Downstream, Hyprland's
CMonitor::supportsHDR()then returns false and silently downgrades any HDR request toCM_SRGB—cm = "hdr"/cm = "hdredid"are accepted with no error and simply don't take effect. HDR is unavailable to every Wayland client (mpv, Chromium/Brave, etc.) on affected hardware.This affects modern eDP laptop panels generally, since DisplayID 2.0 is common there.
Environment
ATNA60KA02-0(OLED, internal eDP) — Lenovo ThinkPad P1 Gen 8 / 21Q8libdisplay-info.so.3Root cause
src/backend/drm/DRM.cpp, in the extension loop:The DisplayID branch logs a FIXME and falls through; only
di_edid_ext_get_cta()extensions are parsed.Evidence
The panel does advertise PQ —
edid-decodeshows it inside Block 1, DisplayID Extension Block, not a top-level CTA extension:And the FIXME fires on every start:
With HDR unavailable,
wp_color_manager_v1advertises the output as plain SDR despite a 10bpc framebuffer:so clients correctly tone-map to SDR. mpv logs
transfer: srgb, max_luma=80even with--target-colorspace-hint=yes --target-trc=pqforced.Workaround
Hyprland's per-monitor overrides bypass the failed probe:
With those set, the same output immediately advertises HDR correctly:
and mpv negotiates
transfer: pq, primaries: bt.2020,max_cll=1600 max_fall=650. HDR10 video then plays with real passthrough in both mpv and Brave.Suggested fix
Parse CTA-861 data blocks nested in DisplayID extensions.
libdisplay-infoexposes DisplayID viadi_edid_get_displayid()/ thedi_displayid_*API, and the high-leveldi_info_*interface may already surface this without walking extensions manually.Secondary: Hyprland downgrading
cmtoCM_SRGBwith no diagnostic makes this very hard to trace — a warning when an explicitcm = "hdr"is refused becausesupportsHDR()failed would help a lot.