Add API for pushing color transforms to SurfaceFlinger

BUG: 9057596
Change-Id: Iea0953366eac875b7968897a75472c25a137edb5
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index 09b0ddc..38450c2 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -169,7 +169,7 @@
             fs << "gl_FragColor.rgb = gl_FragColor.rgb/gl_FragColor.a;";
         }
         fs << "gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(2.2));";
-        fs << "gl_FragColor     = colorMatrix*gl_FragColor;";
+        fs << "gl_FragColor.rgb = mat3(colorMatrix) * gl_FragColor.rgb + vec3(colorMatrix[3]);";
         fs << "gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0 / 2.2));";
         if (!needs.isOpaque() && needs.isPremultiplied()) {
             // and re-premultiply if needed after gamma correction
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index fa1ea09..d020871 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -114,7 +114,8 @@
         mDebugInTransaction(0),
         mLastTransactionTime(0),
         mBootFinished(false),
-        mDaltonize(false)
+        mDaltonize(false),
+        mHasColorMatrix(false)
 {
     ALOGI("SurfaceFlinger is starting");
 
@@ -869,7 +870,7 @@
                         for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
                             const sp<Layer>& layer(currentLayers[i]);
                             layer->setGeometry(hw, *cur);
-                            if (mDebugDisableHWC || mDebugRegion || mDaltonize) {
+                            if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) {
                                 cur->setSkip(true);
                             }
                         }
@@ -1483,11 +1484,17 @@
         }
     }
 
-    if (CC_LIKELY(!mDaltonize)) {
+    if (CC_LIKELY(!mDaltonize && !mHasColorMatrix)) {
         doComposeSurfaces(hw, dirtyRegion);
     } else {
         RenderEngine& engine(getRenderEngine());
-        engine.beginGroup(mDaltonizer());
+        mat4 colorMatrix = mColorMatrix;
+        if (mDaltonize) {
+            // preserve last row of color matrix
+            colorMatrix = colorMatrix * mDaltonizer();
+            colorMatrix[3] = mColorMatrix[3];
+        }
+        engine.beginGroup(colorMatrix);
         doComposeSurfaces(hw, dirtyRegion);
         engine.endGroup();
     }
@@ -2371,7 +2378,8 @@
     colorizer.reset(result);
     result.appendFormat("  h/w composer %s and %s\n",
             hwc.initCheck()==NO_ERROR ? "present" : "not present",
-                    (mDebugDisableHWC || mDebugRegion || mDaltonize) ? "disabled" : "enabled");
+                    (mDebugDisableHWC || mDebugRegion || mDaltonize
+                            || mHasColorMatrix) ? "disabled" : "enabled");
     hwc.dump(result);
 
     /*
@@ -2534,8 +2542,33 @@
                 mDaltonize = n > 0;
                 invalidateHwcGeometry();
                 repaintEverything();
+                return NO_ERROR;
             }
-            return NO_ERROR;
+            case 1015: {
+                // apply a color matrix
+                n = data.readInt32();
+                mHasColorMatrix = n ? 1 : 0;
+                if (n) {
+                    // color matrix is sent as mat3 matrix followed by vec3
+                    // offset, then packed into a mat4 where the last row is
+                    // the offset and extra values are 0
+                    for (size_t i = 0 ; i < 3 ; i++) {
+                        for (size_t j = 0; j < 3; j++) {
+                            mColorMatrix[i][j] = data.readFloat();
+                        }
+                        mColorMatrix[i][3] = 0;
+                    }
+                    for (size_t i = 0; i < 3; i++) {
+                        mColorMatrix[3][i] = data.readFloat();
+                    }
+                    mColorMatrix[3][3] = 0;
+                } else {
+                    mColorMatrix = mat4();
+                }
+                invalidateHwcGeometry();
+                repaintEverything();
+                return NO_ERROR;
+            }
         }
     }
     return err;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 347e3e3..a0604bd 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -38,6 +38,7 @@
 #include <binder/IMemory.h>
 
 #include <ui/PixelFormat.h>
+#include <ui/mat4.h>
 
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
@@ -461,6 +462,9 @@
 
     Daltonizer mDaltonizer;
     bool mDaltonize;
+
+    mat4 mColorMatrix;
+    bool mHasColorMatrix;
 };
 
 // ---------------------------------------------------------------------------