Two and three color GPU gradients without textures.

R=bsalomon@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@11158 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index ca6386a..f1b5e58 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -831,28 +831,113 @@
 
 GrGLGradientEffect::~GrGLGradientEffect() { }
 
-void GrGLGradientEffect::emitYCoordUniform(GrGLShaderBuilder* builder) {
-    fFSYUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
-                                  kFloat_GrSLType, "GradientYCoordFS");
+void GrGLGradientEffect::emitUniforms(GrGLShaderBuilder* builder, EffectKey key) {
+
+    if (GrGradientEffect::kTwo_ColorType == ColorTypeFromKey(key)) { // 2 Color case
+        fColorStartUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+                                             kVec4f_GrSLType, "GradientStartColor");
+        fColorEndUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+                                           kVec4f_GrSLType, "GradientEndColor");
+        
+    } else if (GrGradientEffect::kThree_ColorType == ColorTypeFromKey(key)){ // 3 Color Case
+        fColorStartUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+                                             kVec4f_GrSLType, "GradientStartColor");
+        fColorMidUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+                                           kVec4f_GrSLType, "GradientMidColor");
+        fColorEndUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+                                             kVec4f_GrSLType, "GradientEndColor");
+
+    } else { // if not a fast case
+        fFSYUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+                                      kFloat_GrSLType, "GradientYCoordFS");
+    }
+}
+
+static inline void set_color_uni(const GrGLUniformManager& uman,
+                                 const GrGLUniformManager::UniformHandle uni,
+                                 const SkColor* color) {
+       uman.set4f(uni,
+                  SkColorGetR(*color) / 255.f,
+                  SkColorGetG(*color) / 255.f,
+                  SkColorGetB(*color) / 255.f,
+                  SkColorGetA(*color) / 255.f);
+}
+
+static inline void set_mul_color_uni(const GrGLUniformManager& uman,
+                                     const GrGLUniformManager::UniformHandle uni,
+                                     const SkColor* color){
+       float a = SkColorGetA(*color) / 255.f;
+       float aDiv255 = a / 255.f;
+       uman.set4f(uni,
+                  SkColorGetR(*color) * aDiv255,
+                  SkColorGetG(*color) * aDiv255,
+                  SkColorGetB(*color) * aDiv255,
+                  a);
 }
 
 void GrGLGradientEffect::setData(const GrGLUniformManager& uman,
                                  const GrDrawEffect& drawEffect) {
-    const GrGradientEffect& e = drawEffect.castEffect<GrGradientEffect>();
-    const GrTexture* texture = e.texture(0);
-    fEffectMatrix.setData(uman, e.getMatrix(), drawEffect, texture);
 
-    SkScalar yCoord = e.getYCoord();
-    if (yCoord != fCachedYCoord) {
-        uman.set1f(fFSYUni, yCoord);
-        fCachedYCoord = yCoord;
+    const GrGradientEffect& e = drawEffect.castEffect<GrGradientEffect>();
+
+
+    if (GrGradientEffect::kTwo_ColorType == e.getColorType()){
+
+        fEffectMatrix.setData(uman, e.getMatrix(), drawEffect, NULL);
+        if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
+            set_mul_color_uni(uman, fColorStartUni, e.getColors(0));
+            set_mul_color_uni(uman, fColorEndUni,   e.getColors(1));
+        } else {
+            set_color_uni(uman, fColorStartUni, e.getColors(0));
+            set_color_uni(uman, fColorEndUni,   e.getColors(1));
+        }
+
+    } else if (GrGradientEffect::kThree_ColorType == e.getColorType()){
+
+        fEffectMatrix.setData(uman, e.getMatrix(), drawEffect, NULL);
+        if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
+            set_mul_color_uni(uman, fColorStartUni, e.getColors(0));
+            set_mul_color_uni(uman, fColorMidUni,   e.getColors(1));
+            set_mul_color_uni(uman, fColorEndUni,   e.getColors(2));
+        } else {
+            set_color_uni(uman, fColorStartUni, e.getColors(0));
+            set_color_uni(uman, fColorMidUni,   e.getColors(1));
+            set_color_uni(uman, fColorEndUni,   e.getColors(2));
+        }
+    } else {
+        const GrTexture* texture = e.texture(0);
+        fEffectMatrix.setData(uman, e.getMatrix(), drawEffect, texture);
+        
+        SkScalar yCoord = e.getYCoord();
+        if (yCoord != fCachedYCoord) {
+            uman.set1f(fFSYUni, yCoord);
+            fCachedYCoord = yCoord;
+        }
     }
 }
 
-GrGLEffect::EffectKey GrGLGradientEffect::GenMatrixKey(const GrDrawEffect& drawEffect) {
+
+GrGLEffect::EffectKey GrGLGradientEffect::GenBaseGradientKey(const GrDrawEffect& drawEffect) {
     const GrGradientEffect& e = drawEffect.castEffect<GrGradientEffect>();
-    const GrTexture* texture = e.texture(0);
-    return GrGLEffectMatrix::GenKey(e.getMatrix(), drawEffect, kCoordsType, texture);
+    const GrTexture* texture = NULL;
+    
+    if (GrGradientEffect::kTexture_ColorType == e.getColorType()){
+        texture = e.texture(0);
+    }
+    
+    EffectKey key = GrGLEffectMatrix::GenKey(e.getMatrix(), drawEffect, kCoordsType, texture);
+
+    if (GrGradientEffect::kTwo_ColorType == e.getColorType()) {
+        key |= kTwoColorKey;
+    } else if (GrGradientEffect::kThree_ColorType == e.getColorType()){
+        key |= kThreeColorKey;
+    }
+
+    if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
+        key |= kPremulBeforeInterpKey;
+    }
+
+    return key;
 }
 
 void GrGLGradientEffect::setupMatrix(GrGLShaderBuilder* builder,
@@ -867,18 +952,57 @@
                                          vsVaryingType);
 }
 
-void GrGLGradientEffect::emitColorLookup(GrGLShaderBuilder* builder,
-                                         const char* gradientTValue,
-                                         const char* outputColor,
-                                         const char* inputColor,
-                                         const GrGLShaderBuilder::TextureSampler& sampler) {
+void GrGLGradientEffect::emitColor(GrGLShaderBuilder* builder,
+                                   const char* gradientTValue,
+                                   EffectKey key,
+                                   const char* outputColor,
+                                   const char* inputColor,
+                                   const GrGLShaderBuilder::TextureSamplerArray& samplers) {
+    if (GrGradientEffect::kTwo_ColorType == ColorTypeFromKey(key)){
+        builder->fsCodeAppendf("\tvec4 colorTemp = mix(%s, %s, clamp(%s, 0.0, 1.0));\n",
+                               builder->getUniformVariable(fColorStartUni).c_str(),
+                               builder->getUniformVariable(fColorEndUni).c_str(),
+                               gradientTValue);
+        // Note that we could skip this step if both colors are known to be opaque. Two
+        // considerations:
+        // The gradient SkShader reporting opaque is more restrictive than necessary in the two pt
+        // case. Make sure the key reflects this optimization (and note that it can use the same
+        // shader as thekBeforeIterp case). This same optimization applies to the 3 color case below.
+        if (GrGradientEffect::kAfterInterp_PremulType == PremulTypeFromKey(key)) {
+            builder->fsCodeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
+        }
 
-    builder->fsCodeAppendf("\tvec2 coord = vec2(%s, %s);\n",
-                           gradientTValue,
-                           builder->getUniformVariable(fFSYUni).c_str());
-    builder->fsCodeAppendf("\t%s = ", outputColor);
-    builder->fsAppendTextureLookupAndModulate(inputColor, sampler, "coord");
-    builder->fsCodeAppend(";\n");
+        SkString output;
+        builder->fsCodeAppendf("\t%s = ", outputColor);
+        GrGLSLModulatef<4>(&output, inputColor, "colorTemp");
+        builder->fsCodeAppend(output.c_str());
+        builder->fsCodeAppend(";\n");
+    } else if (GrGradientEffect::kThree_ColorType == ColorTypeFromKey(key)){
+        builder->fsCodeAppendf("\tfloat oneMinus2t = 1.0 - (2.0 * (%s));\n",
+                               gradientTValue);
+        builder->fsCodeAppendf("\tvec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s +(1.0 - min(abs(oneMinus2t), 1.0)) * %s + clamp(-oneMinus2t, 0.0, 1.0) * %s;\n",
+                               builder->getUniformVariable(fColorStartUni).c_str(),
+                               builder->getUniformVariable(fColorMidUni).c_str(),
+                               builder->getUniformVariable(fColorEndUni).c_str());
+        if (GrGradientEffect::kAfterInterp_PremulType == PremulTypeFromKey(key)) {
+            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");
+    } else {
+        builder->fsCodeAppendf("\tvec2 coord = vec2(%s, %s);\n",
+                               gradientTValue,
+                               builder->getUniformVariable(fFSYUni).c_str());
+        builder->fsCodeAppendf("\t%s = ", outputColor);
+        builder->fsAppendTextureLookupAndModulate(inputColor,
+                                                  samplers[0],
+                                                  "coord");
+        builder->fsCodeAppend(";\n");
+    }
 }
 
 /////////////////////////////////////////////////////////////////////
@@ -887,48 +1011,77 @@
                                    const SkGradientShaderBase& shader,
                                    const SkMatrix& matrix,
                                    SkShader::TileMode tileMode) {
-    // TODO: check for simple cases where we don't need a texture:
-    //GradientInfo info;
-    //shader.asAGradient(&info);
-    //if (info.fColorCount == 2) { ...
+
 
     fMatrix = matrix;
-
-    SkBitmap bitmap;
-    shader.getGradientTableBitmap(&bitmap);
-
     fIsOpaque = shader.isOpaque();
 
-    GrTextureStripAtlas::Desc desc;
-    desc.fWidth  = bitmap.width();
-    desc.fHeight = 32;
-    desc.fRowHeight = bitmap.height();
-    desc.fContext = ctx;
-    desc.fConfig = SkBitmapConfig2GrPixelConfig(bitmap.config());
-    fAtlas = GrTextureStripAtlas::GetAtlas(desc);
-    SkASSERT(NULL != fAtlas);
+    SkShader::GradientInfo info;
+    SkScalar pos[3] = {0};
 
-    // We always filter the gradient table. Each table is one row of a texture, so always y-clamp.
-    GrTextureParams params;
-    params.setFilterMode(GrTextureParams::kBilerp_FilterMode);
-    params.setTileModeX(tileMode);
+    info.fColorCount = 3;
+    info.fColors = &fColors[0];
+    info.fColorOffsets = &pos[0];
+    shader.asAGradient(&info);
 
-    fRow = fAtlas->lockRow(bitmap);
-    if (-1 != fRow) {
-        fYCoord = fAtlas->getYOffset(fRow) + SK_ScalarHalf *
-                  fAtlas->getVerticalScaleFactor();
-        fTextureAccess.reset(fAtlas->getTexture(), params);
-    } else {
-        GrTexture* texture = GrLockAndRefCachedBitmapTexture(ctx, bitmap, &params);
-        fTextureAccess.reset(texture, params);
-        fYCoord = SK_ScalarHalf;
-
-        // Unlock immediately, this is not great, but we don't have a way of
-        // knowing when else to unlock it currently, so it may get purged from
-        // the cache, but it'll still be ref'd until it's no longer being used.
-        GrUnlockAndUnrefCachedBitmapTexture(texture);
+    // The two and three color specializations do not currently support tiling.
+    bool foundSpecialCase = false;
+    if (SkShader::kClamp_TileMode == info.fTileMode) {
+        if (2 == info.fColorCount) {
+            fRow = -1; // flag for no atlas
+            fColorType = kTwo_ColorType;
+            foundSpecialCase = true;
+        } else if (3 == info.fColorCount &&
+                   (SkScalarAbs(pos[1] - SK_ScalarHalf) < SK_Scalar1 / 1000)) { // 3 color symmetric
+            fRow = -1; // flag for no atlas
+            fColorType = kThree_ColorType;
+            foundSpecialCase = true;
+        }
     }
-    this->addTextureAccess(&fTextureAccess);
+    if (foundSpecialCase) {
+        if (SkGradientShader::kInterpolateColorsInPremul_Flag & info.fGradientFlags) {
+            fPremulType = kBeforeInterp_PremulType;
+        } else {
+            fPremulType = kAfterInterp_PremulType;
+        }
+    } else {
+        // doesn't matter how this is set, just be consistent because it is part of the effect key.
+        fPremulType = kBeforeInterp_PremulType;
+        SkBitmap bitmap;
+        shader.getGradientTableBitmap(&bitmap);
+        fColorType = kTexture_ColorType;
+        
+        GrTextureStripAtlas::Desc desc;
+        desc.fWidth  = bitmap.width();
+        desc.fHeight = 32;
+        desc.fRowHeight = bitmap.height();
+        desc.fContext = ctx;
+        desc.fConfig = SkBitmapConfig2GrPixelConfig(bitmap.config());
+        fAtlas = GrTextureStripAtlas::GetAtlas(desc);
+        SkASSERT(NULL != fAtlas);
+
+        // We always filter the gradient table. Each table is one row of a texture, always y-clamp.
+        GrTextureParams params;
+        params.setFilterMode(GrTextureParams::kBilerp_FilterMode);
+        params.setTileModeX(tileMode);
+
+        fRow = fAtlas->lockRow(bitmap);
+        if (-1 != fRow) {
+            fYCoord = fAtlas->getYOffset(fRow) + SK_ScalarHalf *
+            fAtlas->getVerticalScaleFactor();
+            fTextureAccess.reset(fAtlas->getTexture(), params);
+        } else {
+            GrTexture* texture = GrLockAndRefCachedBitmapTexture(ctx, bitmap, &params);
+            fTextureAccess.reset(texture, params);
+            fYCoord = SK_ScalarHalf;
+
+            // Unlock immediately, this is not great, but we don't have a way of
+            // knowing when else to unlock it currently, so it may get purged from
+            // the cache, but it'll still be ref'd until it's no longer being used.
+            GrUnlockAndUnrefCachedBitmapTexture(texture);
+        }
+        this->addTextureAccess(&fTextureAccess);
+    }
 }
 
 GrGradientEffect::~GrGradientEffect() {
@@ -939,12 +1092,31 @@
 
 bool GrGradientEffect::onIsEqual(const GrEffect& effect) const {
     const GrGradientEffect& s = CastEffect<GrGradientEffect>(effect);
-    return fTextureAccess.getTexture() == s.fTextureAccess.getTexture()  &&
-           fTextureAccess.getParams().getTileModeX() ==
+
+    if (this->fColorType == s.getColorType()){
+
+        if (kTwo_ColorType == fColorType) {
+            if (*this->getColors(0) != *s.getColors(0) ||
+                *this->getColors(1) != *s.getColors(1)) {
+                return false;
+            }
+        } else if (kThree_ColorType == fColorType) {
+            if (*this->getColors(0) != *s.getColors(0) ||
+                *this->getColors(1) != *s.getColors(1) ||
+                *this->getColors(2) != *s.getColors(2)) {
+                return false;
+            }
+        }
+        
+        return fTextureAccess.getTexture() == s.fTextureAccess.getTexture()  &&
+            fTextureAccess.getParams().getTileModeX() ==
                 s.fTextureAccess.getParams().getTileModeX() &&
-           this->useAtlas() == s.useAtlas() &&
-           fYCoord == s.getYCoord() &&
-           fMatrix.cheapEqualTo(s.getMatrix());
+            this->useAtlas() == s.useAtlas() &&
+            fYCoord == s.getYCoord() &&
+            fMatrix.cheapEqualTo(s.getMatrix());
+    }
+
+    return false;
 }
 
 void GrGradientEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index 8e93604..451bd2d 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -250,6 +250,27 @@
     const SkMatrix& getMatrix() const { return fMatrix;}
 
     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
+    
+    enum ColorType {
+        kTwo_ColorType,
+        kThree_ColorType,
+        kTexture_ColorType
+    };
+
+    ColorType getColorType() const { return fColorType; }
+
+    enum PremulType {
+        kBeforeInterp_PremulType,
+        kAfterInterp_PremulType,
+    };
+
+    PremulType getPremulType() const { return fPremulType; }
+
+    const SkColor* getColors(int pos) const {
+        SkASSERT(fColorType != kTexture_ColorType);
+        SkASSERT((pos-1) <= fColorType);
+        return &fColors[pos];
+    }
 
 protected:
 
@@ -270,13 +291,20 @@
 
 private:
 
+    enum {
+        kMaxAnalyticColors = 3 // if more colors use texture
+    };
+
     GrTextureAccess fTextureAccess;
     SkScalar fYCoord;
     GrTextureStripAtlas* fAtlas;
     int fRow;
     SkMatrix fMatrix;
     bool fIsOpaque;
-
+    ColorType fColorType;
+    SkColor fColors[kMaxAnalyticColors];
+    PremulType fPremulType; // This only changes behavior for two and three color special cases.
+                            // It is already baked into to the table for texture gradients.
     typedef GrEffect INHERITED;
 
 };
@@ -299,13 +327,42 @@
     enum {
         kMatrixKeyBitCnt = GrGLEffectMatrix::kKeyBits,
         kMatrixKeyMask = (1 << kMatrixKeyBitCnt) - 1,
+
+        kPremulTypeKeyBitCnt = 1,
+        kPremulTypeMask = 1 << kMatrixKeyBitCnt,
+        kPremulBeforeInterpKey = kPremulTypeMask,
+
+        kTwoColorKey = 2 << (kMatrixKeyBitCnt + kPremulTypeKeyBitCnt),
+        kThreeColorKey = 3 << (kMatrixKeyBitCnt + kPremulTypeKeyBitCnt),
+        kColorKeyMask = kTwoColorKey | kThreeColorKey,
+        kColorKeyBitCnt = 2,
+
+        // Subclasses must shift any key bits they produce up by this amount
+        // and combine with the result of GenBaseGradientKey.
+        kBaseKeyBitCnt = (kMatrixKeyBitCnt + kPremulTypeKeyBitCnt + kColorKeyBitCnt)
     };
 
+    static GrGradientEffect::ColorType ColorTypeFromKey(EffectKey key){
+        if (kTwoColorKey == (key & kColorKeyMask)) {
+            return GrGradientEffect::kTwo_ColorType;
+        } else if (kThreeColorKey == (key & kColorKeyMask)) {
+            return GrGradientEffect::kThree_ColorType;
+        } else {return GrGradientEffect::kTexture_ColorType;}
+    }
+
+    static GrGradientEffect::PremulType PremulTypeFromKey(EffectKey key){
+        if (kPremulBeforeInterpKey == (key & kPremulTypeMask)) {
+            return GrGradientEffect::kBeforeInterp_PremulType;
+        } else {
+            return GrGradientEffect::kAfterInterp_PremulType;
+        }
+    }
+
     /**
-     * Subclasses must call this. It will return a value restricted to the lower kMatrixKeyBitCnt
+     * Subclasses must call this. It will return a value restricted to the lower kBaseKeyBitCnt
      * bits.
      */
-    static EffectKey GenMatrixKey(const GrDrawEffect&);
+    static EffectKey GenBaseGradientKey(const GrDrawEffect&);
 
     /**
      * Inserts code to implement the GrGradientEffect's matrix. This should be called before a
@@ -323,22 +380,27 @@
 
     // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses
     // should call this method from their emitCode().
-    void emitYCoordUniform(GrGLShaderBuilder* builder);
+    void emitUniforms(GrGLShaderBuilder* builder, EffectKey key);
 
-    // emit code that gets a fragment's color from an expression for t; for now this always uses the
-    // texture, but for simpler cases we'll be able to lerp. Subclasses should call this method from
-    // their emitCode().
-    void emitColorLookup(GrGLShaderBuilder* builder,
-                         const char* gradientTValue,
-                         const char* outputColor,
-                         const char* inputColor,
-                         const GrGLShaderBuilder::TextureSampler&);
+
+    // emit code that gets a fragment's color from an expression for t; Has branches for 3 separate
+    // control flows inside -- 2 color gradients, 3 color symmetric gradients (both using
+    // native GLSL mix), and 4+ color gradients that use the traditional texture lookup.
+    void emitColor(GrGLShaderBuilder* builder,
+                   const char* gradientTValue,
+                   EffectKey key,
+                   const char* outputColor,
+                   const char* inputColor,
+                   const GrGLShaderBuilder::TextureSamplerArray& samplers);
 
 private:
     static const GrEffect::CoordsType kCoordsType = GrEffect::kLocal_CoordsType;
 
     SkScalar fCachedYCoord;
     GrGLUniformManager::UniformHandle fFSYUni;
+    GrGLUniformManager::UniformHandle fColorStartUni;
+    GrGLUniformManager::UniformHandle fColorMidUni;
+    GrGLUniformManager::UniformHandle fColorEndUni;
     GrGLEffectMatrix fEffectMatrix;
 
     typedef GrGLEffect INHERITED;
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index 76a44a2..0b2854e 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -1,4 +1,3 @@
-
 /*
  * Copyright 2012 Google Inc.
  *
@@ -452,7 +451,7 @@
                           const TextureSamplerArray&) SK_OVERRIDE;
 
     static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
-        return GenMatrixKey(drawEffect);
+        return GenBaseGradientKey(drawEffect);
     }
 
 private:
@@ -524,13 +523,13 @@
                                   const char* outputColor,
                                   const char* inputColor,
                                   const TextureSamplerArray& samplers) {
-    this->emitYCoordUniform(builder);
+    this->emitUniforms(builder, key);
     SkString coords;
     this->setupMatrix(builder, key, &coords);
     SkString t;
     t.append(coords);
     t.append(".x");
-    this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]);
+    this->emitColor(builder, t.c_str(), key, outputColor, inputColor, samplers);
 }
 
 /////////////////////////////////////////////////////////////////////
diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp
index 9fcce68..9f32303 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -484,7 +484,7 @@
                           const TextureSamplerArray&) SK_OVERRIDE;
 
     static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
-        return GenMatrixKey(drawEffect);
+        return GenBaseGradientKey(drawEffect);
     }
 
 private:
@@ -558,13 +558,13 @@
                                   const char* outputColor,
                                   const char* inputColor,
                                   const TextureSamplerArray& samplers) {
-    this->emitYCoordUniform(builder);
+    this->emitUniforms(builder, key);
     SkString coords;
     this->setupMatrix(builder, key, &coords);
     SkString t("length(");
     t.append(coords);
     t.append(")");
-    this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]);
+    this->emitColor(builder, t.c_str(), key, outputColor, inputColor, samplers);
 }
 
 /////////////////////////////////////////////////////////////////////
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index 2af20b0..350b20a 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -405,7 +405,7 @@
                           const TextureSamplerArray&) SK_OVERRIDE;
 
     static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
-        return GenMatrixKey(drawEffect);
+        return GenBaseGradientKey(drawEffect);
     }
 
 private:
@@ -472,12 +472,13 @@
                                  const char* outputColor,
                                  const char* inputColor,
                                  const TextureSamplerArray& samplers) {
-    this->emitYCoordUniform(builder);
+    this->emitUniforms(builder, key);
     SkString coords;
     this->setupMatrix(builder, key, &coords);
     SkString t;
     t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5", coords.c_str(), coords.c_str());
-    this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]);
+    this->emitColor(builder, t.c_str(), key, 
+                          outputColor, inputColor, samplers);
 }
 
 /////////////////////////////////////////////////////////////////////
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp
index cf9cb98..9a23071 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -1,4 +1,3 @@
-
 /*
  * Copyright 2012 Google Inc.
  *
@@ -495,7 +494,7 @@
     GrSLType coordsVaryingType;
     this->setupMatrix(builder, key, &fsCoords, &vsCoordsVarying, &coordsVaryingType);
 
-    this->emitYCoordUniform(builder);
+    this->emitUniforms(builder, key);
     // 2 copies of uniform array, 1 for each of vertex & fragment shader,
     // to work around Xoom bug. Doesn't seem to cause performance decrease
     // in test apps, but need to keep an eye on it.
@@ -617,7 +616,7 @@
                                    p5.c_str(), p3.c_str());
 
             builder->fsCodeAppend("\t\t");
-            this->emitColorLookup(builder, tName.c_str(), outputColor, inputColor, samplers[0]);
+            this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers);
 
             // otherwise, if r(t) for the larger root was <= 0, try the other root
             builder->fsCodeAppend("\t\t} else {\n");
@@ -629,7 +628,7 @@
                                    tName.c_str(), p5.c_str(), p3.c_str());
 
             builder->fsCodeAppend("\t\t\t");
-            this->emitColorLookup(builder, tName.c_str(), outputColor, inputColor, samplers[0]);
+            this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers);
 
             // end if (r(t) > 0) for smaller root
             builder->fsCodeAppend("\t\t\t}\n");
@@ -647,7 +646,7 @@
             builder->fsCodeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
                                    p5.c_str(), p3.c_str());
             builder->fsCodeAppend("\t");
-            this->emitColorLookup(builder, tName.c_str(), outputColor, inputColor, samplers[0]);
+            this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers);
             builder->fsCodeAppend("\t}\n");
         }
     }
@@ -693,10 +692,10 @@
 GrGLEffect::EffectKey GrGLConical2Gradient::GenKey(const GrDrawEffect& drawEffect,
                                                    const GrGLCaps&) {
     enum {
-        kIsDegenerate = 1 << kMatrixKeyBitCnt,
+        kIsDegenerate = 1 << kBaseKeyBitCnt,
     };
 
-    EffectKey key = GenMatrixKey(drawEffect);
+    EffectKey key = GenBaseGradientKey(drawEffect);
     if (drawEffect.castEffect<GrConical2Gradient>().isDegenerate()) {
         key |= kIsDegenerate;
     }
diff --git a/src/effects/gradients/SkTwoPointRadialGradient.cpp b/src/effects/gradients/SkTwoPointRadialGradient.cpp
index e8ec736..b4b8402 100644
--- a/src/effects/gradients/SkTwoPointRadialGradient.cpp
+++ b/src/effects/gradients/SkTwoPointRadialGradient.cpp
@@ -532,9 +532,10 @@
                                    const char* inputColor,
                                    const TextureSamplerArray& samplers) {
 
-    this->emitYCoordUniform(builder);
+    this->emitUniforms(builder, key);
     SkString fsCoords;
     SkString vsCoordsVarying;
+
     GrSLType coordsVaryingType;
     this->setupMatrix(builder, key, &fsCoords, &vsCoordsVarying, &coordsVaryingType);
 
@@ -632,7 +633,7 @@
             t.printf("-%s / %s", cName.c_str(), bVar.c_str());
         }
 
-        this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]);
+        this->emitColor(builder, t.c_str(), key, outputColor, inputColor, samplers);
     }
 }
 
@@ -674,10 +675,10 @@
 GrGLEffect::EffectKey GrGLRadial2Gradient::GenKey(const GrDrawEffect& drawEffect,
                                                   const GrGLCaps&) {
     enum {
-        kIsDegenerate = 1 << kMatrixKeyBitCnt,
+        kIsDegenerate = 1 << kBaseKeyBitCnt,
     };
 
-    EffectKey key = GenMatrixKey(drawEffect);
+    EffectKey key = GenBaseGradientKey(drawEffect);
     if (drawEffect.castEffect<GrRadial2Gradient>().isDegenerate()) {
         key |= kIsDegenerate;
     }