Implement the color matrix filter in Ganesh.  Also, fix and enable the color
matrix test slide.  This was basically implemented in the same places where
the blending-based color filter was being done.  The shader simply does a mat4
matrix multiply and a vec4 add.

Review URL:  http://codereview.appspot.com/5489107/



git-svn-id: http://skia.googlecode.com/svn/trunk@2948 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrGLProgram.cpp b/src/gpu/GrGLProgram.cpp
index b7e902d..ce87b85 100644
--- a/src/gpu/GrGLProgram.cpp
+++ b/src/gpu/GrGLProgram.cpp
@@ -94,6 +94,8 @@
 #define COL_UNI_NAME "uColor"
 #define EDGES_UNI_NAME "uEdges"
 #define COL_FILTER_UNI_NAME "uColorFilter"
+#define COL_MATRIX_UNI_NAME "uColorMatrix"
+#define COL_MATRIX_VEC_UNI_NAME "uColorMatrixVec"
 
 namespace {
 inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
@@ -365,6 +367,14 @@
 
     add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode);
 }
+/**
+ * Adds code to the fragment shader code which modifies the color by
+ * the specified color matrix.
+ */
+static void addColorMatrix(GrStringBuilder* fsCode, const char * outputVar,
+                           const char* inColor) {
+    fsCode->appendf("%s = %s * %s + %s;\n", outputVar, COL_MATRIX_UNI_NAME, inColor, COL_MATRIX_VEC_UNI_NAME);
+}
 
 namespace {
 
@@ -798,10 +808,10 @@
                                          COL_FILTER_UNI_NAME);
         programData->fUniLocations.fColorFilterUni = kUseUniform;
     }
-
     bool wroteFragColorZero = false;
     if (SkXfermode::kZero_Coeff == uniformCoeff &&
-        SkXfermode::kZero_Coeff == colorCoeff) {
+        SkXfermode::kZero_Coeff == colorCoeff &&
+        !fProgramDesc.fColorMatrixEnabled) {
         segments.fFSCode.appendf("\t%s = %s;\n",
                                  fsColorOutput,
                                  all_zeros_vec(4));
@@ -822,6 +832,19 @@
                        colorCoeff, color);
         inColor = "filteredColor";
     }
+    if (fProgramDesc.fColorMatrixEnabled) {
+        segments.fFSUnis.push_back().set(GrGLShaderVar::kMat44f_Type,
+                                         GrGLShaderVar::kUniform_TypeModifier,
+                                         COL_MATRIX_UNI_NAME);
+        segments.fFSUnis.push_back().set(GrGLShaderVar::kVec4f_Type,
+                                         GrGLShaderVar::kUniform_TypeModifier,
+                                         COL_MATRIX_VEC_UNI_NAME);
+        programData->fUniLocations.fColorMatrixUni = kUseUniform;
+        programData->fUniLocations.fColorMatrixVecUni = kUseUniform;
+        segments.fFSCode.appendf("\tvec4 matrixedColor;\n");
+        addColorMatrix(&segments.fFSCode, "matrixedColor", inColor.c_str());
+        inColor = "matrixedColor";
+    }
 
     ///////////////////////////////////////////////////////////////////////////
     // compute the partial coverage (coverage stages and edge aa)
@@ -1243,6 +1266,16 @@
         GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
     }
 
+    if (kUseUniform == programData->fUniLocations.fColorMatrixUni) {
+        GR_GL_CALL_RET(gl, programData->fUniLocations.fColorMatrixUni,
+                       GetUniformLocation(progID, COL_MATRIX_UNI_NAME));
+    }
+
+    if (kUseUniform == programData->fUniLocations.fColorMatrixVecUni) {
+        GR_GL_CALL_RET(gl, programData->fUniLocations.fColorMatrixVecUni,
+                       GetUniformLocation(progID, COL_MATRIX_VEC_UNI_NAME));
+    }
+
     if (kUseUniform == programData->fUniLocations.fEdgesUni) {
         GR_GL_CALL_RET(gl, programData->fUniLocations.fEdgesUni,
                        GetUniformLocation(progID, EDGES_UNI_NAME));