diff --git a/cta.c b/cta.c index 5714671..ef30301 100644 --- a/cta.c +++ b/cta.c @@ -214,6 +214,29 @@ parse_hdr_static_metadata_block(struct di_edid_cta *cta, return true; } +static bool +parse_vesa_transfer_characteristics_block(struct di_edid_cta *cta, + struct di_cta_vesa_transfer_characteristics *tf, + const uint8_t *data, size_t size) +{ + size_t i; + + if (size != 7 && size != 15 && size != 31) { + add_failure(cta, "Invalid length %u.", size); + return false; + } + + tf->points_len = (uint8_t) size + 1; + tf->usage = get_bit_range(data[0], 7, 6); + + tf->points[0] = get_bit_range(data[0], 5, 0) / 1023.0f; + for (i = 1; i < size; i++) + tf->points[i] = tf->points[i - 1] + data[i] / 1023.0f; + tf->points[i] = 1.0f; + + return true; +} + static void destroy_data_block(struct di_cta_data_block *data_block) { @@ -262,6 +285,10 @@ parse_data_block(struct di_edid_cta *cta, uint8_t raw_tag, const uint8_t *data, break; case 5: tag = DI_CTA_DATA_BLOCK_VESA_DISPLAY_TRANSFER_CHARACTERISTIC; + if (!parse_vesa_transfer_characteristics_block(cta, + &data_block->vesa_transfer_characteristics, + data, size)) + goto error; break; case 7: /* Use Extended Tag */ @@ -536,3 +563,12 @@ di_edid_cta_get_detailed_timing_defs(const struct di_edid_cta *cta) { return (const struct di_edid_detailed_timing_def *const *) cta->detailed_timing_defs; } + +const struct di_cta_vesa_transfer_characteristics * +di_cta_data_block_get_vesa_transfer_characteristics(const struct di_cta_data_block *block) +{ + if (block->tag != DI_CTA_DATA_BLOCK_VESA_DISPLAY_TRANSFER_CHARACTERISTIC) { + return NULL; + } + return &block->vesa_transfer_characteristics; +} diff --git a/di-edid-decode.c b/di-edid-decode.c index 1324dc8..553a8ea 100644 --- a/di-edid-decode.c +++ b/di-edid-decode.c @@ -14,6 +14,7 @@ static struct { bool color_point_descriptor; bool color_management_data; + bool cta_transfer_characteristics; } contains_uncommon_feature; static size_t num_detailed_timing_defs = 0; @@ -703,6 +704,34 @@ print_cta_hdr_static_metadata(const struct di_cta_hdr_static_metadata_block *met metadata->desired_content_min_luminance); } +static void +print_cta_vesa_transfer_characteristics(const struct di_cta_vesa_transfer_characteristics *tf) +{ + size_t i; + + switch (tf->usage) { + case DI_CTA_VESA_TRANSFER_CHARACTERISTIC_USAGE_WHITE: + printf(" White"); + break; + case DI_CTA_VESA_TRANSFER_CHARACTERISTIC_USAGE_RED: + printf(" Red"); + break; + case DI_CTA_VESA_TRANSFER_CHARACTERISTIC_USAGE_GREEN: + printf(" Green"); + break; + case DI_CTA_VESA_TRANSFER_CHARACTERISTIC_USAGE_BLUE: + printf(" Blue"); + break; + } + + printf(" transfer characteristics:"); + for (i = 0; i < tf->points_len; i++) + printf(" %u", (uint16_t) (tf->points[i] * 1023.0f)); + printf("\n"); + + contains_uncommon_feature.cta_transfer_characteristics = true; +} + static const char * cta_data_block_tag_name(enum di_cta_data_block_tag tag) { @@ -781,6 +810,7 @@ print_cta(const struct di_edid_cta *cta) const struct di_cta_video_cap_block *video_cap; const struct di_cta_colorimetry_block *colorimetry; const struct di_cta_hdr_static_metadata_block *hdr_static_metadata; + const struct di_cta_vesa_transfer_characteristics *transfer_characteristics; size_t i; const struct di_edid_detailed_timing_def *const *detailed_timing_defs; @@ -858,6 +888,10 @@ print_cta(const struct di_edid_cta *cta) hdr_static_metadata = di_cta_data_block_get_hdr_static_metadata(data_block); print_cta_hdr_static_metadata(hdr_static_metadata); break; + case DI_CTA_DATA_BLOCK_VESA_DISPLAY_TRANSFER_CHARACTERISTIC: + transfer_characteristics = di_cta_data_block_get_vesa_transfer_characteristics(data_block); + print_cta_vesa_transfer_characteristics(transfer_characteristics); + break; default: break; /* Ignore */ } @@ -1312,6 +1346,11 @@ main(int argc, char *argv[]) "Management Data Descriptor. Please share the " "EDID blob with upstream!\n"); } + if (contains_uncommon_feature.cta_transfer_characteristics) { + fprintf(stderr, "The EDID blob contains an uncommon CTA VESA " + "Display Transfer Characteristic data block. " + "Please share the EDID blob with upstream!\n"); + } di_info_destroy(info); return failure_msg ? 254 : 0; diff --git a/include/cta.h b/include/cta.h index 30d3ef0..80d6eea 100644 --- a/include/cta.h +++ b/include/cta.h @@ -72,6 +72,8 @@ struct di_cta_data_block { struct di_cta_colorimetry_block colorimetry; /* Used for DI_CTA_DATA_BLOCK_HDR_STATIC_METADATA */ struct di_cta_hdr_static_metadata_block_priv hdr_static_metadata; + /* Used for DI_CTA_DATA_BLOCK_VESA_DISPLAY_TRANSFER_CHARACTERISTIC */ + struct di_cta_vesa_transfer_characteristics vesa_transfer_characteristics; }; bool diff --git a/include/libdisplay-info/cta.h b/include/libdisplay-info/cta.h index 5d0a5a5..4fd8c94 100644 --- a/include/libdisplay-info/cta.h +++ b/include/libdisplay-info/cta.h @@ -259,6 +259,44 @@ struct di_cta_svd { const struct di_cta_svd *const * di_cta_data_block_get_svds(const struct di_cta_data_block *block); +enum di_cta_vesa_transfer_characteristics_usage { + /* White transfer characteristic */ + DI_CTA_VESA_TRANSFER_CHARACTERISTIC_USAGE_WHITE = 0, + /* Red transfer characteristic */ + DI_CTA_VESA_TRANSFER_CHARACTERISTIC_USAGE_RED = 1, + /* Green transfer characteristic */ + DI_CTA_VESA_TRANSFER_CHARACTERISTIC_USAGE_GREEN = 2, + /* Blue transfer characteristic */ + DI_CTA_VESA_TRANSFER_CHARACTERISTIC_USAGE_BLUE = 3, +}; + +/** + * VESA Display Transfer Characteristic Data Block, defined in VESA Display + * Transfer Characteristics Data Block Standard Version 1.0 + * + * Contains 8, 16 or 32 evenly distributed points on the input axis describing + * the normalized relative luminance at that input. The first value includes the + * relative black level luminance. + */ +struct di_cta_vesa_transfer_characteristics { + enum di_cta_vesa_transfer_characteristics_usage usage; + uint8_t points_len; + float points[32]; +}; + +/** + * Get the Display Transfer Characteristic from a CTA data block. + * + * Returns NULL if the data block tag is not + * DI_CTA_DATA_BLOCK_VESA_DISPLAY_TRANSFER_CHARACTERISTIC. + * + * Upstream is not aware of any EDID blob containing a Display Transfer + * Characteristic data block. + * If such a blob is found, please share it with upstream! + */ +const struct di_cta_vesa_transfer_characteristics * +di_cta_data_block_get_vesa_transfer_characteristics(const struct di_cta_data_block *block); + /** * Get a list of EDID detailed timing definitions. *