Express (GLSL expression, possibly known value) pairs as a class

Express (GLSL expression, possibly known value) pairs as a class
instead of two variables Introduces GrGLSLExpr<N> to encapsulate
the expression and possibly constant-folded value of the expression.

This simplifies passing of the expressions to functions.

Changes the shaders with following patterns:
        { // Stage 0: Linear Gradient
        vec4 colorTemp = mix(uGradientStartColor_Stage0, uGradientEndColor_Stage0, clamp(vMatrixCoord_Stage0.x, 0.0, 1
        colorTemp.rgb *= colorTemp.a;
-       output_Stage0 = vec4((vColor) * (colorTemp));
+       output_Stage0 = (vColor * colorTemp);
+       }

Previously the vector cast was always added if constant folding was
effective, regardless of the term dimensions. Now the vector upcast is
not inserted in places where it is not needed, ie. when the binary
operator term is of the target dimension.

Also, some parentheses can be omitted. It is assumed that
GrGLSLExpr<N>("string") constructors construct a simple expression or
parenthesized expression.

Otherwise the shader code remains identical.

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

Author: kkinnunen@nvidia.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@11690 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
index 6f2fee6..993c754 100644
--- a/src/core/SkXfermode.cpp
+++ b/src/core/SkXfermode.cpp
@@ -944,7 +944,7 @@
 
             // We don't try to optimize for this case at all
             if (NULL == inputColor) {
-                builder->fsCodeAppendf("\t\tconst vec4 ones = %s;\n", GrGLSLOnesVecf(4));
+                builder->fsCodeAppendf("\t\tconst vec4 ones = vec4(1);\n");
                 inputColor = "ones";
             }
             builder->fsCodeAppendf("\t\t// SkXfermode::Mode: %s\n", SkXfermode::ModeName(mode));
diff --git a/src/effects/SkArithmeticMode.cpp b/src/effects/SkArithmeticMode.cpp
index d746ecb..fff03c2 100644
--- a/src/effects/SkArithmeticMode.cpp
+++ b/src/effects/SkArithmeticMode.cpp
@@ -366,7 +366,7 @@
 
     // We don't try to optimize for this case at all
     if (NULL == inputColor) {
-        builder->fsCodeAppendf("\t\tconst vec4 src = %s;\n", GrGLSLOnesVecf(4));
+        builder->fsCodeAppendf("\t\tconst vec4 src = vec4(1);\n");
     } else {
         builder->fsCodeAppendf("\t\tvec4 src = %s;\n", inputColor);
         if (gUseUnpremul) {
diff --git a/src/effects/SkBitmapAlphaThresholdShader.cpp b/src/effects/SkBitmapAlphaThresholdShader.cpp
index c8db3a5..69e22c9 100644
--- a/src/effects/SkBitmapAlphaThresholdShader.cpp
+++ b/src/effects/SkBitmapAlphaThresholdShader.cpp
@@ -149,12 +149,8 @@
                                     "\t\t\tcolor.a = thresh;\n"
                                     "\t\t}\n");
 
-            builder->fsCodeAppend("color = ");
-            SkString outStr;
-            outStr.appendf("\t\t%s = ", outputColor);
-            GrGLSLModulatef<4>(&outStr, inputColor, "color");
-            outStr.append(";\n");
-            builder->fsCodeAppend(outStr.c_str());
+            builder->fsCodeAppendf("color = %s = %s;\n", outputColor,
+                                   (GrGLSLExpr<4>(inputColor) * GrGLSLExpr<4>("color")).c_str());
         }
 
         virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect& e) SK_OVERRIDE {
diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp
index 484836a..1e3c779 100644
--- a/src/effects/SkColorMatrixFilter.cpp
+++ b/src/effects/SkColorMatrixFilter.cpp
@@ -410,7 +410,7 @@
 
             if (NULL == inputColor) {
                 // could optimize this case, but we aren't for now.
-                inputColor = GrGLSLOnesVecf(4);
+                inputColor = "vec4(1)";
             }
             // The max() is to guard against 0 / 0 during unpremul when the incoming color is
             // transparent black.
diff --git a/src/effects/SkLumaColorFilter.cpp b/src/effects/SkLumaColorFilter.cpp
index c9f1fb0..eff1645 100644
--- a/src/effects/SkLumaColorFilter.cpp
+++ b/src/effects/SkLumaColorFilter.cpp
@@ -120,7 +120,7 @@
                               const TransformedCoordsArray&,
                               const TextureSamplerArray&) SK_OVERRIDE {
             if (NULL == inputColor) {
-                inputColor = GrGLSLOnesVecf(4);
+                inputColor = "vec4(1)";
             }
 
             // The max() is to guard against 0 / 0 during unpremul when the incoming color is
diff --git a/src/effects/SkLumaXfermode.cpp b/src/effects/SkLumaXfermode.cpp
index 3ecb0be..aa3d780 100644
--- a/src/effects/SkLumaXfermode.cpp
+++ b/src/effects/SkLumaXfermode.cpp
@@ -214,7 +214,7 @@
     const char* dstColor = builder->dstColor();
     SkASSERT(NULL != dstColor);
     if (NULL == inputColor) {
-        inputColor = GrGLSLOnesVecf(4);
+        inputColor = "vec4(1)";
     }
 
     const char *opA = lumaOpA<char>(lumaEffect.getMode(), inputColor, dstColor);
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index dff2d8c..9360ba9 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -950,11 +950,8 @@
             builder->fsCodeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
         }
 
-        SkString output;
-        builder->fsCodeAppendf("\t%s = ", outputColor);
-        GrGLSLModulatef<4>(&output, inputColor, "colorTemp");
-        builder->fsCodeAppend(output.c_str());
-        builder->fsCodeAppend(";\n");
+        builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+                               (GrGLSLExpr<4>(inputColor) * GrGLSLExpr<4>("colorTemp")).c_str());
     } else if (GrGradientEffect::kThree_ColorType == ColorTypeFromKey(key)){
         builder->fsCodeAppendf("\tfloat oneMinus2t = 1.0 - (2.0 * (%s));\n",
                                gradientTValue);
@@ -977,11 +974,8 @@
             builder->fsCodeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
         }
 
-        SkString output;
-        builder->fsCodeAppendf("\t%s = ", outputColor);
-        GrGLSLModulatef<4>(&output, inputColor, "colorTemp");
-        builder->fsCodeAppend(output.c_str());
-        builder->fsCodeAppend(";\n");
+        builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+                               (GrGLSLExpr<4>(inputColor) * GrGLSLExpr<4>("colorTemp")).c_str());
     } else {
         builder->fsCodeAppendf("\tvec2 coord = vec2(%s, %s);\n",
                                gradientTValue,
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index ebb2f69..ad6e061 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -559,9 +559,9 @@
             builder->fsCodeAppendf("\t\t\tedgeAlpha = "
                                    "clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n\t\t}\n");
 
-            SkString modulate;
-            GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
-            builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
+
+            builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+                                   (GrGLSLExpr<4>(inputColor) * GrGLSLExpr<1>("edgeAlpha")).c_str());
 
             builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
         }
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp
index b2052a8..a6b8d97 100644
--- a/src/gpu/GrAARectRenderer.cpp
+++ b/src/gpu/GrAARectRenderer.cpp
@@ -84,9 +84,9 @@
                 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
                 fsRectName, fsRectName);
 
-            SkString modulate;
-            GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
-            builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
+
+            builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+                                   (GrGLSLExpr<4>(inputColor) * GrGLSLExpr<1>("coverage")).c_str());
         }
 
         static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
@@ -217,9 +217,9 @@
                     "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
                     fsWidthHeightName);
 
-            SkString modulate;
-            GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
-            builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
+
+            builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+                                   (GrGLSLExpr<4>(inputColor) * GrGLSLExpr<1>("coverage")).c_str());
         }
 
         static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index 7851265..91e3997 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -116,9 +116,8 @@
                 builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n");
             }
 
-            SkString modulate;
-            GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
-            builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
+            builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+                                   (GrGLSLExpr<4>(inputColor) * GrGLSLExpr<1>("edgeAlpha")).c_str());
         }
 
         static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
