From 519f3bfd50257cdc3fd391b528ae02fe03bbf29a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 11 Aug 2023 22:04:26 +0800 Subject: [PATCH] Monitor (macOS): test HDR support for external monitors --- src/detection/monitor/monitor_apple.m | 6 ++++-- src/util/edidHelper.c | 29 +++++++++++++++++++++++++++ src/util/edidHelper.h | 1 + 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/detection/monitor/monitor_apple.m b/src/detection/monitor/monitor_apple.m index 35a8d413c..8f931a98d 100644 --- a/src/detection/monitor/monitor_apple.m +++ b/src/detection/monitor/monitor_apple.m @@ -106,11 +106,13 @@ static const char* detectWithDdcci(FFlist* results) if (IOAVServiceCopyEDID(service, &edid) != KERN_SUCCESS) continue; - if (CFDataGetLength(edid) < 128) + uint32_t edidLength = (uint32_t) CFDataGetLength(edid); + if (edidLength == 0 || edidLength % 128 != 0) continue; uint32_t width, height; const uint8_t* edidData = CFDataGetBytePtr(edid); + ffEdidGetPhysicalResolution(edidData, &width, &height); if (width == 0 || height == 0) continue; @@ -120,7 +122,7 @@ static const char* detectWithDdcci(FFlist* results) ffStrbufInit(&display->name); ffEdidGetName(edidData, &display->name); ffEdidGetPhysicalSize(edidData, &display->physicalWidth, &display->physicalHeight); - display->hdrCompatible = false; + display->hdrCompatible = ffEdidGetHdrCompatible(edidData, edidLength); } return NULL; } diff --git a/src/util/edidHelper.c b/src/util/edidHelper.c index 3b44f3556..456d8c58b 100644 --- a/src/util/edidHelper.c +++ b/src/util/edidHelper.c @@ -49,3 +49,32 @@ void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* h *width = (((uint32_t) edid[68] & 0xF0) << 4) + edid[66]; *height = (((uint32_t) edid[68] & 0x0F) << 8) + edid[67]; } + +bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length) +{ + if (length <= 128) return false; + for (const uint8_t* cta = &edid[128]; cta < &edid[length]; cta += 128) + { + // https://en.wikipedia.org/wiki/Extended_Display_Identification_Data#CTA_EDID_Timing_Extension_Block + if (cta[0] != 0x02 /* CTA EDID */) continue; + if (cta[1] < 0x03 /* Version 3 */) continue; + const uint8_t offset = cta[2]; + if (offset <= 4) continue; + for (uint8_t i = 4; i < offset;) + { + uint8_t blkLen = cta[i] & 0x1f; + if (blkLen > 0) + { + uint8_t blkTag = (cta[i] & 0xe0) >> 5; + if (blkTag == 0x07 /* Extended Block Type Tag */) + { + uint8_t extendedTag = cta[i + 1]; + if (extendedTag == 6 /* HDR SMDB */ || extendedTag == 7 /* HDR DMDB */) + return true; + } + } + i += blkLen + 1; + } + } + return false; +} diff --git a/src/util/edidHelper.h b/src/util/edidHelper.h index 1c424e1f4..200926376 100644 --- a/src/util/edidHelper.h +++ b/src/util/edidHelper.h @@ -10,5 +10,6 @@ void ffEdidGetVendorAndModel(const uint8_t edid[128], FFstrbuf* result); bool ffEdidGetName(const uint8_t edid[128], FFstrbuf* name); void ffEdidGetPhysicalResolution(const uint8_t edid[128], uint32_t* width, uint32_t* height); void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* height); // in mm +bool ffEdidGetHdrCompatible(const uint8_t edid[128], uint32_t length); #endif