Implement SkColorFilter as a GrGLEffect

Adds GrEffect::willUseInputColor() which indicates whether or not the
input color affects the output of the effect. This is needed for
certain Xfermodes, such as kSrc_Mode. For these modes the color filter
will not use the input color.

An effect with GrEffect::willUseInputColor() true will cause all color
or coverage effects before it to be discarded, as their computations
cannot affect the output. In these cases program is marked as having
white input color.

This fixes an assert when Skia is compiled in a mode that prefers
using uniforms instead of attributes for constants. (Flags
GR_GL_USE_NV_PATH_RENDERING or GR_GL_NO_CONSTANT_ATTRIBUTES). Using
attributes hides the problem where the fragment shader does not need
input color for color filters that ignore DST part of the filter. The
assert would be hit when uniform manager tries to bind an uniform which
has been optimized away by the shader compiler.

Adds specific GrGLSLExpr4 and GrGLSLExpr1 classes. This way the GLSL
expressions like "(v - src.a)" can remain somewhat readable in form of
"(v - src.a())". The GrGLSLExpr<typename> template implements the
generic functionality, GrGLSLExprX is the specialization that exposes
the type-safe interface to this functionality.

Also adds operators so that GLSL binary operators of the form
"(float * vecX)" can be expressed in C++. Before only the equivalent
"(vecX * float)" was possible. This reverts the common blending
calculations to more conventional order, such as "(1-a) * c" instead of
"c * (1-a)".

Changes GrGLSLExpr1::OnesStr from 1 to 1.0 in order to preserve the
color filter blending formula string the same (with the exception of
variable name change).

Shaders change in case of input color being needed:
 -   vec4 filteredColor;
 -   filteredColor = (((1.0 - uFilterColor.a) * output_Stage0) + uFilterColor);
 -   fsColorOut = filteredColor;
 +   vec4 output_Stage1;
 +   { // Stage 1: ModeColorFilterEffect
 +   output_Stage1 = (((1.0 - uFilterColor_Stage1.a) * output_Stage0) + uFilterColor_Stage1);
 +   }
 +   fsColorOut = output_Stage1;

Shaders change in case of input color being not needed:
 -uniform vec4 uFilterColor;
 -in vec4 vColor;
 +uniform vec4 uFilterColor_Stage0;
  out vec4 fsColorOut;
  void main() {
 -   vec4 filteredColor;
 -   filteredColor = uFilterColor;
 -   fsColorOut = filteredColor;
 +   vec4 output_Stage0;
 +   { // Stage 0: ModeColorFilterEffect
 +   output_Stage0 = uFilterColor_Stage0;
 +   }
 +   fsColorOut = output_Stage0;
  }

R=bsalomon@google.com, robertphillips@google.com, jvanverth@google.com

Author: kkinnunen@nvidia.com

Review URL: https://codereview.chromium.org/25023003

git-svn-id: http://skia.googlecode.com/svn/trunk/include@11912 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/GrEffect.h b/gpu/GrEffect.h
index 7875270..5fed532 100644
--- a/gpu/GrEffect.h
+++ b/gpu/GrEffect.h
@@ -95,6 +95,9 @@
      */
     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const = 0;
 
+    /** Will this effect read the source color value? */
+    bool willUseInputColor() const { return fWillUseInputColor; }
+
     /** This object, besides creating back-end-specific helper objects, is used for run-time-type-
         identification. The factory should be an instance of templated class,
         GrTBackendEffectFactory. It is templated on the subclass of GrEffect. The subclass must have
@@ -221,6 +224,7 @@
     GrEffect()
         : fWillReadDstColor(false)
         , fWillReadFragmentPosition(false)
+        , fWillUseInputColor(true)
         , fHasVertexCode(false)
         , fEffectRef(NULL) {}
 
@@ -287,6 +291,13 @@
      */
     void setWillReadFragmentPosition() { fWillReadFragmentPosition = true; }
 
+    /**
+     * If the effect will generate a result that does not depend on the input color value then it must
+     * call this function from its constructor. Otherwise, when its generated backend-specific code
+     * might fail during variable binding due to unused variables.
+     */
+    void setWillNotUseInputColor() { fWillUseInputColor = false; }
+
 private:
     bool isEqual(const GrEffect& other) const {
         if (&this->getFactory() != &other.getFactory()) {
@@ -321,6 +332,7 @@
     SkSTArray<kMaxVertexAttribs, GrSLType, true> fVertexAttribTypes;
     bool                                         fWillReadDstColor;
     bool                                         fWillReadFragmentPosition;
+    bool                                         fWillUseInputColor;
     bool                                         fHasVertexCode;
     GrEffectRef*                                 fEffectRef;
 
diff --git a/gpu/GrPaint.h b/gpu/GrPaint.h
index 25557f9..50a32a5 100644
--- a/gpu/GrPaint.h
+++ b/gpu/GrPaint.h
@@ -85,31 +85,13 @@
     bool isDither() const { return fDither; }
 
     /**
-     * Enables a SkXfermode::Mode-based color filter applied to the primitive color. The constant
-     * color passed to this function is considered the "src" color and the primitive's color is
-     * considered the "dst" color. Defaults to kDst_Mode which equates to simply passing through
-     * the primitive color unmodified.
-     */
-    void setXfermodeColorFilter(SkXfermode::Mode mode, GrColor color) {
-        fColorFilterColor = color;
-        fColorFilterXfermode = mode;
-    }
-    SkXfermode::Mode getColorFilterMode() const { return fColorFilterXfermode; }
-    GrColor getColorFilterColor() const { return fColorFilterColor; }
-
-    /**
-     * Disables the SkXfermode::Mode color filter.
-     */
-    void resetColorFilter() {
-        fColorFilterXfermode = SkXfermode::kDst_Mode;
-        fColorFilterColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
-    }
-
-    /**
      * Appends an additional color effect to the color computation.
      */
     const GrEffectRef* addColorEffect(const GrEffectRef* effect, int attr0 = -1, int attr1 = -1) {
         SkASSERT(NULL != effect);
+        if (!(*effect)->willUseInputColor()) {
+            fColorStages.reset();
+        }
         SkNEW_APPEND_TO_TARRAY(&fColorStages, GrEffectStage, (effect, attr0, attr1));
         return effect;
     }
@@ -119,6 +101,9 @@
      */
     const GrEffectRef* addCoverageEffect(const GrEffectRef* effect, int attr0 = -1, int attr1 = -1) {
         SkASSERT(NULL != effect);
+        if (!(*effect)->willUseInputColor()) {
+            fCoverageStages.reset();
+        }
         SkNEW_APPEND_TO_TARRAY(&fCoverageStages, GrEffectStage, (effect, attr0, attr1));
         return effect;
     }
@@ -153,9 +138,6 @@
         fColor = paint.fColor;
         fCoverage = paint.fCoverage;
 
-        fColorFilterColor = paint.fColorFilterColor;
-        fColorFilterXfermode = paint.fColorFilterXfermode;
-
         fColorStages = paint.fColorStages;
         fCoverageStages = paint.fCoverageStages;
 
@@ -171,7 +153,6 @@
         this->resetColor();
         this->resetCoverage();
         this->resetStages();
-        this->resetColorFilter();
     }
 
     /**
@@ -245,9 +226,6 @@
     GrColor                     fColor;
     uint8_t                     fCoverage;
 
-    GrColor                     fColorFilterColor;
-    SkXfermode::Mode            fColorFilterXfermode;
-
     void resetBlend() {
         fSrcBlendCoeff = kOne_GrBlendCoeff;
         fDstBlendCoeff = kZero_GrBlendCoeff;