@@ -249,9 +248,8 @@
                 builder->fsCodeAppend("\tedgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);\n");
             }
 
-            SkString modulate;
-            GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
-            builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
+            builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+                                   (GrGLSLExpr<4>(inputColor) * GrGLSLExpr<1>("edgeAlpha")).c_str());
         }
 
         static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
@@ -408,9 +406,8 @@
                 builder->fsCodeAppend("\tedgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);\n");
             }
 
-            SkString modulate;
-            GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
-            builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
+            builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+                                   (GrGLSLExpr<4>(inputColor) * GrGLSLExpr<1>("edgeAlpha")).c_str());
         }
 
         static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
diff --git a/src/gpu/effects/GrBezierEffect.cpp b/src/gpu/effects/GrBezierEffect.cpp
index 4dca884..9cca054 100644
--- a/src/gpu/effects/GrBezierEffect.cpp
+++ b/src/gpu/effects/GrBezierEffect.cpp
@@ -110,9 +110,8 @@
         }
     }
 
-    SkString modulate;
-    GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
-    builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
+    builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+                           (GrGLSLExpr<4>(inputColor) * GrGLSLExpr<1>("edgeAlpha")).c_str());
 }
 
 GrGLEffect::EffectKey GrGLConicEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
@@ -239,9 +238,9 @@
         }
     }
 
-    SkString modulate;
-    GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
-    builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
+    builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+                           (GrGLSLExpr<4>(inputColor) * GrGLSLExpr<1>("edgeAlpha")).c_str());
+
 
     builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
 }
@@ -383,9 +382,8 @@
         }
     }
 
-    SkString modulate;
-    GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
-    builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
+    builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+                           (GrGLSLExpr<4>(inputColor) * GrGLSLExpr<1>("edgeAlpha")).c_str());
 }
 
 GrGLEffect::EffectKey GrGLCubicEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index a69333f..b043592 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -158,13 +158,13 @@
         str->printf("(%s * %s)", src, value);
         break;
     case SkXfermode::kISC_Coeff:
-        str->printf("((%s - %s) * %s)", GrGLSLOnesVecf(4), src, value);
+        str->printf("((vec4(1) - %s) * %s)", src, value);
         break;
     case SkXfermode::kDC_Coeff:
         str->printf("(%s * %s)", dst, value);
         break;
     case SkXfermode::kIDC_Coeff:
-        str->printf("((%s - %s) * %s)", GrGLSLOnesVecf(4), dst, value);
+        str->printf("((vec4(1) - %s) * %s)", dst, value);
         break;
     case SkXfermode::kSA_Coeff:      /** src alpha */
         str->printf("(%s.a * %s)", src, value);
@@ -196,31 +196,20 @@
     SkString colorStr, constStr;
     blend_term_string(&colorStr, colorCoeff, filterColor, inColor, inColor);
     blend_term_string(&constStr, uniformCoeff, filterColor, inColor, filterColor);
-
-    SkString sum;
-    GrGLSLAddf<4>(&sum, colorStr.c_str(), constStr.c_str());
+    GrGLSLExpr<4> sum;
+    if (colorStr.isEmpty() && constStr.isEmpty()) {
+        sum = GrGLSLExpr<4>(0);
+    } else if (colorStr.isEmpty()) {
+        sum = constStr;
+    } else if (constStr.isEmpty()) {
+        sum = colorStr;
+    } else {
+        sum = GrGLSLExpr<4>(colorStr) + GrGLSLExpr<4>(constStr);
+    }
     builder->fsCodeAppendf("\t%s = %s;\n", outputVar, sum.c_str());
 }
 }
 
-namespace {
-
-void expand_known_value4f(SkString* string, GrSLConstantVec vec) {
-    SkASSERT(string->isEmpty() == (vec != kNone_GrSLConstantVec));
-    switch (vec) {
-        case kNone_GrSLConstantVec:
-            break;
-        case kZeros_GrSLConstantVec:
-            *string = GrGLSLZerosVecf(4);
-            break;
-        case kOnes_GrSLConstantVec:
-            *string = GrGLSLOnesVecf(4);
-            break;
-    }
-}
-
-}
-
 bool GrGLProgram::genProgram(GrGLShaderBuilder* builder,
                              const GrEffectStage* colorStages[],
                              const GrEffectStage* coverageStages[]) {
@@ -229,8 +218,7 @@
     const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
 
     // incoming color to current stage being processed.
-    SkString inColor = builder->getInputColor();
-    GrSLConstantVec knownColorValue = builder->getKnownColorValue();
+    GrGLSLExpr<4> inColor = builder->getInputColor();
 
     // Get the coeffs for the Mode-based color filter, determine if color is needed.
     SkXfermode::Coeff colorCoeff;
@@ -246,8 +234,7 @@
         builder->createAndEmitEffects(colorStages,
                                       fDesc.effectKeys(),
                                       needColor ? fDesc.numColorEffects() : 0,
-                                      &inColor,
-                                      &knownColorValue));
+                                      &inColor));
 
     // Insert the color filter. This will soon be replaced by a color effect.
     if (SkXfermode::kDst_Mode != header.fColorFilterXfermode) {
@@ -257,35 +244,24 @@
                                                               &colorFilterColorUniName);
 
         builder->fsCodeAppend("\tvec4 filteredColor;\n");
-        const char* color;
-        // add_color_filter requires a real input string.
-        if (knownColorValue == kOnes_GrSLConstantVec) {
-            color = GrGLSLOnesVecf(4);
-        } else if (knownColorValue == kZeros_GrSLConstantVec) {
-            color = GrGLSLZerosVecf(4);
-        } else {
-            color = inColor.c_str();
-        }
         add_color_filter(builder, "filteredColor", filterColorCoeff,
-                         colorCoeff, colorFilterColorUniName, color);
+                         colorCoeff, colorFilterColorUniName, inColor.c_str());
         inColor = "filteredColor";
     }
 
     ///////////////////////////////////////////////////////////////////////////
     // compute the partial coverage
-    SkString inCoverage = builder->getInputCoverage();
-    GrSLConstantVec knownCoverageValue = builder->getKnownCoverageValue();
+    GrGLSLExpr<4> inCoverage = builder->getInputCoverage();
 
     fCoverageEffects.reset(
         builder->createAndEmitEffects(coverageStages,
                                       fDesc.getEffectKeys() + fDesc.numColorEffects(),
                                       fDesc.numCoverageEffects(),
-                                      &inCoverage,
-                                      &knownCoverageValue));
+                                      &inCoverage));
 
     // discard if coverage is zero
-    if (header.fDiscardIfZeroCoverage && kOnes_GrSLConstantVec != knownCoverageValue) {
-        if (kZeros_GrSLConstantVec == knownCoverageValue) {
+    if (header.fDiscardIfZeroCoverage && !inCoverage.isOnes()) {
+        if (inCoverage.isZeros()) {
             // This is unfortunate.
             builder->fsCodeAppend("\tdiscard;\n");
         } else {
@@ -298,79 +274,30 @@
         const char* secondaryOutputName = builder->enableSecondaryOutput();
 
         // default coeff to ones for kCoverage_DualSrcOutput
-        SkString coeff;
-        GrSLConstantVec knownCoeffValue = kOnes_GrSLConstantVec;
+        GrGLSLExpr<4> coeff(1);
         if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCoverageOutput) {
             // Get (1-A) into coeff
-            SkString inColorAlpha;
-            GrGLSLGetComponent4f(&inColorAlpha,
-                                    inColor.c_str(),
-                                    kA_GrColorComponentFlag,
-                                    knownColorValue,
-                                    true);
-            knownCoeffValue = GrGLSLSubtractf<1>(&coeff,
-                                                 NULL,
-                                                 inColorAlpha.c_str(),
-                                                 kOnes_GrSLConstantVec,
-                                                 knownColorValue,
-                                                 true);
+            coeff = GrGLSLExprCast4(GrGLSLExpr<1>(1) - GrGLSLExprExtractAlpha(inColor));
         } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == header.fCoverageOutput) {
             // Get (1-RGBA) into coeff
-            knownCoeffValue = GrGLSLSubtractf<4>(&coeff,
-                                                 NULL,
-                                                 inColor.c_str(),
-                                                 kOnes_GrSLConstantVec,
-                                                 knownColorValue,
-                                                 true);
+            coeff = GrGLSLExpr<4>(1) - inColor;
         }
         // Get coeff * coverage into modulate and then write that to the dual source output.
-        SkString modulate;
-        GrGLSLModulatef<4>(&modulate,
-                           coeff.c_str(),
-                           inCoverage.c_str(),
-                           knownCoeffValue,
-                           knownCoverageValue,
-                           false);
-        builder->fsCodeAppendf("\t%s = %s;\n", secondaryOutputName, modulate.c_str());
+        builder->fsCodeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inCoverage).c_str());
     }
 
     ///////////////////////////////////////////////////////////////////////////
     // combine color and coverage as frag color
 
     // Get "color * coverage" into fragColor
