This code was originally written by Soren Sandmann <sandm...@redhat.com> and was found here: http://people.gnome.org/~ssp/randr/edid-parse.c
The code has been in use in gnome-settings-daemon for a couple of years now and is used to generate an Auto-EDID ICC profile if the screen has not been profiled with a calibration device. This will be used by the CMS plugins in the future, and so it makes sense being common code in compositor-drm. --- src/compositor-drm.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index f39096e..e4a1919 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -136,11 +136,22 @@ struct drm_fb { void *map; }; +struct drm_color_Yxy { + double Y; + double x; + double y; +}; + struct drm_edid { char eisa_id[13]; char monitor_name[13]; char pnp_id[5]; char serial_number[13]; + struct drm_color_Yxy whitepoint; + struct drm_color_Yxy primary_red; + struct drm_color_Yxy primary_green; + struct drm_color_Yxy primary_blue; + double gamma; }; struct drm_output { @@ -1558,6 +1569,31 @@ edid_parse_string(const uint8_t *data, char text[]) #define EDID_OFFSET_SERIAL 0x0c static int +edid_get_bit(int in, int bit) +{ + return (in & (1 << bit)) >> bit; +} + +static int +edid_get_bits(int in, int begin, int end) +{ + int mask = (1 << (end - begin + 1)) - 1; + return (in >> begin) & mask; +} + +static double +edid_decode_fraction(int high, int low) +{ + double result = 0.0; + int i; + + high = (high << 2) | low; + for (i = 0; i < 10; ++i) + result += edid_get_bit(high, i) * pow(2, i - 10); + return result; +} + +static int edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length) { int i; @@ -1579,6 +1615,26 @@ edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length) edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1; edid->pnp_id[3] = '\0'; + /* get native gamma */ + if (data[0x17] == 0xff) + edid->gamma = -1.0; + else + edid->gamma = (data[0x17] + 100.0) / 100.0; + + /* get primaries and whitepoint */ + edid->primary_red.Y = 1.0f; + edid->primary_red.x = edid_decode_fraction(data[0x1b], edid_get_bits(data[0x19], 6, 7)); + edid->primary_red.y = edid_decode_fraction(data[0x1c], edid_get_bits(data[0x19], 5, 4)); + edid->primary_green.Y = 1.0f; + edid->primary_green.x = edid_decode_fraction(data[0x1d], edid_get_bits(data[0x19], 2, 3)); + edid->primary_green.y = edid_decode_fraction(data[0x1e], edid_get_bits(data[0x19], 0, 1)); + edid->primary_blue.Y = 1.0f; + edid->primary_blue.x = edid_decode_fraction(data[0x1f], edid_get_bits(data[0x1a], 6, 7)); + edid->primary_blue.y = edid_decode_fraction(data[0x20], edid_get_bits(data[0x1a], 4, 5)); + edid->whitepoint.Y = 1.0f; + edid->whitepoint.x = edid_decode_fraction(data[0x21], edid_get_bits(data[0x1a], 2, 3)); + edid->whitepoint.y = edid_decode_fraction(data[0x22], edid_get_bits(data[0x1a], 0, 1)); + /* maybe there isn't a ASCII serial number descriptor, so use this instead */ serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0]; serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100; -- 1.8.2.1 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel