This is an automatic generated email to let you know that the following patch were queued:
Subject: edid-decode: add support for DisplayID 2.1a Author: Hans Verkuil <hverkuil-ci...@xs4all.nl> Date: Wed Jul 3 13:25:28 2024 +0200 Add the new features from 2.1a. Mostly improved checks when data blocks should be included or not. The main addition is the new Brightness Luminance Range Data Block. Signed-off-by: Hans Verkuil <hverkuil-ci...@xs4all.nl> edid-decode.1 | 2 +- edid-decode.h | 19 ++++++++++- parse-base-block.cpp | 8 +++-- parse-displayid-block.cpp | 83 ++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 99 insertions(+), 13 deletions(-) --- diff --git a/edid-decode.1 b/edid-decode.1 index 2f5c4fe781ef..3bf4988be3b4 100644 --- a/edid-decode.1 +++ b/edid-decode.1 @@ -117,7 +117,7 @@ EDID 1.4: VESA Enhanced Extended Display Identication Data Standard, Release A, .TP DisplayID 1.3: VESA Display Identification Data (DisplayID) Standard, Version 1.3 .TP -DisplayID 2.1: VESA DisplayID Standard, Version 2.1 +DisplayID 2.1a: VESA DisplayID Standard, Version 2.1a .TP DI-EXT: VESA Display Information Extension Block Standard, Release A .TP diff --git a/edid-decode.h b/edid-decode.h index 126647cd8a5b..0a06b17a2122 100644 --- a/edid-decode.h +++ b/edid-decode.h @@ -144,6 +144,11 @@ struct edid_state { dtd_max_vsize_mm = dtd_max_hsize_mm = 0; warnings = failures = 0; has_cta = has_dispid = false; + // Note: for now we do not support native DisplayID data, + // so this is always false. But some tests are different + // depending on whether it is a native DisplayID structure + // or an extension block, so they can use this bool. + native_dispid = false; hide_serial_numbers = false; replace_unique_ids = false; image_width = image_height = diagonal = 0; @@ -206,7 +211,10 @@ struct edid_state { dispid.is_base_block = true; dispid.is_display = dispid.has_product_identification = dispid.has_display_parameters = dispid.has_type_1_7 = - dispid.has_display_interface_features = false; + dispid.has_display_interface_features = + dispid.has_tiled_display_topology = dispid.has_ycbcr_420 = + dispid.is_arvr = dispid.has_arvr_hdm = dispid.has_arvr_layer = + dispid.has_stereo = dispid.has_stereo_display_interface = false; dispid.block_number = 0; dispid.image_width = dispid.image_height = 0; @@ -224,6 +232,7 @@ struct edid_state { unsigned unused_bytes; bool has_cta; bool has_dispid; + bool native_dispid; bool hide_serial_numbers; bool replace_unique_ids; std::vector<std::string> serial_strings; @@ -334,10 +343,17 @@ struct edid_state { unsigned preparsed_displayid_blocks; bool is_base_block; bool is_display; + bool is_arvr; bool has_product_identification; bool has_display_parameters; bool has_type_1_7; bool has_display_interface_features; + bool has_tiled_display_topology; + bool has_stereo_display_interface; + bool has_arvr_hdm; + bool has_arvr_layer; + bool has_ycbcr_420; + bool has_stereo; vec_timings_ext preferred_timings; unsigned native_width, native_height; // in 0.1 mm units @@ -467,6 +483,7 @@ struct edid_state { void parse_displayid_adaptive_sync(const unsigned char *x); void parse_displayid_arvr_hmd(const unsigned char *x); void parse_displayid_arvr_layer(const unsigned char *x); + void parse_displayid_brightness_lum_range(const unsigned char *x); void parse_displayid_type_10_timing(const unsigned char *x, unsigned sz, bool is_cta = false); void preparse_displayid_block(unsigned char *x); diff --git a/parse-base-block.cpp b/parse-base-block.cpp index 26cebb3c2344..5644e72999c9 100644 --- a/parse-base-block.cpp +++ b/parse-base-block.cpp @@ -1432,8 +1432,12 @@ void edid_state::parse_base_block(const unsigned char *x) printf(" Manufacturer: %s\n Model: %u\n", manufacturer, (unsigned short)(x[0x0a] + (x[0x0b] << 8))); - if (!strcmp(manufacturer, "CID") && !cta.has_pidb) - fail("Manufacturer name is set to CID, but there is no CTA-861 Product Information Data Block.\n"); + if (!strcmp(manufacturer, "CID")) { + if (has_cta && !cta.has_pidb) + fail("Manufacturer name is set to CID, but there is no CTA-861 Product Information Data Block.\n"); + if (has_dispid && !has_cta && !dispid.has_product_identification) + fail("Manufacturer name is set to CID, but there is no DisplayID Product Identification Data Block.\n"); + } if (base.serial_number) { unsigned sn = base.serial_number; diff --git a/parse-displayid-block.cpp b/parse-displayid-block.cpp index 2f68a0ed76c5..54a691be0cb0 100644 --- a/parse-displayid-block.cpp +++ b/parse-displayid-block.cpp @@ -309,17 +309,21 @@ void edid_state::parse_displayid_type_1_7_timing(const unsigned char *x, break; case 1: s += ", 3D stereo"; + dispid.has_stereo = true; break; case 2: s += ", 3D stereo depends on user action"; + dispid.has_stereo = true; break; case 3: s += ", reserved"; fail("Reserved stereo 0x03.\n"); break; } - if (block_rev >= 2 && (x[3] & 0x80)) + if (block_rev >= 2 && (x[3] & 0x80)) { s += ", YCbCr 4:2:0"; + dispid.has_ycbcr_420 = true; + } t.hact = 1 + (x[4] | (x[5] << 8)); hbl = 1 + (x[6] | (x[7] << 8)); @@ -418,9 +422,11 @@ void edid_state::parse_displayid_type_2_timing(const unsigned char *x) break; case 1: s += ", 3D stereo"; + dispid.has_stereo = true; break; case 2: s += ", 3D stereo depends on user action"; + dispid.has_stereo = true; break; case 3: s += ", reserved"; @@ -850,6 +856,8 @@ void edid_state::parse_displayid_display_intf(const unsigned char *x) void edid_state::parse_displayid_stereo_display_intf(const unsigned char *x) { + dispid.has_stereo_display_interface = true; + check_displayid_datablock_revision(x[1], 0xc0, 1); switch (x[1] >> 6) { @@ -956,9 +964,11 @@ void edid_state::parse_displayid_type_5_timing(const unsigned char *x) break; case 1: s += ", 3D stereo"; + dispid.has_stereo = true; break; case 2: s += ", 3D stereo depends on user action"; + dispid.has_stereo = true; break; case 3: s += ", reserved"; @@ -993,6 +1003,8 @@ void edid_state::parse_displayid_tiled_display_topology(const unsigned char *x, if (!check_displayid_datablock_length(x, 22, 22)) return; + dispid.has_tiled_display_topology = true; + unsigned caps = x[3]; unsigned num_v_tile = (x[4] & 0xf) | (x[6] & 0x30); unsigned num_h_tile = (x[4] >> 4) | ((x[6] >> 2) & 0x30); @@ -1106,9 +1118,11 @@ void edid_state::parse_displayid_type_6_timing(const unsigned char *x) break; case 1: s += ", 3D stereo"; + dispid.has_stereo = true; break; case 2: s += ", 3D stereo depends on user action"; + dispid.has_stereo = true; break; case 3: s += ", reserved"; @@ -1253,9 +1267,11 @@ void edid_state::parse_displayid_type_9_timing(const unsigned char *x) break; case 1: s += ", 3D stereo"; + dispid.has_stereo = true; break; case 2: s += ", 3D stereo depends on user action"; + dispid.has_stereo = true; break; case 3: s += ", reserved"; @@ -1452,9 +1468,14 @@ void edid_state::parse_displayid_adaptive_sync(const unsigned char *x) void edid_state::parse_displayid_arvr_hmd(const unsigned char *x) { - check_displayid_datablock_revision(x[1]); + dispid.has_arvr_hdm = true; + + if (!native_dispid && dispid.is_arvr) + fail("Not allowed for DisplayID Extension Blocks.\n"); + + check_displayid_datablock_revision(x[1], 1); - if (!check_displayid_datablock_length(x, 77, 77)) + if (!check_displayid_datablock_length(x, 79, 79)) return; // TODO: parse the DB @@ -1464,14 +1485,40 @@ void edid_state::parse_displayid_arvr_hmd(const unsigned char *x) void edid_state::parse_displayid_arvr_layer(const unsigned char *x) { - check_displayid_datablock_revision(x[1]); + dispid.has_arvr_layer = true; + + if (!native_dispid && dispid.is_arvr) + fail("Not allowed for DisplayID Extension Blocks.\n"); + + check_displayid_datablock_revision(x[1], 1); - if (!check_displayid_datablock_length(x, 25, 25)) + if (!check_displayid_datablock_length(x, 20, 20)) return; // TODO: parse the DB } +// tag 0x2e + +void edid_state::parse_displayid_brightness_lum_range(const unsigned char *x) +{ + check_displayid_datablock_revision(x[1]); + + if (!check_displayid_datablock_length(x, 6, 6)) + return; + + printf(" Minimum SDR Luminance (Full Coverage): %s\n", + ieee7542d(x[3] | (x[4] << 8)).c_str()); + // TODO: test that this is > Native Minimum Luminance from Display Params DB + printf(" Maximum Suggested SDR Luminance (Full Coverage): %s\n", + ieee7542d(x[5] | (x[6] << 8)).c_str()); + // TODO: test that this is > Native Minimum Luminance from Display Params DB + // and <= Native Maximum Luminance (Full Coverage) in same DB. + printf(" Maximum Boost SDR Luminance: %s\n", + ieee7542d(x[5] | (x[6] << 8)).c_str()); + // TODO: test that this is >= the previous value +} + // tag 0x32 void edid_state::parse_displayid_type_10_timing(const unsigned char *x, @@ -1492,9 +1539,11 @@ void edid_state::parse_displayid_type_10_timing(const unsigned char *x, break; case 1: s += ", 3D stereo"; + dispid.has_stereo = true; break; case 2: s += ", 3D stereo depends on user action"; + dispid.has_stereo = true; break; case 3: s += ", reserved"; @@ -1528,8 +1577,10 @@ void edid_state::parse_displayid_type_10_timing(const unsigned char *x, fail("VR_HB must be 0.\n"); } } - if (x[0] & 0x80) + if (x[0] & 0x80) { s += ", YCbCr 4:2:0"; + dispid.has_ycbcr_420 = true; + } if (x[0] & 0x08) { if (rb == RB_CVT_V3) { @@ -1692,6 +1743,7 @@ std::string edid_state::product_type(unsigned char x, bool heading) headingstr = "Display Product Primary Use Case"; if (heading) return headingstr; dispid.is_display = x >= 2 && x <= 8; + dispid.is_arvr = x >= 7 && x <= 8; switch (x) { case 0: return "Same primary use case as the base section"; case 1: return "Test Structure; test equipment only"; @@ -1846,6 +1898,7 @@ unsigned edid_state::displayid_block(const unsigned version, const unsigned char case 0x2b: data_block = "Adaptive Sync Data Block"; break; case 0x2c: data_block = "ARVR_HMD Data Block"; break; case 0x2d: data_block = "ARVR_Layer Data Block"; break; + case 0x2e: data_block = "Brightness Luminance Range Data Block"; break; case 0x32: data_block = "Video Timing Modes Type 10 - Formula-based Timings Data Block"; break; // 0x2a .. 0x7d RESERVED for Additional VESA-defined Data Blocks case 0x7e: // DisplayID 2.0 @@ -2024,10 +2077,14 @@ unsigned edid_state::displayid_block(const unsigned version, const unsigned char case 0x2b: parse_displayid_adaptive_sync(x); break; case 0x2c: parse_displayid_arvr_hmd(x); break; case 0x2d: parse_displayid_arvr_layer(x); break; + case 0x2e: parse_displayid_brightness_lum_range(x); break; case 0x32: { unsigned sz = 6 + ((x[1] & 0x70) >> 4); check_displayid_datablock_revision(x[1], 0x70); + if (sz > 8) + fail("Invalid descriptor size %u.\n", sz); + for (i = 0; i < len / sz; i++) parse_displayid_type_10_timing(&x[3 + i * sz], sz); break; @@ -2109,12 +2166,20 @@ void edid_state::parse_displayid_block(const unsigned char *x) void edid_state::check_displayid_blocks() { data_block = "DisplayID"; - if (!dispid.has_product_identification) + if (!dispid.has_product_identification && + (native_dispid || dispid.has_tiled_display_topology)) fail("Missing DisplayID Product Identification Data Block.\n"); - if (dispid.is_display && !dispid.has_display_parameters) + if (dispid.is_display && (native_dispid || !dispid.has_display_parameters)) fail("Missing DisplayID Display Parameters Data Block.\n"); - if (dispid.is_display && !dispid.has_display_interface_features) + if (dispid.is_display && !dispid.has_display_interface_features && + (native_dispid || dispid.has_ycbcr_420)) fail("Missing DisplayID Display Interface Features Data Block.\n"); + if (native_dispid && dispid.is_arvr && !dispid.has_arvr_hdm) + fail("Missing DisplayID ARVR_HMD Data Block.\n"); + if (native_dispid && dispid.is_arvr && !dispid.has_arvr_layer) + fail("Missing DisplayID ARVR_Layer Data Block.\n"); + if (dispid.has_stereo && !dispid.has_stereo_display_interface) + fail("Missing DisplayID Stereo Display Interface Data Block.\n"); if (dispid.is_display && !dispid.has_type_1_7) fail("Missing DisplayID Type %s Detailed Timing Data Block.\n", dispid.version >= 0x20 ? "VII" : "I");