-    SkString fragColor;
-    GrSLConstantVec knownFragColorValue = GrGLSLModulatef<4>(&fragColor,
-                                                             inColor.c_str(),
-                                                             inCoverage.c_str(),
-                                                             knownColorValue,
-                                                             knownCoverageValue,
-                                                             true);
+    GrGLSLExpr<4> fragColor = inColor * inCoverage;
     // Now tack on "+(1-coverage)dst onto the frag color if we were asked to do so.
     if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == header.fCoverageOutput) {
-        SkString dstCoeff;
-        GrSLConstantVec knownDstCoeffValue = GrGLSLSubtractf<4>(&dstCoeff,
-                                                                NULL,
-                                                                inCoverage.c_str(),
-                                                                kOnes_GrSLConstantVec,
-                                                                knownCoverageValue,
-                                                                true);
-        SkString dstContribution;
-        GrSLConstantVec knownDstContributionValue = GrGLSLModulatef<4>(&dstContribution,
-                                                                       dstCoeff.c_str(),
-                                                                       builder->dstColor(),
-                                                                       knownDstCoeffValue,
-                                                                       kNone_GrSLConstantVec,
-                                                                       true);
-        SkString oldFragColor = fragColor;
-        fragColor.reset();
-        GrGLSLAddf<4>(&fragColor,
-                      oldFragColor.c_str(),
-                      dstContribution.c_str(),
-                      knownFragColorValue,
-                      knownDstContributionValue,
-                      false);
-    } else {
-        expand_known_value4f(&fragColor, knownFragColorValue);
+        GrGLSLExpr<4> dstCoeff = GrGLSLExpr<4>(1) - inCoverage;
+
+        GrGLSLExpr<4> dstContribution = dstCoeff * GrGLSLExpr<4>(builder->dstColor());
+
+        fragColor = fragColor + dstContribution;
     }
     builder->fsCodeAppendf("\t%s = %s;\n", builder->getColorOutputName(), fragColor.c_str());
 
diff --git a/src/gpu/gl/GrGLProgramDesc.h b/src/gpu/gl/GrGLProgramDesc.h
index 46eed09..c8ad77c 100644
--- a/src/gpu/gl/GrGLProgramDesc.h
+++ b/src/gpu/gl/GrGLProgramDesc.h
@@ -113,17 +113,6 @@
         kColorInputCnt
     };
 
-    static GrSLConstantVec KnownColorInputValue(ColorInput ci) {
-        switch (ci) {
-            case GrGLProgramDesc::kTransBlack_ColorInput:
-                return kZeros_GrSLConstantVec;
-            case GrGLProgramDesc::kSolidWhite_ColorInput:
-                return kOnes_GrSLConstantVec;
-            default:
-                return kNone_GrSLConstantVec;
-        }
-    }
-
     enum CoverageOutput {
         // modulate color and coverage, write result as the color output.
         kModulate_CoverageOutput,
diff --git a/src/gpu/gl/GrGLSL.cpp b/src/gpu/gl/GrGLSL.cpp
index f48f038..3dfd5e5 100644
--- a/src/gpu/gl/GrGLSL.cpp
+++ b/src/gpu/gl/GrGLSL.cpp
@@ -63,26 +63,6 @@
     }
 }
 
-const char* GrGLSLVectorHomogCoord(int count) {
-    static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
-    SkASSERT(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS));
-    return HOMOGS[count];
-}
-
-const char* GrGLSLVectorHomogCoord(GrSLType type) {
-    return GrGLSLVectorHomogCoord(GrSLTypeToVecLength(type));
-}
-
-const char* GrGLSLVectorNonhomogCoords(int count) {
-    static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
-    SkASSERT(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS));
-    return NONHOMOGS[count];
-}
-
-const char* GrGLSLVectorNonhomogCoords(GrSLType type) {
-    return GrGLSLVectorNonhomogCoords(GrSLTypeToVecLength(type));
-}
-
 namespace {
     void append_tabs(SkString* outAppend, int tabCnt) {
         static const char kTabs[] = "\t\t\t\t\t\t\t\t";
@@ -94,50 +74,19 @@
     }
 }
 
