From 7bf40c3501d85af921f95d7398cd52840db839f2 Mon Sep 17 00:00:00 2001 From: Jakub Piecuch Date: Tue, 21 May 2024 11:22:51 +0000 Subject: [PATCH] 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. BUG: 486585 --- src/utils/edid.cpp | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/utils/edid.cpp b/src/utils/edid.cpp index d60e17cf0e..0e926150b2 100644 --- a/src/utils/edid.cpp +++ b/src/utils/edid.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -92,6 +93,34 @@ static QByteArray parseVendor(const uint8_t *data) return {}; } +static QSize determineScreenPhysicalSizeMm(const di_edid *edid) +{ + // An EDID can contain zero or more detailed timing definitions, which can + // contain more precise physical dimensions (in millimeters, as opposed to + // centimeters). Pick the first sane physical dimension from detailed timings + // and fall back to the basic dimensions. + const struct di_edid_detailed_timing_def *const *detailedTimings = di_edid_get_detailed_timing_defs(edid); + // detailedTimings is a null-terminated array. + for (int i = 0; detailedTimings[i] != nullptr; i++) { + const struct di_edid_detailed_timing_def *timing = detailedTimings[i]; + // Sanity check dimensions: physical aspect ratio should roughly equal + // mode aspect ratio (i.e. width_in_pixels / height_in_pixels). + // This assumes that the display has square pixels, but this is true for + // basically all modern displays. + if (timing->horiz_image_mm > 0 && timing->vert_image_mm > 0 + && timing->horiz_video > 0 && timing->vert_video > 0) { + const double physicalAspectRatio = double(timing->horiz_image_mm) / double(timing->vert_image_mm); + const double modeAspectRatio = double(timing->horiz_video) / double(timing->vert_video); + + if (std::abs(physicalAspectRatio - modeAspectRatio) <= 0.1) { + return QSize(timing->horiz_image_mm, timing->vert_image_mm); + } + } + } + const di_edid_screen_size *screenSize = di_edid_get_screen_size(edid); + return QSize(screenSize->width_cm, screenSize->height_cm) * 10; +} + Edid::Edid() { } @@ -110,10 +139,9 @@ Edid::Edid(const void *data, uint32_t size) } const di_edid *edid = di_info_get_edid(info); const di_edid_vendor_product *productInfo = di_edid_get_vendor_product(edid); - const di_edid_screen_size *screenSize = di_edid_get_screen_size(edid); // basic output information - m_physicalSize = QSize(screenSize->width_cm, screenSize->height_cm) * 10; + m_physicalSize = determineScreenPhysicalSizeMm(edid); m_eisaId = parseEisaId(bytes); UniqueCPtr monitorName{di_info_get_model(info)}; m_monitorName = QByteArray(monitorName.get());