Skip to content

EDID: HDR metadata in DisplayID extension blocks is not parsed, silently disabling HDR #371

Description

@scotttromley

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_SRGBcm = "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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions