Skip to content

nvt: only parse per-VIC 3D entries when 3D_present is set - #1308

Open
clinche wants to merge 1 commit into
NVIDIA:mainfrom
clinche:fix-hdmi3d-offbyone
Open

nvt: only parse per-VIC 3D entries when 3D_present is set#1308
clinche wants to merge 1 commit into
NVIDIA:mainfrom
clinche:fix-hdmi3d-offbyone

Conversation

@clinche

@clinche clinche commented Aug 19, 2026

Copy link
Copy Markdown

Fixes HDR being unavailable on HDMI displays whose Vendor Specific Data
Block ends with reserved or padding bytes.

The final loop in parseEdidHDMILLCTiming() is missing the
ThreeD_Present guard that the two preceding 3D parsing blocks have, so
it reinterprets leftover VSDB bytes as per-VIC 3D entries. Any byte
value sets a non-zero stereo mask, so HDMI3DSupported ends up set on
displays that advertise no 3D support at all.

This trips two gates: nvDpyIsHDRCapable() (EINVAL on any BT2020
Colorspace commit, with no kernel log at any debug level) and
SendHDRInfoFrame() (the DRM InfoFrame is never sent, so the display
stays in SDR while the compositor composites in PQ/BT2020).
This accounts for both failure modes people report. If HDR cannot
be enabled at all, it is the first gate. If HDR appears to enable
but the picture is washed out and the display stays in SDR, as
in #779, it is the second: the compositor composites in
PQ/BT2020 while the sink is never told to switch.

Reproducer: RTX 5080 (GB203), 610.57.04, kernel 7.1.8, KDE Plasma 6.7.4
Wayland, Acer XV322QK KV over HDMI. Its VSDB is 13 bytes and ends with
one padding byte after two HDMI VICs, with 3D_present = 0 and
HDMI_3D_Len = 0. The parser walk gives DataSz = 5 and DataCnt = 4, so
the loop runs once on the padding byte.

Verified by instrumenting nvDpyIsHDRCapable(): every condition passes
except hdmi3D. Independently confirmed on a stock driver by overriding
the EDID via drm.edid_firmware to widen HDMI_VIC_Len so the trailing
byte is consumed as an (ignored) HDMI VIC instead: HDR then enables and
the monitor leaves SDR.

Note that trailing reserved bytes in a VSDB are expected and are meant
to be ignored by parsers for forward compatibility, so this is likely
to affect a range of displays rather than one vendor's EDID.

A stricter variant would bound the loop by HDMI_3D_Len rather than
gating on ThreeD_Present, which would also cover displays that do
advertise 3D and have padding. I kept the change minimal and
symmetrical with the surrounding code; happy to switch if you prefer.

parseEdidHDMILLCTiming() ends with a loop that consumes the remaining
bytes of the HDMI VSDB and interprets each one as an NVT_3D_MULTI_LIST
entry. Unlike the two 3D parsing blocks above it, this loop is not
guarded by pHDMIVideo->ThreeD_Present, so trailing reserved or padding
bytes are treated as 3D mode descriptors.

Because NVT_HDMI_3D_SUPPORTED_STRUCT_MASK(x) is 1 << x, any byte value
yields a non-zero StereoStructureMask, including 0x00. A single padding
byte is therefore enough to leave HDMI3DSupported set on a display whose
VSDB advertises 3D_present = 0.

The cost is user-visible: nvDpyIsHDRCapable() then returns FALSE, so
atomic commits setting the DRM Colorspace property to BT2020_RGB or
BT2020_YCC fail with EINVAL, and SendHDRInfoFrame() returns early, so
the Dynamic Range and Mastering InfoFrame is never transmitted. HDR is
either unavailable or appears to enable while the sink stays in SDR.

Guard the loop the same way the preceding ones are.
@CLAassistant

CLAassistant commented Aug 19, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@aritger

aritger commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the proposed patch. Could you please attach the EDID you used to test this? I'd like to step through this path.

@clinche

clinche commented Aug 20, 2026

Copy link
Copy Markdown
Author

I'm attaching 3 EDIDs, zipped together as github doesn't allow upload raw bin files:

  • The first one is the original one, i.e. cat /sys/class/drm/card1-HDMI-A-1/edid > xv322qk_orig.bin
  • The second one is a try I did because di-edid-decode reported an invalid Colorimetry Data Block: Reserved bits MD0-MD3 must be 0., so I've zeroed them
  • The third one is the one that's working with the untouched latest driver, it has zeroed out CDB and VIC_Len has been incremented.

xv322qk.zip

To wrap it up:

  • Recompiled driver with my proposed change but original, untouched EDID -> HDR working flawlessly
  • Original driver but with the VIC_Len patched EDID -> HDR working flawlessly
  • Original driver with original EDID -> monitor gets declared 3D, HDR rejected by driver
#> cat /sys/class/drm/card1-HDMI-A-1/edid > xv322qk_orig.bin
#> di-edid-decode < xv322qk_orig.bin| tail -8               
----------------

