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/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;