diff --git a/di-edid-decode.c b/di-edid-decode.c index 5acd02b..525bcf2 100644 --- a/di-edid-decode.c +++ b/di-edid-decode.c @@ -932,6 +932,39 @@ print_cta(const struct di_edid_cta *cta) } } +static void +print_displayid_display_params(const struct di_displayid_display_params *params) +{ + printf(" Image size: %.1f mm x %.1f mm\n", + params->horiz_image_mm, params->vert_image_mm); + printf(" Display native pixel format: %dx%d\n", + params->horiz_pixels, params->vert_pixels); + + printf(" Feature support flags:\n"); + if (params->features->audio) + printf(" Audio support on video interface\n"); + if (params->features->separate_audio_inputs) + printf(" Separate audio inputs provided\n"); + if (params->features->audio_input_override) + printf(" Audio input override\n"); + if (params->features->power_management) + printf(" Power management (DPM)\n"); + if (params->features->fixed_timing) + printf(" Fixed timing\n"); + if (params->features->fixed_pixel_format) + printf(" Fixed pixel format\n"); + if (params->features->ai) + printf(" Support ACP, ISRC1, or ISRC2packets\n"); + if (params->features->deinterlacing) + printf(" De-interlacing\n"); + + if (params->gamma != 0) + printf(" Gamma: %.2f\n", params->gamma); + printf(" Aspect ratio: %.2f\n", params->aspect_ratio); + printf(" Dynamic bpc native: %d\n", params->bits_per_color_native); + printf(" Dynamic bpc overall: %d\n", params->bits_per_color_overall); +} + static void get_displayid_type_i_timing_aspect_ratio(enum di_displayid_type_i_timing_aspect_ratio ratio, int *horiz, int *vert) @@ -1135,6 +1168,7 @@ print_displayid(const struct di_displayid *displayid) const struct di_displayid_data_block *data_block; enum di_displayid_data_block_tag tag; size_t i; + const struct di_displayid_display_params *display_params; printf(" Version: %d.%d\n", di_displayid_get_version(displayid), di_displayid_get_revision(displayid)); @@ -1150,6 +1184,10 @@ print_displayid(const struct di_displayid *displayid) tag = di_displayid_data_block_get_tag(data_block); printf(" %s:\n", displayid_data_block_tag_name(tag)); switch (tag) { + case DI_DISPLAYID_DATA_BLOCK_DISPLAY_PARAMS: + display_params = di_displayid_data_block_get_display_params(data_block); + print_displayid_display_params(display_params); + break; case DI_DISPLAYID_DATA_BLOCK_TYPE_I_TIMING: print_displayid_type_i_timing_block(data_block); break; diff --git a/displayid.c b/displayid.c index aed173c..6b6bfa5 100644 --- a/displayid.c +++ b/displayid.c @@ -53,6 +53,49 @@ check_data_block_revision(struct di_displayid *displayid, } } +static bool +parse_display_params_block(struct di_displayid *displayid, + struct di_displayid_display_params_priv *priv, + const uint8_t *data, size_t size) +{ + struct di_displayid_display_params *params = &priv->base; + uint8_t raw_features; + + check_data_block_revision(displayid, data, + "Display Parameters Data Block", + 0); + + if (size != 0x0F) { + add_failure(displayid, "Display Parameters Data Block: DisplayID payload length is different than expected (%zu != %zu)", size, 0x0F); + return false; + } + + params->horiz_image_mm = 0.1f * (float)(data[0x03] | (data[0x04] << 8)); + params->vert_image_mm = 0.1f * (float)(data[0x05] | (data[0x06] << 8)); + + params->horiz_pixels = data[0x07] | (data[0x08] << 8); + params->vert_pixels = data[0x09] | (data[0x0A] << 8); + + raw_features = data[0x0B]; + params->features = &priv->features; + priv->features.audio = has_bit(raw_features, 7); + priv->features.separate_audio_inputs = has_bit(raw_features, 6); + priv->features.audio_input_override = has_bit(raw_features, 5); + priv->features.power_management = has_bit(raw_features, 4); + priv->features.fixed_timing = has_bit(raw_features, 3); + priv->features.fixed_pixel_format = has_bit(raw_features, 2); + priv->features.ai = has_bit(raw_features, 1); + priv->features.deinterlacing = has_bit(raw_features, 0); + + if (data[0x0C] != 0xFF) + params->gamma = (float)data[0x0C] / 100 + 1; + params->aspect_ratio = (float)data[0x0D] / 100 + 1; + params->bits_per_color_overall = get_bit_range(data[0x0E], 7, 4) + 1; + params->bits_per_color_native = get_bit_range(data[0x0E], 3, 0) + 1; + + return true; +} + static bool parse_type_i_timing(struct di_displayid *displayid, struct di_displayid_data_block *data_block, @@ -174,12 +217,17 @@ parse_data_block(struct di_displayid *displayid, const uint8_t *data, goto error; switch (tag) { + case DI_DISPLAYID_DATA_BLOCK_DISPLAY_PARAMS: + if (!parse_display_params_block(displayid, + &data_block->display_params, + data, data_block_size)) + goto error; + break; case DI_DISPLAYID_DATA_BLOCK_TYPE_I_TIMING: if (!parse_type_i_timing_block(displayid, data_block, data, data_block_size)) goto error; break; case DI_DISPLAYID_DATA_BLOCK_PRODUCT_ID: - case DI_DISPLAYID_DATA_BLOCK_DISPLAY_PARAMS: case DI_DISPLAYID_DATA_BLOCK_COLOR_CHARACT: case DI_DISPLAYID_DATA_BLOCK_TYPE_II_TIMING: case DI_DISPLAYID_DATA_BLOCK_TYPE_III_TIMING: @@ -381,6 +429,15 @@ di_displayid_data_block_get_tag(const struct di_displayid_data_block *data_block return data_block->tag; } +const struct di_displayid_display_params * +di_displayid_data_block_get_display_params(const struct di_displayid_data_block *data_block) +{ + if (data_block->tag != DI_DISPLAYID_DATA_BLOCK_DISPLAY_PARAMS) { + return NULL; + } + return &data_block->display_params.base; +} + const struct di_displayid_type_i_timing *const * di_displayid_data_block_get_type_i_timings(const struct di_displayid_data_block *data_block) { diff --git a/include/displayid.h b/include/displayid.h index 489bb75..b03720c 100644 --- a/include/displayid.h +++ b/include/displayid.h @@ -38,12 +38,20 @@ struct di_displayid { struct di_logger *logger; }; +struct di_displayid_display_params_priv { + struct di_displayid_display_params base; + struct di_displayid_display_params_features features; +}; + struct di_displayid_data_block { enum di_displayid_data_block_tag tag; /* Used for TYPE_I_TIMING, NULL-terminated */ struct di_displayid_type_i_timing *type_i_timings[DISPLAYID_MAX_TYPE_I_TIMINGS + 1]; size_t type_i_timings_len; + + /* Used for DISPLAY_PARAMS */ + struct di_displayid_display_params_priv display_params; }; bool diff --git a/include/libdisplay-info/displayid.h b/include/libdisplay-info/displayid.h index decd16b..5d782c5 100644 --- a/include/libdisplay-info/displayid.h +++ b/include/libdisplay-info/displayid.h @@ -109,6 +109,57 @@ struct di_displayid_data_block; enum di_displayid_data_block_tag di_displayid_data_block_get_tag(const struct di_displayid_data_block *data_block); +/** + * Display parameters feature support flags, defined in section 4.2.3. + */ +struct di_displayid_display_params_features { + /* Audio support on video interface */ + bool audio; + /* Audio inputs are provided separately from the video interface */ + bool separate_audio_inputs; + /* Audio information received via the video interface will automatically + * override any other audio input channels provided */ + bool audio_input_override; + /* Display supports the VESA Display Power Management (DPM) standard */ + bool power_management; + /* Display is capable of only a single fixed timing */ + bool fixed_timing; + /* Display is capable of supporting timings at only a single fixed pixel + * format */ + bool fixed_pixel_format; + /* Display supports ACP, ISRC1 or ISRC2 packets */ + bool ai; + /* Display by default will de-interlace any interlaced video input */ + bool deinterlacing; +}; + +/** + * Display parameters data block, defined in section 4.2. + */ +struct di_displayid_display_params { + /* Image size in millimeters accurate to the thenths place, zero if unset */ + float horiz_image_mm, vert_image_mm; + /* Native format size in pixels, zero if unset */ + int32_t horiz_pixels, vert_pixels; + /* Feature flags */ + const struct di_displayid_display_params_features *features; + /* Transfer characteristic gamma, zero if unset */ + float gamma; + /* Aspect ratio (long axis divided by short axis) */ + float aspect_ratio; + /* Color bit depth (dynamic range) */ + int32_t bits_per_color_overall, bits_per_color_native; +}; + +/** + * Get display parameters from a DisplayID data block. + * + * Returns NULL if the data block tag isn't + * DI_DISPLAYID_DATA_BLOCK_DISPLAY_PARAMS. + */ +const struct di_displayid_display_params * +di_displayid_data_block_get_display_params(const struct di_displayid_data_block *data_block); + enum di_displayid_type_i_timing_stereo_3d { /* This timing is always displayed monoscopic (no stereo) */ DI_DISPLAYID_TYPE_I_TIMING_STEREO_3D_NEVER = 0x00, diff --git a/test/data/apple-xdr-dp.diff b/test/data/apple-xdr-dp.diff index a059146..cea7e0c 100644 --- a/test/data/apple-xdr-dp.diff +++ b/test/data/apple-xdr-dp.diff @@ -1,6 +1,6 @@ --- ref +++ di -@@ -62,44 +62,15 @@ +@@ -62,16 +62,13 @@ DTD 6: 3840x2160 47.951737 Hz 16:9 134.696 kHz 528.010000 MHz (699 mm x 393 mm) Hfront 8 Hsync 32 Hback 40 Hpol P Vfront 59 Vsync 8 Vback 582 Vpol N @@ -16,14 +16,12 @@ - ContainerID Data Block: - Container ID: dfde542f-1339-444b-ad7d-7071d131bff8 Display Parameters Data Block (0x01): -- Image size: 699.4 mm x 393.4 mm -- Display native pixel format: 6016x3384 -- Feature support flags: -- Power management (DPM) -- Gamma: 2.20 -- Aspect ratio: 1.78 -- Dynamic bpc native: 12 -- Dynamic bpc overall: 12 + Image size: 699.4 mm x 393.4 mm + Display native pixel format: 6016x3384 +@@ -81,25 +78,7 @@ + Aspect ratio: 1.78 + Dynamic bpc native: 12 + Dynamic bpc overall: 12 - Vendor-Specific Data Block (0x7f) (Apple), OUI 00-10-FA: - Type: 4, Version: 1 - 00 00 '..' @@ -46,7 +44,7 @@ Video Timing Modes Type 1 - Detailed Timings Data Block: DTD: 3840x2160 59.999545 Hz 16:9 134.699 kHz 528.020000 MHz (aspect 16:9, no 3D stereo) Hfront 8 Hsync 32 Hback 40 Hpol P -@@ -107,14 +78,12 @@ +@@ -107,14 +86,12 @@ DTD: 3008x3384 59.999726 Hz 0:0 210.959 kHz 648.910000 MHz (aspect undefined, no 3D stereo) Hfront 8 Hsync 32 Hback 28 Hpol P Vfront 118 Vsync 8 Vback 6 Vpol N @@ -61,7 +59,7 @@ Video Timing Modes Type 1 - Detailed Timings Data Block: DTD: 2560x2880 59.999451 Hz 0:0 179.578 kHz 481.270000 MHz (aspect undefined, no 3D stereo) Hfront 8 Hsync 32 Hback 80 Hpol P -@@ -131,14 +100,12 @@ +@@ -131,14 +108,12 @@ DTD: 2560x2880 47.951349 Hz 0:0 179.530 kHz 481.140000 MHz (aspect undefined, no 3D stereo) Hfront 8 Hsync 32 Hback 80 Hpol P Vfront 850 Vsync 8 Vback 6 Vpol N @@ -76,7 +74,7 @@ Video Timing Modes Type 1 - Detailed Timings Data Block: DTD: 3008x3384 59.999726 Hz 0:0 210.959 kHz 648.910000 MHz (aspect undefined, no 3D stereo) Hfront 8 Hsync 32 Hback 28 Hpol P -@@ -155,14 +122,12 @@ +@@ -155,14 +130,12 @@ DTD: 3008x3384 47.951701 Hz 0:0 210.940 kHz 648.850000 MHz (aspect undefined, no 3D stereo) Hfront 8 Hsync 32 Hback 28 Hpol P Vfront 1001 Vsync 8 Vback 6 Vpol N @@ -91,7 +89,7 @@ Video Timing Modes Type 1 - Detailed Timings Data Block: DTD: 5120x2880 59.999614 Hz 16:9 179.579 kHz 933.810000 MHz (aspect 16:9, no 3D stereo) Hfront 8 Hsync 32 Hback 40 Hpol P -@@ -179,16 +144,14 @@ +@@ -179,16 +152,14 @@ DTD: 5120x2880 47.951594 Hz 16:9 179.531 kHz 933.560000 MHz (aspect 16:9, no 3D stereo) Hfront 8 Hsync 32 Hback 40 Hpol P Vfront 850 Vsync 8 Vback 6 Vpol N @@ -109,7 +107,7 @@ Hfront 8 Hsync 32 Hback 40 Hpol P Vfront 118 Vsync 8 Vback 6 Vpol N DTD: 6016x3384 59.939891 Hz 16:9 210.928 kHz 1285.820000 MHz (aspect 16:9, no 3D stereo) -@@ -203,30 +166,13 @@ +@@ -203,30 +174,13 @@ DTD: 6016x3384 47.951798 Hz 16:9 210.940 kHz 1285.890000 MHz (aspect 16:9, no 3D stereo) Hfront 8 Hsync 32 Hback 40 Hpol P Vfront 1001 Vsync 8 Vback 6 Vpol N