Add gamma support to ply-image.

BUG=chromium-os:10138
TEST=Run chrome os with a color profile, check that it gets loaded (I use a profile with one of the components zeroed for testing so changes are obvious).

Review URL: http://codereview.chromium.org/6877024

Change-Id: I328c32c30e7e73080895b0344bdcc354a6ad7053
diff --git a/src/Makefile b/src/Makefile
index 27f3acd..ce85b09 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,9 +1,11 @@
 C = ply-image.c \
     ply-frame-buffer.c \
+    ply-gamma.c \
     ply-list.c \
 
 
 H = ply-frame-buffer.h \
+    ply-gamma.h \
     ply-image.h \
     ply-list.h \
     ply-utils.h \
@@ -12,7 +14,7 @@
 
 ply-image: $(C) $(H) Makefile
 	$(CC) $(CFLAGS) $(C) $(LIBS) -Wall -I. -o ply-image -o ply-image \
-		-lpng -lrt -lm
+		-lpng -lrt -lm `pkg-config --libs --cflags libdrm`
 
 clean:
 	rm -f ply-image *~
diff --git a/src/ply-frame-buffer.c b/src/ply-frame-buffer.c
old mode 100755
new mode 100644
diff --git a/src/ply-gamma.c b/src/ply-gamma.c
new file mode 100644
index 0000000..1f4f7b0
--- /dev/null
+++ b/src/ply-gamma.c
@@ -0,0 +1,114 @@
+/* ply-gamma.c - plymouth gamma setup via KMS
+ *
+ * Copyright (C) 2011, The Chromium OS Authors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ */
+
+#include "ply-gamma.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+static const int kInternalPanel = 1;
+
+typedef struct {
+  uint16_t *red;
+  uint16_t *green;
+  uint16_t *blue;
+} GammaRamp;
+
+static GammaRamp* load_gamma_ramp(const char* file) {
+  const int kGammaSize = 256;
+  int i, r = 0;
+
+  FILE* f = fopen(file, "rb");
+  if (!f)
+    return NULL;
+
+  unsigned char red[kGammaSize], green[kGammaSize], blue[kGammaSize];
+
+  r += fread(red, sizeof(red), 1, f);
+  r += fread(green, sizeof(green), 1, f);
+  r += fread(blue, sizeof(blue), 1, f);
+  fclose(f);
+
+  if (r != 3)
+    return NULL;
+
+  GammaRamp* ramp = (GammaRamp*)malloc(sizeof(GammaRamp));
+  ramp->red = (uint16_t*)malloc(sizeof(uint16_t) * kGammaSize);
+  ramp->green = (uint16_t*)malloc(sizeof(uint16_t) * kGammaSize);
+  ramp->blue = (uint16_t*)malloc(sizeof(uint16_t) * kGammaSize);
+
+  for(i = 0; i < kGammaSize; ++i) {
+    ramp->red[i]   = (uint16_t)red[i] * 257;
+    ramp->green[i] = (uint16_t)green[i] * 257;
+    ramp->blue[i]  = (uint16_t)blue[i] * 257;
+  }
+
+  return ramp;
+}
+
+static void free_gamma_ramp(GammaRamp* ramp) {
+  free(ramp->red);
+  free(ramp->green);
+  free(ramp->blue);
+  free(ramp);
+}
+
+bool ply_gamma_set(const char* file) {
+  int r;
+  drmModeCrtcPtr mode;
+  GammaRamp* ramp;
+
+  ramp = load_gamma_ramp(file);
+
+  if (!ramp) {
+    fprintf(stderr, "Unable to load gamma ramp\n");
+    return false;
+  }
+
+  int fd = drmOpen("i915", NULL);
+  if (fd < 0) {
+    fprintf(stderr, "Unable to open i915 drm\n");
+    return false;
+  }
+
+  drmModeRes *resources = drmModeGetResources(fd);
+  if (!resources) {
+    fprintf(stderr, "Unable to get mode resources\n");
+    drmClose(fd);
+    return false;
+  }
+
+  mode = drmModeGetCrtc(fd, resources->crtcs[kInternalPanel]);
+  r = drmModeCrtcSetGamma(fd,
+                           mode->crtc_id,
+                           mode->gamma_size,
+                           ramp->red,
+                           ramp->green,
+                           ramp->blue);
+
+  drmModeFreeResources(resources);
+  drmClose(fd);
+  free_gamma_ramp(ramp);
+  return r >= 0;
+}
diff --git a/src/ply-gamma.h b/src/ply-gamma.h
new file mode 100644
index 0000000..0390911
--- /dev/null
+++ b/src/ply-gamma.h
@@ -0,0 +1,32 @@
+/* ply-gamma.c - plymouth gamma setup via KMS
+ *
+ * Copyright (C) 2011, The Chromium OS Authors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ */
+
+#ifndef PLY_GAMMA_H
+#define PLY_GAMMA_H
+
+#include <stdbool.h>
+
+#include "ply-utils.h"
+
+/* Set the gamma of the screen. */
+bool ply_gamma_set(const char* file);
+
+#endif /* PLY_GAMMA_H */
diff --git a/src/ply-image.c b/src/ply-image.c
index 3395c92..1230492 100644
--- a/src/ply-image.c
+++ b/src/ply-image.c
@@ -451,6 +451,7 @@
 }
 
 #include "ply-frame-buffer.h"
+#include "ply-gamma.h"
 
 #include <math.h>
 #include <signal.h>
@@ -517,7 +518,8 @@
 {
   fprintf(stderr,
           "usage: ply-image --clear\n"
-          "       ply-image <background> [<x-offset> <y-offset> "
+          "       ply-image [--gamma <gammafile>] "
+          "<background> [<x-offset> <y-offset> "
           "<frame-1> ... <frame-n>]\n");
   exit(1);
 }
@@ -529,6 +531,7 @@
 {
   int exit_code = 0;
   int clear = 0;
+  int gamma = 0;
   int help = 0;
   ply_frame_buffer_t *buffer;
   int i;
@@ -544,11 +547,12 @@
   if (argc > 1)
     {
       clear = strcasecmp (argv[1], "--clear") == 0;
+      gamma = strcasecmp (argv[1], "--gamma") == 0;
       help = strcasecmp (argv[1], "--help") == 0 ||
         strcasecmp (argv[1], "-h") == 0;
     }
 
-  if (help || argc == 1 || argc == 3 || argc == 4)
+  if (help)
     {
       usage();
     }
@@ -568,6 +572,19 @@
     }
   else
     {
+      int num_gamma_args = 0;
+      if (gamma)
+        {
+          if (argc < 6)
+            usage();
+          ply_gamma_set(argv[2]);
+          argv += 2;
+          argc -= 2;
+        }
+      else
+        if (argc < 4)
+          usage();
+
       /*
        * Display main image.
        */