-GrSLConstantVec GrGLSLMulVarBy4f(SkString* outAppend,
-                                 int tabCnt,
-                                 const char* vec4VarName,
-                                 const char* mulFactor,
-                                 GrSLConstantVec mulFactorDefault) {
-    bool haveFactor = NULL != mulFactor && '\0' != *mulFactor;
-
-    SkASSERT(NULL != outAppend);
-    SkASSERT(NULL != vec4VarName);
-    SkASSERT(kNone_GrSLConstantVec != mulFactorDefault || haveFactor);
-
-    if (!haveFactor) {
-        if (kOnes_GrSLConstantVec == mulFactorDefault) {
-            return kNone_GrSLConstantVec;
-        } else {
-            SkASSERT(kZeros_GrSLConstantVec == mulFactorDefault);
-            append_tabs(outAppend, tabCnt);
-            outAppend->appendf("%s = vec4(0, 0, 0, 0);\n", vec4VarName);
-            return kZeros_GrSLConstantVec;
-        }
+void GrGLSLMulVarBy4f(SkString* outAppend,
+                      unsigned tabCnt,
+                      const char* vec4VarName,
+                      const GrGLSLExpr<4>& mulFactor) {
+    if (mulFactor.isOnes()) {
+        *outAppend = SkString();
     }
+
     append_tabs(outAppend, tabCnt);
-    outAppend->appendf("%s *= %s;\n", vec4VarName, mulFactor);
-    return kNone_GrSLConstantVec;
+
+    if (mulFactor.isZeros()) {
+        outAppend->appendf("%s = vec4(0);\n", vec4VarName);
+    }
+    outAppend->appendf("%s *= %s;\n", vec4VarName, mulFactor.c_str());
 }
 
-GrSLConstantVec GrGLSLGetComponent4f(SkString* outAppend,
-                                     const char* expr,
-                                     GrColorComponentFlags component,
-                                     GrSLConstantVec defaultExpr,
-                                     bool omitIfConst) {
-    if (NULL == expr || '\0' == *expr) {
-        SkASSERT(defaultExpr != kNone_GrSLConstantVec);
-        if (!omitIfConst) {
-            if (kOnes_GrSLConstantVec == defaultExpr) {
-                outAppend->append("1.0");
-            } else {
-                SkASSERT(kZeros_GrSLConstantVec == defaultExpr);
-                outAppend->append("0.0");
-            }
-        }
-        return defaultExpr;
-    } else {
-        outAppend->appendf("(%s).%c", expr, GrColorComponentFlagToChar(component));
-        return kNone_GrSLConstantVec;
-    }
-}
diff --git a/src/gpu/gl/GrGLSL.h b/src/gpu/gl/GrGLSL.h
index b97e709..9387d2b 100644
--- a/src/gpu/gl/GrGLSL.h
+++ b/src/gpu/gl/GrGLSL.h
@@ -11,10 +11,10 @@
 #include "gl/GrGLInterface.h"
 #include "GrColor.h"
 #include "GrTypesPriv.h"
+#include "SkString.h"
 
 class GrGLContextInfo;
 class GrGLShaderVar;
-class SkString;
 
 // Limited set of GLSL versions we build shaders for. Caller should round
 // down the GLSL version to one of these enums.
@@ -37,43 +37,6 @@
     k150_GrGLSLGeneration,
 };
 
-enum GrSLConstantVec {
-    kZeros_GrSLConstantVec,
-    kOnes_GrSLConstantVec,
-    kNone_GrSLConstantVec,
-};
-
-namespace {
-static inline int GrSLTypeToVecLength(GrSLType type) {
-    static const int kVecLengths[] = {
-        0, // kVoid_GrSLType
-        1, // kFloat_GrSLType
-        2, // kVec2f_GrSLType
-        3, // kVec3f_GrSLType
-        4, // kVec4f_GrSLType
-        1, // kMat33f_GrSLType
-        1, // kMat44f_GrSLType
-        1, // kSampler2D_GrSLType
-    };
-    GR_STATIC_ASSERT(kGrSLTypeCount == GR_ARRAY_COUNT(kVecLengths));
-    return kVecLengths[type];
-}
-
-static inline const char* GrGLSLOnesVecf(int count) {
-    static const char* kONESVEC[] = {"ERROR", "1.0", "vec2(1,1)",
-                                     "vec3(1,1,1)", "vec4(1,1,1,1)"};
-    SkASSERT(count >= 1 && count < (int)GR_ARRAY_COUNT(kONESVEC));
-    return kONESVEC[count];
-}
-
-static inline const char* GrGLSLZerosVecf(int count) {
-    static const char* kZEROSVEC[] = {"ERROR", "0.0", "vec2(0,0)",
-                                      "vec3(0,0,0)", "vec4(0,0,0,0)"};
-    SkASSERT(count >= 1 && count < (int)GR_ARRAY_COUNT(kZEROSVEC));
-    return kZEROSVEC[count];
-}
-}
-
 /**
  * Gets the most recent GLSL Generation compatible with the OpenGL context.
  */
@@ -89,7 +52,7 @@
 /**
  * Converts a GrSLType to a string containing the name of the equivalent GLSL type.
  */
-static const char* GrGLSLTypeString(GrSLType t) {
+static inline const char* GrGLSLTypeString(GrSLType t) {
     switch (t) {
         case kVoid_GrSLType:
             return "void";
@@ -113,101 +76,203 @@
     }
 }
 
-/** Return the type enum for a vector of floats of length n (1..4),
-    e.g. 1 -> "float", 2 -> "vec2", ... */
-static inline const char* GrGLSLFloatVectorTypeString(int n) {
-    return GrGLSLTypeString(GrSLFloatVectorType(n));
+/** A class representing a GLSL expression.
+ * The instance can be a variable name, expression or vecN(0) or vecN(1). Does simple constant
+ * folding with help of 1 and 0.
+ * Complex expressions can be constructed with operators *, +, -
+ */
+template <int N>
+class GrGLSLExpr {
+public:
+    /** Constructs an invalid expression.
+     * Useful only as a return value from functions that never actually return
+     * this and instances that will be assigned to later. */
+    GrGLSLExpr()
+        : fType(kFullExpr_ExprType) {
+        SK_COMPILE_ASSERT(N > 0 && N <= 4, dimensions_not_in_range);
+        // The only constructor that is allowed to build an empty expression.
+        SkASSERT(!this->isValid());
+    }
+
+    /** Constructs an expression with all components as value v */
+    explicit GrGLSLExpr(int v) {
+        SK_COMPILE_ASSERT(N > 0 && N <= 4, dimensions_not_in_range);
+        if (v == 0) {
+            fType = kZeros_ExprType;
+        } else if (v == 1) {
+            fType = kOnes_ExprType;
+        } else {
+            fType = kFullExpr_ExprType;
+            fExpr.appendf(CastIntStr(), v);
+        }
+    }
+
+    /** Constructs an expression from a string.
+     * Argument expr is a simple expression or a parenthesized expression. */
+    // TODO: make explicit once effects input Exprs.
+    GrGLSLExpr(const char expr[]) {
+        SK_COMPILE_ASSERT(N > 0 && N <= 4, dimensions_not_in_range);
+        if (NULL == expr) {  // TODO: remove this once effects input Exprs.
+            fType = kOnes_ExprType;
+        } else {
+            fType = kFullExpr_ExprType;
+            fExpr = expr;
+        }
+        SkASSERT(this->isValid());
+    }
+
+    /** Constructs an expression from a string.
+     * Argument expr is a simple expression or a parenthesized expression. */
+    // TODO: make explicit once effects input Exprs.
+    GrGLSLExpr(const SkString& expr) {
+        SK_COMPILE_ASSERT(N > 0 && N <= 4, dimensions_not_in_range);
+        if (expr.isEmpty()) {  // TODO: remove this once effects input Exprs.
+            fType = kOnes_ExprType;
+        } else {
+            fType = kFullExpr_ExprType;
+            fExpr = expr;
+        }
+        SkASSERT(this->isValid());
+    }
+
+    bool isOnes() const { return kOnes_ExprType == fType; }
+    bool isZeros() const { return kZeros_ExprType == fType; }
+
+    const char* c_str() const {
+        if (kZeros_ExprType == fType) {
+            return ZerosStr();
+        } else if (kOnes_ExprType == fType) {
+            return OnesStr();
+        }
+        SkASSERT(!fExpr.isEmpty()); // Empty expressions should not be used.
+        return fExpr.c_str();
+    }
+
+private:
+    GrGLSLExpr(const char format[], const char in0[])
+        : fType(kFullExpr_ExprType) {
+        fExpr.appendf(format, in0);
+    }
+
+    GrGLSLExpr(const char format[], const char in0[], const char in1[])
+        : fType(kFullExpr_ExprType) {
+        fExpr.appendf(format, in0, in1);
+    }
+
+    GrGLSLExpr(const char format[], const char in0[], char in1)
+        : fType(kFullExpr_ExprType) {
+        fExpr.appendf(format, in0, in1);
+    }
+
+    bool isValid() const {
+        return kFullExpr_ExprType != fType || !fExpr.isEmpty();
+    }
+
+    static const char* ZerosStr();
+    static const char* OnesStr();
+    static const char* ExtractAlphaStr();
+    static const char* CastStr();
+    static const char* CastIntStr();
+
+    /** Casts the expression expr into smaller or bigger expression.
+     * Casting is done with GLSL rules:
+     * M==3, N==4 vec3(a, b, c) -> vec4(a, b, c, 0)
+     * N==4, M==3 vec4(a, b, c, d) -> vec3(a, b, c)
+     */
+    template <int M>
+    static GrGLSLExpr<N> VectorCast(const GrGLSLExpr<M>& expr);
+
+    /** GLSL multiplication: component-wise or multiply each component by a scalar.
+     * M == N --> vecN(in0.x * in1.x, ...)
+     * M == 1 --> vecN(in0.x * in1, ...)
+     * otherwise --> compile-time error
+     */
+    template <int M>
+    static GrGLSLExpr<N> Mul(const GrGLSLExpr<N>& in0, const GrGLSLExpr<M>& in1);
+
+    /** GLSL addition: component-wise or add a scalar to each compoment.
+     * M == N --> vecN(in0.x + in1.x, ...)
+     * M == 1 --> vecN(in0.x + in1, ...)
+     * otherwise --> compile-time error
+     */
+    template <int M>
+    static GrGLSLExpr<N> Add(const GrGLSLExpr<N>& in0, const GrGLSLExpr<M>& in1);
+
+    /** GLSL subtraction: component-wise or subtract compoments by a scalar.
+     * M == N --> vecN(in0.x - in1.x, ...)
+     * M == 1 --> vecN(in0.x - in1, ...)
+     * otherwise --> compile-time error
+     */
+    template <int M>
+    static GrGLSLExpr<N> Sub(const GrGLSLExpr<N>& in0, const GrGLSLExpr<M>& in1);
+
+    enum ExprType {
+        kZeros_ExprType,
+        kOnes_ExprType,
+        kFullExpr_ExprType,
+    };
+    ExprType fType;
+    SkString fExpr;
+
+    template <int> friend class GrGLSLExpr;
+
+    /** Multiplies two expressions component-wise. */
+    template <int M> friend GrGLSLExpr<M> operator*(const GrGLSLExpr<M>&, const GrGLSLExpr<M>&);
+    /** Adds two expressions component-wise. */
+    template <int M> friend GrGLSLExpr<M> operator+(const GrGLSLExpr<M>&, const GrGLSLExpr<M>&);
+    /** Subtracts two expressions component-wise. */
+    template <int M> friend GrGLSLExpr<M> operator-(const GrGLSLExpr<M>&, const GrGLSLExpr<M>&);
+    /** Multiplies every component of an expression with a scalar expression. */
+    friend GrGLSLExpr<4> operator*(const GrGLSLExpr<4>&, const GrGLSLExpr<1>&);
+    /** Adds a scalar expression to every component of an expression. */
+    friend GrGLSLExpr<4> operator+(const GrGLSLExpr<4>&, const GrGLSLExpr<1>&);
+    /** Subtracts a scalar expression from every component of an expression. */
+    friend GrGLSLExpr<4> operator-(const GrGLSLExpr<4>&, const GrGLSLExpr<1>&);
+
+    friend GrGLSLExpr<1> GrGLSLExprExtractAlpha(const GrGLSLExpr<4>& expr);
+    friend GrGLSLExpr<4> GrGLSLExprCast4(const GrGLSLExpr<1>& expr);
+};
+
+
+template <int N>
+inline GrGLSLExpr<N> operator*(const GrGLSLExpr<N>& in0, const GrGLSLExpr<N>&in1) {
+    return GrGLSLExpr<N>::Mul(in0, in1);
 }
 
-/** Return the GLSL swizzle operator for a homogenous component of a vector
-    with the given number of coordinates, e.g. 2 -> ".y", 3 -> ".z" */
-const char* GrGLSLVectorHomogCoord(int count);
-const char* GrGLSLVectorHomogCoord(GrSLType type);
-
-/** Return the GLSL swizzle operator for a nonhomogenous components of a vector
-    with the given number of coordinates, e.g. 2 -> ".x", 3 -> ".xy" */
-const char* GrGLSLVectorNonhomogCoords(int count);
-const char* GrGLSLVectorNonhomogCoords(GrSLType type);
-
-/**
-  * Produces a string that is the result of modulating two inputs. The inputs must be vecN or
-  * float. The result is always a vecN. The inputs may be expressions, not just identifier names.
-  * Either can be NULL or "" in which case the default params control whether a vector of ones or
-  * zeros. It is an error to pass kNone for default<i> if in<i> is NULL or "". Note that when the
-  * function determines that the result is a zeros or ones vec then any expression represented by
-  * or in1 will not be emitted (side effects won't occur). The return value indicates whether a
-  * known zeros or ones vector resulted. The output can be suppressed when known vector is produced
-  * by passing true for omitIfConstVec.
-  */
 template <int N>
-GrSLConstantVec GrGLSLModulatef(SkString* outAppend,
-                                const char* in0,
-                                const char* in1,
-                                GrSLConstantVec default0 = kOnes_GrSLConstantVec,
-                                GrSLConstantVec default1 = kOnes_GrSLConstantVec,
-                                bool omitIfConstVec = false);
+inline GrGLSLExpr<N> operator+(const GrGLSLExpr<N>& in0, const GrGLSLExpr<N>&in1) {
+    return GrGLSLExpr<N>::Add(in0, in1);
+}
 
-/**
- * Produces a string that is the result of adding two inputs. The inputs must be vecN or
- * float. The result is always a vecN. The inputs may be expressions, not just identifier names.
- * Either can be NULL or "" in which case the default params control whether a vector of ones or
- * zeros. It is an error to pass kNone for default<i> if in<i> is NULL or "". Note that when the
- * function determines that the result is a zeros or ones vec then any expression represented by
- * or in1 will not be emitted (side effects won't occur). The return value indicates whether a
- * known zeros or ones vector resulted. The output can be suppressed when known vector is produced
- * by passing true for omitIfConstVec.
- */
 template <int N>
-GrSLConstantVec GrGLSLAddf(SkString* outAppend,
-                           const char* in0,
-                           const char* in1,
-                           GrSLConstantVec default0 = kZeros_GrSLConstantVec,
-                           GrSLConstantVec default1 = kZeros_GrSLConstantVec,
-                           bool omitIfConstVec = false);
+inline GrGLSLExpr<N> operator-(const GrGLSLExpr<N>& in0, const GrGLSLExpr<N>&in1) {
+    return GrGLSLExpr<N>::Sub(in0, in1);
+}
+
+inline GrGLSLExpr<4> operator*(const GrGLSLExpr<4>& in0, const GrGLSLExpr<1>& in1) {
+    return GrGLSLExpr<4>::Mul(in0, in1);
+}
+
+inline GrGLSLExpr<4> operator+(const GrGLSLExpr<4>& in0, const GrGLSLExpr<1>& in1) {
+    return GrGLSLExpr<4>::Add(in0, in1);
+}
+
+inline GrGLSLExpr<4> operator-(const GrGLSLExpr<4>& in0, const GrGLSLExpr<1>& in1) {
+    return GrGLSLExpr<4>::Sub(in0, in1);
+}
+
+/** Casts an vec1 expression  to vec4 expresison, eg. vec1(v) -> vec4(v,v,v,v). */
+GrGLSLExpr<4> GrGLSLExprCast4(const GrGLSLExpr<1>& expr);
+
+/** Extracts alpha component from an expression of vec<4>. */
+GrGLSLExpr<1> GrGLSLExprExtractAlpha(const GrGLSLExpr<4>& expr);
 
 /**
- * Produces a string that is the result of subtracting two inputs. The inputs must be vecN or
- * float. The result is always a vecN. The inputs may be expressions, not just identifier names.
- * Either can be NULL or "" in which case the default params control whether a vector of ones or
- * zeros. It is an error to pass kNone for default<i> if in<i> is NULL or "". Note that when the
- * function determines that the result is a zeros or ones vec then any expression represented by
- * or in1 will not be emitted (side effects won't occur). The return value indicates whether a
- * known zeros or ones vector resulted. The output can be suppressed when known vector is produced
- * by passing true for omitIfConstVec.
+ * Does an inplace mul, *=, of vec4VarName by mulFactor.
+ * A semicolon and newline are added after the assignment.
  */
-template <int N>
-GrSLConstantVec GrGLSLSubtractf(SkString* outAppend,
-                                const char* in0,
-                                const char* in1,
-                                GrSLConstantVec default0 = kZeros_GrSLConstantVec,
-                                GrSLConstantVec default1 = kZeros_GrSLConstantVec,
-                                bool omitIfConstVec = false);
-
-/**
- * Does an inplace mul, *=, of vec4VarName by mulFactor. If mulFactorDefault is not kNone then
- * mulFactor may be either "" or NULL. In this case either nothing will be appended (kOnes) or an
- * assignment of vec(0,0,0,0) will be appended (kZeros). The assignment is prepended by tabCnt tabs.
- * A semicolon and newline are added after the assignment. (TODO: Remove tabCnt when we auto-insert
- * tabs to GrGLEffect-generated lines.) If a zeros vec is assigned then the return value is
- * kZeros, otherwise kNone.
- */
-GrSLConstantVec GrGLSLMulVarBy4f(SkString* outAppend,
-                                 int tabCnt,
-                                 const char* vec4VarName,
-                                 const char* mulFactor,
-                                 GrSLConstantVec mulFactorDefault = kOnes_GrSLConstantVec);
-
-/**
- * Given an expression that evaluates to a GLSL vec4, extract a component. If expr is NULL or ""
- * the value of defaultExpr is used. It is an error to pass an empty expr and have set defaultExpr
- * to kNone. The return value indicates whether the value is known to be 0 or 1. If omitIfConst is
- * set then nothing is appended when the return is not kNone.
- */
-GrSLConstantVec GrGLSLGetComponent4f(SkString* outAppend,
-                                     const char* expr,
-                                     GrColorComponentFlags component,
-                                     GrSLConstantVec defaultExpr = kNone_GrSLConstantVec,
-                                     bool omitIfConst = false);
+void GrGLSLMulVarBy4f(SkString* outAppend, unsigned tabCnt,
+                      const char* vec4VarName, const GrGLSLExpr<4>& mulFactor);
 
 #include "GrGLSL_impl.h"
 
diff --git a/src/gpu/gl/GrGLSL_impl.h b/src/gpu/gl/GrGLSL_impl.h
index 292048c..008d512 100644
--- a/src/gpu/gl/GrGLSL_impl.h
+++ b/src/gpu/gl/GrGLSL_impl.h
@@ -8,185 +8,133 @@
 #ifndef GrGLSL_impl_DEFINED
 #define GrGLSL_impl_DEFINED
 
-#include "SkString.h"
+template<>
+inline const char* GrGLSLExpr<4>::ZerosStr() {
+    return "vec4(0)";
+}
 
-namespace {
+template<>
+inline const char* GrGLSLExpr<4>::OnesStr() {
+    return "vec4(1)";
+}
+
+template<>
+inline const char* GrGLSLExpr<4>::ExtractAlphaStr() {
+    return "%s.a";
+}
+
+template<>
+inline const char* GrGLSLExpr<4>::CastStr() {
+    return "vec4(%s)";
+}
+template<>
+inline const char* GrGLSLExpr<4>::CastIntStr() {
+    return "vec4(%d)";
+}
+
+template<>
+inline const char* GrGLSLExpr<1>::ZerosStr() {
+    return "0";
+}
+
+template<>
+inline const char* GrGLSLExpr<1>::OnesStr() {
+    return "1";
+}
+
+// GrGLSLExpr<1>::ExtractAlphaStr() and GrGLSLExpr<1>::CastStr() are
+// unimplemented because using them is likely an error. This is now caught
+// compile-time.
+
+template<>
+inline const char* GrGLSLExpr<1>::CastIntStr() {
+    return "%d";
+}
+
+template<>
+template<>
+inline GrGLSLExpr<4> GrGLSLExpr<4>::VectorCast(const GrGLSLExpr<4>& expr) {
+    return expr;
+}
+
+template<>
+template<>
+inline GrGLSLExpr<1>  GrGLSLExpr<1>::VectorCast(const GrGLSLExpr<1>& expr)  {
+    return expr;
+}
+
 template<int N>
-GrSLConstantVec return_const_vecf(GrSLConstantVec constVec, SkString* outAppend, bool omitAppend) {
-    SkASSERT(kNone_GrSLConstantVec != constVec);
-    if (!omitAppend) {
-        if (kZeros_GrSLConstantVec == constVec) {
-            outAppend->append(GrGLSLZerosVecf(N));
-        } else {
-            outAppend->append(GrGLSLOnesVecf(N));
-        }
+template<int M>
+inline GrGLSLExpr<N> GrGLSLExpr<N>::VectorCast(const GrGLSLExpr<M>& expr) {
+    if (expr.isZeros()) {
+        return GrGLSLExpr<N>(0);
     }
-    return constVec;
-}
+    if (expr.isOnes()) {
+        return GrGLSLExpr<N>(1);
+    }
+    return GrGLSLExpr<N>(GrGLSLExpr<N>::CastStr(), expr.c_str());
 }
 
-template <int N>
-GrSLConstantVec GrGLSLModulatef(SkString* outAppend,
-                                const char* in0,
-                                const char* in1,
-                                GrSLConstantVec default0,
-                                GrSLConstantVec default1,
-                                bool omitIfConstVec) {
-    SkASSERT(N > 0 && N <= 4);
-    SkASSERT(NULL != outAppend);
-
-    bool has0 = NULL != in0 && '\0' != *in0;
-    bool has1 = NULL != in1 && '\0' != *in1;
-
-    SkASSERT(has0 || kNone_GrSLConstantVec != default0);
-    SkASSERT(has1 || kNone_GrSLConstantVec != default1);
-
-    if (!has0 && !has1) {
-        SkASSERT(kZeros_GrSLConstantVec == default0 || kOnes_GrSLConstantVec == default0);
-        SkASSERT(kZeros_GrSLConstantVec == default1 || kOnes_GrSLConstantVec == default1);
-        if (kZeros_GrSLConstantVec == default0 || kZeros_GrSLConstantVec == default1) {
-            return return_const_vecf<N>(kZeros_GrSLConstantVec, outAppend, omitIfConstVec);
-        } else {
-            // both inputs are ones vectors
-            return return_const_vecf<N>(kOnes_GrSLConstantVec, outAppend, omitIfConstVec);
-        }
-    } else if (!has0) {
-        SkASSERT(kZeros_GrSLConstantVec == default0 || kOnes_GrSLConstantVec == default0);
-        if (kZeros_GrSLConstantVec == default0) {
-            return return_const_vecf<N>(kZeros_GrSLConstantVec, outAppend, omitIfConstVec);
-        } else {
-            outAppend->appendf("%s(%s)", GrGLSLFloatVectorTypeString(N), in1);
-            return kNone_GrSLConstantVec;
-        }
-    } else if (!has1) {
-        SkASSERT(kZeros_GrSLConstantVec == default1 || kOnes_GrSLConstantVec == default1);
-        if (kZeros_GrSLConstantVec == default1) {
-            return return_const_vecf<N>(kZeros_GrSLConstantVec, outAppend, omitIfConstVec);
-        } else {
-            outAppend->appendf("%s(%s)", GrGLSLFloatVectorTypeString(N), in0);
-            return kNone_GrSLConstantVec;
-        }
-    } else {
-        outAppend->appendf("%s((%s) * (%s))", GrGLSLFloatVectorTypeString(N), in0, in1);
-        return kNone_GrSLConstantVec;
+template<int N>
+template<int M>
+inline GrGLSLExpr<N> GrGLSLExpr<N>::Mul(const GrGLSLExpr<N>& in0, const GrGLSLExpr<M>& in1) {
+    SK_COMPILE_ASSERT(N == M || M == 1, binary_op_dimensions_incompatible);
+    if (in0.isZeros() || in1.isZeros()) {
+        return GrGLSLExpr<N>(0);
     }
+    if (in0.isOnes()) {
+        return VectorCast<M>(in1);
+    }
+    if (in1.isOnes()) {
+        return in0;
+    }
+    return GrGLSLExpr<N>("(%s * %s)", in0.c_str(), in1.c_str());
 }
 
-template <int N>
-GrSLConstantVec GrGLSLAddf(SkString* outAppend,
-                           const char* in0,
-                           const char* in1,
-                           GrSLConstantVec default0,
-                           GrSLConstantVec default1,
-                           bool omitIfConstVec) {
-    SkASSERT(N > 0 && N <= 4);
-    SkASSERT(NULL != outAppend);
-
-    bool has0 = NULL != in0 && '\0' != *in0;
-    bool has1 = NULL != in1 && '\0' != *in1;
-
-    if (!has0 && !has1) {
-        SkASSERT(kNone_GrSLConstantVec != default0);
-        SkASSERT(kNone_GrSLConstantVec != default1);
-        int sum = (kOnes_GrSLConstantVec == default0) + (kOnes_GrSLConstantVec == default1);
-        if (0 == sum) {
-            return return_const_vecf<N>(kZeros_GrSLConstantVec, outAppend, omitIfConstVec);
-        } else if (1 == sum) {
-            outAppend->append(GrGLSLOnesVecf(N));
-            return return_const_vecf<N>(kOnes_GrSLConstantVec, outAppend, omitIfConstVec);
-        } else {
-            SkASSERT(2 == sum);
-            outAppend->appendf("%s(2)", GrGLSLFloatVectorTypeString(N));
-            return kNone_GrSLConstantVec;
-        }
-    } else if (!has0) {
-        SkASSERT(kNone_GrSLConstantVec != default0);
-        if (kZeros_GrSLConstantVec == default0) {
-            outAppend->appendf("%s(%s)", GrGLSLFloatVectorTypeString(N), in1);
-        } else {
-            outAppend->appendf("%s(%s) + %s",
-                               GrGLSLFloatVectorTypeString(N),
-                               in1,
-                               GrGLSLOnesVecf(N));
-        }
-        return kNone_GrSLConstantVec;
-    } else if (!has1) {
-        SkASSERT(kNone_GrSLConstantVec != default1);
-        if (kZeros_GrSLConstantVec == default1) {
-            outAppend->appendf("%s(%s)", GrGLSLFloatVectorTypeString(N), in0);
-        } else {
-            outAppend->appendf("%s(%s) + %s",
-                               GrGLSLFloatVectorTypeString(N),
-                               in0,
-                               GrGLSLOnesVecf(N));
-        }
-        return kNone_GrSLConstantVec;
-    } else {
-        outAppend->appendf("(%s(%s) + %s(%s))",
-                           GrGLSLFloatVectorTypeString(N),
-                           in0,
-                           GrGLSLFloatVectorTypeString(N),
-                           in1);
-        return kNone_GrSLConstantVec;
+template<int N>
+template<int M>
+inline GrGLSLExpr<N> GrGLSLExpr<N>::Add(const GrGLSLExpr<N>& in0, const GrGLSLExpr<M>& in1) {
+    SK_COMPILE_ASSERT(N == M || M == 1, binary_op_dimensions_incompatible);
+    if (in1.isZeros()) {
+        return in0;
     }
+    if (in0.isZeros()) {
+        return VectorCast<M>(in1);
+    }
+    if (in0.isOnes() && in1.isOnes()) {
+        return GrGLSLExpr<N>(2);
+    }
+    return GrGLSLExpr<N>("(%s + %s)", in0.c_str(), in1.c_str());
 }
 
-template <int N>
-GrSLConstantVec GrGLSLSubtractf(SkString* outAppend,
-                                 const char* in0,
-                                 const char* in1,
-                                 GrSLConstantVec default0,
-                                 GrSLConstantVec default1,
-                                 bool omitIfConstVec) {
-    SkASSERT(N > 0 && N <= 4);
-    SkASSERT(NULL != outAppend);
-
-    bool has0 = NULL != in0 && '\0' != *in0;
-    bool has1 = NULL != in1 && '\0' != *in1;
-
-    if (!has0 && !has1) {
-        SkASSERT(kNone_GrSLConstantVec != default0);
-        SkASSERT(kNone_GrSLConstantVec != default1);
-        int diff = (kOnes_GrSLConstantVec == default0) - (kOnes_GrSLConstantVec == default1);
-        if (-1 == diff) {
-            outAppend->appendf("%s(-1)", GrGLSLFloatVectorTypeString(N));
-            return kNone_GrSLConstantVec;
-        } else if (0 == diff) {
-            return return_const_vecf<N>(kZeros_GrSLConstantVec, outAppend, omitIfConstVec);
-        } else {
-            SkASSERT(1 == diff);
-            return return_const_vecf<N>(kOnes_GrSLConstantVec, outAppend, omitIfConstVec);
-        }
-    } else if (!has0) {
-        SkASSERT(kNone_GrSLConstantVec != default0);
-        if (kZeros_GrSLConstantVec == default0) {
-            outAppend->appendf("-%s(%s)", GrGLSLFloatVectorTypeString(N), in1);
-        } else {
-            outAppend->appendf("%s - %s(%s)",
-                               GrGLSLOnesVecf(N),
-                               GrGLSLFloatVectorTypeString(N),
-                               in1);
-        }
-        return kNone_GrSLConstantVec;
-    } else if (!has1) {
-        SkASSERT(kNone_GrSLConstantVec != default1);
-        if (kZeros_GrSLConstantVec == default1) {
-            outAppend->appendf("%s(%s)", GrGLSLFloatVectorTypeString(N), in0);
-        } else {
-            outAppend->appendf("%s(%s) - %s",
-                               GrGLSLFloatVectorTypeString(N),
-                               in0,
-                               GrGLSLOnesVecf(N));
-        }
-        return kNone_GrSLConstantVec;
-    } else {
-        outAppend->appendf("(%s(%s) - %s(%s))",
-                           GrGLSLFloatVectorTypeString(N),
-                           in0,
-                           GrGLSLFloatVectorTypeString(N),
-                           in1);
-        return kNone_GrSLConstantVec;
+template<int N>
+template<int M>
+inline GrGLSLExpr<N> GrGLSLExpr<N>::Sub(const GrGLSLExpr<N>& in0, const GrGLSLExpr<M>& in1) {
+    SK_COMPILE_ASSERT(N == M || M == 1, binary_op_dimensions_incompatible);
+    if (in1.isZeros()) {
+        return in0;
     }
+    if (in1.isOnes()) {
+        if (in0.isOnes()) {
+            return GrGLSLExpr<N>(0);
+        }
+    }
+
+    return GrGLSLExpr<N>("(%s - %s)", in0.c_str(), in1.c_str());
+}
+
+inline GrGLSLExpr<4> GrGLSLExprCast4(const GrGLSLExpr<1>& expr) {
+    return GrGLSLExpr<4>::VectorCast(expr);
+}
+
+inline GrGLSLExpr<1> GrGLSLExprExtractAlpha(const GrGLSLExpr<4>& expr) {
+    if (expr.isZeros()) {
+        return GrGLSLExpr<1>(0);
+    }
+    if (expr.isOnes()) {
+        return GrGLSLExpr<1>(1);
+    }
+    return GrGLSLExpr<1>(GrGLSLExpr<4>::ExtractAlphaStr(), expr.c_str());
 }
 
 #endif
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index eb7cfa7..8b7d614 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -99,8 +99,6 @@
     , fFSOutputs(kMaxFSOutputs)
     , fUniforms(kVarsPerBlock)
     , fSetupFragPosition(false)
-    , fKnownColorValue(GrGLProgramDesc::KnownColorInputValue(desc.getHeader().fColorInput))
-    , fKnownCoverageValue(GrGLProgramDesc::KnownColorInputValue(desc.getHeader().fCoverageInput))
     , fHasCustomColorOutput(false)
     , fHasSecondaryOutput(false)
     , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFragPosKey) {
@@ -152,6 +150,10 @@
         fColorUniform = this->addUniform(GrGLShaderBuilder::kFragment_Visibility,
                                          kVec4f_GrSLType, "Color", &name);
         fInputColor = name;
+    } else if (GrGLProgramDesc::kSolidWhite_ColorInput == header.fColorInput) {
+        fInputColor = GrGLSLExpr<4>(1);
+    } else if (GrGLProgramDesc::kTransBlack_ColorInput == header.fColorInput) {
+        fInputColor = GrGLSLExpr<4>(0);
     }
 
     if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) {
@@ -159,6 +161,10 @@
         fCoverageUniform = this->addUniform(GrGLShaderBuilder::kFragment_Visibility,
                                             kVec4f_GrSLType, "Coverage", &name);
         fInputCoverage = name;
+    } else if (GrGLProgramDesc::kSolidWhite_ColorInput == header.fCoverageInput) {
+        fInputCoverage = GrGLSLExpr<4>(1);
+    } else if (GrGLProgramDesc::kTransBlack_ColorInput == header.fCoverageInput) {
+        fInputCoverage = GrGLSLExpr<4>(0);
     }
 
     if (k110_GrGLSLGeneration != fGpu->glslGeneration()) {
@@ -289,7 +295,7 @@
                                             GrSLType varyingType) {
     SkString lookup;
     this->appendTextureLookup(&lookup, sampler, coordName, varyingType);
-    GrGLSLModulatef<4>(&fFSCode, modulation, lookup.c_str());
+    fFSCode.append((GrGLSLExpr<4>(modulation) * GrGLSLExpr<4>(lookup)).c_str());
 }
 
 GrGLShaderBuilder::DstReadKey GrGLShaderBuilder::KeyForDstRead(const GrTexture* dstCopy,
@@ -509,12 +515,11 @@
                                              const GrEffectStage* effectStages[],
                                              const EffectKey effectKeys[],
                                              int effectCnt,
-                                             SkString* fsInOutColor,
-                                             GrSLConstantVec* fsInOutColorKnownValue) {
+                                             GrGLSLExpr<4>* fsInOutColor) {
     bool effectEmitted = false;
 
-    SkString inColor = *fsInOutColor;
-    SkString outColor;
+    GrGLSLExpr<4> inColor = *fsInOutColor;
+    GrGLSLExpr<4> outColor;
 
     for (int e = 0; e < effectCnt; ++e) {
         SkASSERT(NULL != effectStages[e] && NULL != effectStages[e]->getEffect());
@@ -522,24 +527,29 @@
 
         CodeStage::AutoStageRestore csar(&fCodeStage, &stage);
 
-        if (kZeros_GrSLConstantVec == *fsInOutColorKnownValue) {
+        if (inColor.isZeros()) {
+            SkString inColorName;
+
             // Effects have no way to communicate zeros, they treat an empty string as ones.
-            this->nameVariable(&inColor, '\0', "input");
-            this->fsCodeAppendf("\tvec4 %s = %s;\n", inColor.c_str(), GrGLSLZerosVecf(4));
+            this->nameVariable(&inColorName, '\0', "input");
+            this->fsCodeAppendf("\tvec4 %s = %s;\n", inColorName.c_str(), inColor.c_str());
+            inColor = inColorName;
         }
 
         // create var to hold stage result
-        this->nameVariable(&outColor, '\0', "output");
-        this->fsCodeAppendf("\tvec4 %s;\n", outColor.c_str());
+        SkString outColorName;
+        this->nameVariable(&outColorName, '\0', "output");
+        this->fsCodeAppendf("\tvec4 %s;\n", outColorName.c_str());
+        outColor = outColorName;
+
 
         programEffectsBuilder->emitEffect(stage,
                                           effectKeys[e],
                                           outColor.c_str(),
-                                          inColor.isEmpty() ? NULL : inColor.c_str(),
+                                          inColor.isOnes() ? NULL : inColor.c_str(),
                                           fCodeStage.stageIndex());
 
         inColor = outColor;
-        *fsInOutColorKnownValue = kNone_GrSLConstantVec;
         effectEmitted = true;
     }
 
@@ -829,16 +839,14 @@
         const GrEffectStage* effectStages[],
         const EffectKey effectKeys[],
         int effectCnt,
-        SkString* inOutFSColor,
-        GrSLConstantVec* fsInOutColorKnownValue) {
+        GrGLSLExpr<4>* inOutFSColor) {
 
     GrGLVertexProgramEffectsBuilder programEffectsBuilder(this, effectCnt);
     this->INHERITED::createAndEmitEffects(&programEffectsBuilder,
                                           effectStages,
                                           effectKeys,
                                           effectCnt,
-                                          inOutFSColor,
-                                          fsInOutColorKnownValue);
+                                          inOutFSColor);
     return programEffectsBuilder.finish();
 }
 
@@ -939,15 +947,13 @@
         const GrEffectStage* effectStages[],
         const EffectKey effectKeys[],
         int effectCnt,
-        SkString* inOutFSColor,
-        GrSLConstantVec* fsInOutColorKnownValue) {
+        GrGLSLExpr<4>* inOutFSColor) {
 
     GrGLTexGenProgramEffectsBuilder texGenEffectsBuilder(this, effectCnt);
     this->INHERITED::createAndEmitEffects(&texGenEffectsBuilder,
                                           effectStages,
                                           effectKeys,
                                           effectCnt,
-                                          inOutFSColor,
-                                          fsInOutColorKnownValue);
+                                          inOutFSColor);
     return texGenEffectsBuilder.finish();
 }
diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h
index 208c610..d7ba58e 100644
--- a/src/gpu/gl/GrGLShaderBuilder.h
+++ b/src/gpu/gl/GrGLShaderBuilder.h
@@ -167,40 +167,26 @@
 
     /**
      * Interfaces used by GrGLProgram.
-     * TODO: These are used by GrGLProgram to insert a mode color filter. Remove these when the
-     * color filter is expressed as a GrEffect.
      */
-    const SkString& getInputColor() const {
-        SkASSERT(fInputColor.isEmpty() != (kNone_GrSLConstantVec == fKnownColorValue));
+    const GrGLSLExpr<4>& getInputColor() const {
         return fInputColor;
     }
-    GrSLConstantVec getKnownColorValue() const {
-        SkASSERT(fInputColor.isEmpty() != (kNone_GrSLConstantVec == fKnownColorValue));
-        return fKnownColorValue;
-    }
-    const SkString& getInputCoverage() const {
-        SkASSERT(fInputCoverage.isEmpty() != (kNone_GrSLConstantVec == fKnownCoverageValue));
+    const GrGLSLExpr<4>& getInputCoverage() const {
         return fInputCoverage;
     }
-    GrSLConstantVec getKnownCoverageValue() const {
-        SkASSERT(fInputCoverage.isEmpty() != (kNone_GrSLConstantVec == fKnownCoverageValue));
-        return fKnownCoverageValue;
-    }
 
     /**
      * Adds code for effects and returns a GrGLProgramEffects* object. The caller is responsible for
      * deleting it when finished. effectStages contains the effects to add. effectKeys[i] is the key
      * generated from effectStages[i]. inOutFSColor specifies the input color to the first stage and
-     * is updated to be the output color of the last stage. fsInOutColorKnownValue specifies whether
-     * the input color has a known constant value and is updated to refer to the status of the
-     * output color. The handles to texture samplers for effectStage[i] are added to
+     * is updated to be the output color of the last stage.
+     * The handles to texture samplers for effectStage[i] are added to
      * effectSamplerHandles[i].
      */
     virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
                                                      const EffectKey effectKeys[],
                                                      int effectCnt,
-                                                     SkString* inOutFSColor,
-                                                     GrSLConstantVec* fsInOutColorKnownValue) = 0;
+                                                     GrGLSLExpr<4>* inOutFSColor) = 0;
 
     const char* getColorOutputName() const;
     const char* enableSecondaryOutput();
@@ -225,8 +211,8 @@
 protected:
     GrGpuGL* gpu() const { return fGpu; }
 
-    void setInputColor(const char* inputColor) { fInputColor = inputColor; }
-    void setInputCoverage(const char* inputCoverage) { fInputCoverage = inputCoverage; }
+    void setInputColor(const GrGLSLExpr<4>& inputColor) { fInputColor = inputColor; }
+    void setInputCoverage(const GrGLSLExpr<4>& inputCoverage) { fInputCoverage = inputCoverage; }
 
     /** Add input/output variable declarations (i.e. 'varying') to the fragment shader. */
     GrGLShaderVar& fsInputAppend() { return fFSInputs.push_back(); }
@@ -241,8 +227,7 @@
                               const GrEffectStage* effectStages[],
                               const EffectKey effectKeys[],
                               int effectCnt,
-                              SkString* inOutFSColor,
-                              GrSLConstantVec* fsInOutColorKnownValue);
+                              GrGLSLExpr<4>* inOutFSColor);
 
     virtual bool compileAndAttachShaders(GrGLuint programId) const;
     virtual void bindProgramLocations(GrGLuint programId) const;
@@ -344,10 +329,8 @@
     bool                                    fSetupFragPosition;
     GrGLUniformManager::UniformHandle       fDstCopySamplerUniform;
 
-    SkString                                fInputColor;
-    GrSLConstantVec                         fKnownColorValue;
-    SkString                                fInputCoverage;
-    GrSLConstantVec                         fKnownCoverageValue;
+    GrGLSLExpr<4>                           fInputColor;
+    GrGLSLExpr<4>                           fInputCoverage;
 
     bool                                    fHasCustomColorOutput;
     bool                                    fHasSecondaryOutput;
@@ -413,8 +396,7 @@
                 const GrEffectStage* effectStages[],
                 const EffectKey effectKeys[],
                 int effectCnt,
-                SkString* inOutFSColor,
-                GrSLConstantVec* fsInOutColorKnownValue) SK_OVERRIDE;
+                GrGLSLExpr<4>* inOutFSColor) SK_OVERRIDE;
 
     GrGLUniformManager::UniformHandle getViewMatrixUniform() const {
         return fViewMatrixUniform;
@@ -463,8 +445,7 @@
                 const GrEffectStage* effectStages[],
                 const EffectKey effectKeys[],
                 int effectCnt,
-                SkString* inOutFSColor,
-                GrSLConstantVec* fsInOutColorKnownValue) SK_OVERRIDE;
+                GrGLSLExpr<4>* inOutFSColor) SK_OVERRIDE;
 
 private:
     int fNumTexCoordSets;