info: add di_info_get_default_color_primaries()

Add a high-level function to retrieve color primaries. Wayland
compositors will be interested in this.

A high-level function may later be extended to support stand-alone
DisplayID and other sources.

The high-level data is derived from low-level API calls in
di_info_parse_edid(). As we stash the results in struct di_info to avoid
requiring the callers to explicitly free the high-level structures, this
allows keeping struct di_info deeply const in high-level API
implementation. We also avoid some dynamic allocations.

https://github.com/linuxhw/EDID.git database contains 20399 samples for
which edid-decode complains:
  Basic Display Parameters & Features: sRGB is signaled, but the chromaticities do not match.

Therefore I assume that the sRGB flag is more correct when set.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
This commit is contained in:
Pekka Paalanen 2023-07-05 16:20:56 +03:00
parent 7b4d87b2d2
commit 85043a07d5
3 changed files with 122 additions and 0 deletions

View file

@ -7,10 +7,20 @@
#include <libdisplay-info/info.h>
/**
* All information here is derived from low-level information contained in
* struct di_info. These are exposed by the high-level API only.
*/
struct di_derived_info {
struct di_color_primaries color_primaries;
};
struct di_info {
struct di_edid *edid;
char *failure_msg;
struct di_derived_info derived;
};
#endif

View file

@ -2,6 +2,7 @@
#define DI_INFO_H
#include <stddef.h>
#include <stdbool.h>
/**
* libdisplay-info's high-level API.
@ -102,4 +103,52 @@ di_info_get_model(const struct di_info *info);
char *
di_info_get_serial(const struct di_info *info);
/** CIE 1931 2-degree observer chromaticity coordinates */
struct di_chromaticity_cie1931 {
float x;
float y;
};
/** Display color primaries and default white point */
struct di_color_primaries {
/* Are primary[] given */
bool has_primaries;
/* Is default_white given */
bool has_default_white_point;
/* Chromaticities of the primaries in RGB order
*
* Either all values are given, or they are all zeroes.
*/
struct di_chromaticity_cie1931 primary[3];
/* Default white point chromaticity
*
* If non-zero, this should be the display white point when it has
* been reset to its factory defaults. Either both x and y are given,
* or they are both zero.
*/
struct di_chromaticity_cie1931 default_white;
};
/**
* Get display color primaries and default white point
*
* Get the parameters of the default RGB colorimetry mode which is always
* supported. Primaries for monochrome displays might be all zeroes.
*
* These primaries might not be display's physical primaries, but only the
* primaries of the default RGB colorimetry signal when using IT Video Format
* (ANSI/CTA-861-H, Section 5).
*
* The returned pointer is owned by the struct di_info passed in. It remains
* valid only as long as the di_info exists, and must not be freed by the
* caller.
*
* This function does not return NULL.
*/
const struct di_color_primaries *
di_info_get_default_color_primaries(const struct di_info *info);
#endif

63
info.c
View file

@ -11,6 +11,61 @@
const char *
pnp_id_table(const char *key);
static void
derive_edid_color_primaries(const struct di_edid *edid,
struct di_color_primaries *cc)
{
const struct di_edid_chromaticity_coords *cm;
const struct di_edid_misc_features *misc;
/* Trust the flag more than the fields. */
misc = di_edid_get_misc_features(edid);
if (misc->srgb_is_primary) {
/*
* https://www.w3.org/Graphics/Color/sRGB.html
* for lack of access to IEC 61966-2-1
*/
cc->primary[0].x = 0.640f; /* red */
cc->primary[0].y = 0.330f;
cc->primary[1].x = 0.300f; /* green */
cc->primary[1].y = 0.600f;
cc->primary[2].x = 0.150f; /* blue */
cc->primary[2].y = 0.060f;
cc->has_primaries = true;
cc->default_white.x = 0.3127f; /* D65 */
cc->default_white.y = 0.3290f;
cc->has_default_white_point = true;
return;
}
cm = di_edid_get_chromaticity_coords(edid);
/*
* Broken EDID might have only partial values.
* Require all values to report anything.
*/
if (cm->red_x > 0.0f &&
cm->red_y > 0.0f &&
cm->green_x > 0.0f &&
cm->green_y > 0.0f &&
cm->blue_x > 0.0f &&
cm->blue_y > 0.0f) {
cc->primary[0].x = cm->red_x;
cc->primary[0].y = cm->red_y;
cc->primary[1].x = cm->green_x;
cc->primary[1].y = cm->green_y;
cc->primary[2].x = cm->blue_x;
cc->primary[2].y = cm->blue_y;
cc->has_primaries = true;
}
if (cm->white_x > 0.0f && cm->white_y > 0.0f) {
cc->default_white.x = cm->white_x;
cc->default_white.y = cm->white_y;
cc->has_default_white_point = true;
}
}
struct di_info *
di_info_parse_edid(const void *data, size_t size)
{
@ -38,6 +93,8 @@ di_info_parse_edid(const void *data, size_t size)
else
free(failure_msg_str);
derive_edid_color_primaries(info->edid, &info->derived.color_primaries);
return info;
err_edid:
@ -194,3 +251,9 @@ di_info_get_serial(const struct di_info *info)
memory_stream_cleanup(&m);
return NULL;
}
const struct di_color_primaries *
di_info_get_default_color_primaries(const struct di_info *info)
{
return &info->derived.color_primaries;
}