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");

Reply via email to