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

Reply via email to