Failures:

Block 1, CTA-861 Extension Block:
  Video Capability Data Block: IT video formats are always overscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to underscanned.
  Colorimetry Data Block: Reserved bits MD0-MD3 must be 0.
EDID conformity: FAIL

#> python fix-cdb.py -o xv322qk_cdb_zeroed.bin xv322qk_orig.bin 
EDID: 384 bytes, 3 blocs.

Bloc 1: extension CTA-861 (revision 3)
  Colorimetry Data Block: at +0x71
    MD Byte    : 0x01  (bits actifs : MD0)
    -> patched : 0x00
  checksum : 0xF6 -> 0xF7

Patched : xv322qk_cdb_zeroed.bin
#> python fix-phantom3d.py xv322qk_cdb_zeroed.bin -o xv322qk_cdbzeroed_extendedviclen.bin
EDID: 384 bytes, 3 blocs.

Bloc 1: VSDB HDMI: at +0x29, len 13
  dump : 6D 03 0C 00 20 00 38 3C 20 00 41 01 03 00
  3D_present=0 HDMI_VIC_Len=2 HDMI_3D_Len=1
  DataSz=5 DataCnt=4 -> tail: 1
  -> HDMI_VIC_Len 2 -> 3 (patching 0x41 -> 0x61)
  checksum : 0xF7 -> 0xD7

Patched : xv322qk_cdbzeroed_extendedviclen.bin
#> diff -u <(xxd xv322qk_orig.bin) <(xxd xv322qk_cdb_zeroed.bin)
--- /proc/self/fd/11	2026-08-20 18:52:02.683329101 +0200
+++ /proc/self/fd/12	2026-08-20 18:52:02.683329101 +0200
@@ -10,10 +10,10 @@
 00000090: 6176 2309 0707 8301 0000 e200 d56d 030c  av#..........m..
 000000a0: 0020 0038 3c20 0041 0103 006d d85d c401  . .8< .A...m.]..
 000000b0: 78c0 3309 3090 c334 0c6d 1a00 0002 0130  x.3.0..4.m.....0
-000000c0: 90e6 0000 0000 00e3 05c3 01e3 0f00 18e6  ................
+000000c0: 90e6 0000 0000 00e3 05c3 00e3 0f00 18e6  ................
 000000d0: 0605 0162 621b 40e7 006a a0a0 6750 0820  ...bb.@..j..gP. 
 000000e0: 9804 b988 2100 001a 6fc2 00a0 a0a0 5550  ....!...o.....UP
-000000f0: 3020 3500 b988 2100 001e 0000 0000 00f6  0 5...!.........
+000000f0: 3020 3500 b988 2100 001e 0000 0000 00f7  0 5...!.........
 00000100: 7012 7900 0003 013c b9fd 0104 ff0e 4f00  p.y....<......O.
 00000110: 0700 1f00 6f08 9900 8b00 0700 eba3 0104  ....o...........
 00000120: ff0e 4f00 0700 1f00 6f08 7e00 7000 0700  ..O.....o.~.p...
#> diff -u <(xxd xv322qk_cdb_zeroed.bin) <(xxd xv322qk_cdbzeroed_extendedviclen.bin) 
--- /proc/self/fd/11	2026-08-20 18:52:42.991505323 +0200
+++ /proc/self/fd/12	2026-08-20 18:52:42.991505323 +0200
@@ -8,12 +8,12 @@
 00000070: 0058 5633 3232 514b 204b 560a 2020 0267  .XV322QK KV.  .g
 00000080: 0203 56f1 4d01 0203 0490 1113 1f3f 5d5f  ..V.M........?]_
 00000090: 6176 2309 0707 8301 0000 e200 d56d 030c  av#..........m..
-000000a0: 0020 0038 3c20 0041 0103 006d d85d c401  . .8< .A...m.]..
+000000a0: 0020 0038 3c20 0061 0103 006d d85d c401  . .8< .a...m.]..
 000000b0: 78c0 3309 3090 c334 0c6d 1a00 0002 0130  x.3.0..4.m.....0
 000000c0: 90e6 0000 0000 00e3 05c3 00e3 0f00 18e6  ................
 000000d0: 0605 0162 621b 40e7 006a a0a0 6750 0820  ...bb.@..j..gP. 
 000000e0: 9804 b988 2100 001a 6fc2 00a0 a0a0 5550  ....!...o.....UP
-000000f0: 3020 3500 b988 2100 001e 0000 0000 00f7  0 5...!.........
+000000f0: 3020 3500 b988 2100 001e 0000 0000 00d7  0 5...!.........
 00000100: 7012 7900 0003 013c b9fd 0104 ff0e 4f00  p.y....<......O.
 00000110: 0700 1f00 6f08 9900 8b00 0700 eba3 0104  ....o...........
 00000120: ff0e 4f00 0700 1f00 6f08 7e00 7000 0700  ..O.....o.~.p...

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants