Bug 486585 - Physical monitor size reported as 790x0 mm on Wayland
Summary: Physical monitor size reported as 790x0 mm on Wayland
Status: RESOLVED FIXED
Alias: None
Product: kwin
Classification: Plasma
Component: wayland-generic (show other bugs)
Version: 6.0.4
Platform: Manjaro Linux
: NOR normal
Target Milestone: ---
Assignee: KWin default assignee
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-05-04 17:13 UTC by Jakub Piecuch
Modified: 2024-05-21 16:24 UTC (History)
2 users (show)

See Also:
Latest Commit:
Version Fixed In: 6.1


Attachments
Display EDID (128 bytes, application/octet-stream)
2024-05-04 17:13 UTC, Jakub Piecuch
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Jakub Piecuch 2024-05-04 17:13:56 UTC
Created attachment 169192 [details]
Display EDID

SUMMARY

KWin reports the physical dimensions of my laptop's built-in display as 790x0 mm on Wayland and X11.
I queried the physical dimensions with the `wayland-info` utility.

STEPS TO REPRODUCE

(I don't know how to reproduce this without access to the hardware, but I have attached the EDID of the display.)
1. Run `wayland-info`

OBSERVED RESULT

physical_width: 790 mm, physical_height: 0 mm

EXPECTED RESULT

physical_width: 344 mm, physical_height: 194 mm

SOFTWARE/OS VERSIONS
Linux: 6.8.8-2-MANJARO 
KDE Plasma Version: 6.0.4
KDE Frameworks Version: 6.1.0
Qt Version: 6.7.0

ADDITIONAL INFORMATION

I used the `di-edid-decode` utility to parse the EDID and it turns out that the correct physical dimensions (344x194 mm) are reported in the "Detailed Timing Descriptors" section:

$ di-edid-decode /sys/class/drm/card1-eDP-1/edid
Block 0, Base EDID:
  EDID Structure Version & Revision: 1.4
  Vendor & Product Identification:
    Manufacturer: LGD
    Model: 1472
    Made in: week 0 of 2017
  Basic Display Parameters & Features:
    Digital display
    Bits per primary color channel: 8
    DisplayPort interface
    Aspect ratio: 1.78 (landscape)
    Gamma: 2.20
    DPMS levels: Standby Suspend Off
    Supported color formats: RGB 4:4:4, YCrCb 4:4:4
    First detailed timing includes the native pixel format and preferred refresh rate
  Color Characteristics:
    Red  : 0.6396, 0.3300
    Green: 0.3046, 0.6054
    Blue : 0.1503, 0.0546
    White: 0.3134, 0.3291
  Established Timings I & II: none
  Standard Timings: none
  Detailed Timing Descriptors:
    DTD 1:  1920x1080  143.998072 Hz  16:9    166.606 kHz    346.540000 MHz (344 mm x 194 mm)
                 Hfront   48 Hsync  32 Hback   80 Hpol P
                 Vfront    3 Vsync   5 Vback   69 Vpol N
    DTD 2:  1920x1080   60.002659 Hz  16:9     69.423 kHz    144.400000 MHz (344 mm x 194 mm)
                 Hfront   48 Hsync  32 Hback   80 Hpol P
                 Vfront    3 Vsync   5 Vback   69 Vpol N
Checksum: 0xa8

An EDID can report the physical dimensions of the display in the "Basic Display Parameters & Features" section, but the units there are centimeters, which leads to imprecise dimensions. An EDID can instead use the same bytes to report just the aspect ratio, which is exactly what is happening here (byte 0x15 = 79, byte 0x16 = 0 correspond to aspect ratio of 16:9).

I believe the 790x0 mm dimensions come from the connector dimensions reported by libdrm. These are then passed to the m_physicalSize of the DrmConnector class in the updateProperties() method:

    // check the physical size
    if (m_edid.physicalSize().isEmpty()) {
        m_physicalSize = QSize(m_conn->mmWidth, m_conn->mmHeight);
    } else {
        m_physicalSize = m_edid.physicalSize();
    }

So in this case, m_edid.physicalSize().isEmpty() return true, because the Edid class uses libdisplay-info to parse the EDID, which correctly parses the {79, 0} bytes as the aspect ratio, not the display's physical size, and reports the physical size as 0x0.  The logic falls back to reading the size from m_conn, which is a pointer to libdrm's drmModeConnector. The libdrm library gets the connector dimension from the kernel, which doesn't do as good of a job parsing the EDID (or maybe it's intentional) and reports the connector dimensions as 790x0 mm.

As explained earlier, the {79, 0} bytes come from the "Basic Display Parameters & Features"  section of the EDID. 
An EDID can also contain a number of detailed timing descriptors, which can specify the physical dimensions of an image, this time in millimeters, giving us more precision.
An important thing to note is that these dimensions are not the display's physical size, but rather the physical size of the displayed image when this particular mode is set. In many cases this will be equal to the display's physical size, but it doesn't have to be.
However, I believe we can use this information as a fallback in case neither libdisplay-info nor libdrm report sensible physical dimensions: we can check if every detailed timing descriptor contains the same physical dimensions, and if so, use these dimensions as the physical size of the display (provided these dimension are sensible, i.e. both width and height are positive) .

I'm curious to know what you think of this workaround :)
Comment 1 Jakub Piecuch 2024-05-04 20:36:19 UTC
(In reply to Jakub Piecuch from comment #0)
> KWin reports the physical dimensions of my laptop's built-in display as
> 790x0 mm on Wayland and X11.

Correction: on X11, xrandr reports correct physical size for the built-in display.
Comment 2 Jakub Piecuch 2024-05-05 10:47:15 UTC
I dug into how the X server determines the monitor's physical size and it appears that the logic is as follows:
1. Find the first detailed timing section with sane physical width and height (the code sanity checks the aspect ratio) and use that as the monitor's width and height [1].
2. If no such section was found, fall back to using the width and height from the "Basic Display Parameters & Features" section [2].

Therefore, it makes sense that the X server reports the correct physical size for my laptop's built-in display.

[1] https://gitlab.freedesktop.org/xorg/xserver/-/blob/069ad69efe166105b8d2280bf2fb217d522b68a9/hw/xfree86/modes/xf86Crtc.c#L3175
[2] https://gitlab.freedesktop.org/xorg/xserver/-/blob/069ad69efe166105b8d2280bf2fb217d522b68a9/hw/xfree86/modes/xf86Crtc.c#L3299
Comment 3 Zamundaaa 2024-05-10 13:19:41 UTC
Adding the same workaround to KWin sounds reasonable
Comment 4 Bug Janitor Service 2024-05-19 14:14:19 UTC
A possibly relevant merge request was started @ https://invent.kde.org/plasma/kwin/-/merge_requests/5749
Comment 5 Zamundaaa 2024-05-21 11:22:55 UTC
Git commit 7bf40c3501d85af921f95d7398cd52840db839f2 by Xaver Hugl, on behalf of Jakub Piecuch.
Committed on 21/05/2024 at 11:22.
Pushed by zamundaaa into branch 'master'.

utils/edid: use detailed timings to compute physical screen size

An EDID can contain zero or more detailed timing definitions, which can contain
more precise physical dimensions of the screen (in millimeters, as opposed to
centimeters).

The Xorg server has similar logic for determining the physical screen size from
the EDID: pick the first sane size from the detailed timing definitions, and
fall back to the screen size given in the "Basic Display Parameters & Features"
section.

M  +30   -2    src/utils/edid.cpp

https://invent.kde.org/plasma/kwin/-/commit/7bf40c3501d85af921f95d7398cd52840db839f2