Reland r6233 with fix for config conversion texture matrices.

git-svn-id: http://skia.googlecode.com/svn/trunk@6238 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 60eff91..78c7e34 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -678,7 +678,9 @@
 GrGLGradientEffect::GrGLGradientEffect(const GrBackendEffectFactory& factory)
     : INHERITED(factory)
     , fCachedYCoord(GR_ScalarMax)
-    , fFSYUni(GrGLUniformManager::kInvalidUniformHandle) { }
+    , fFSYUni(GrGLUniformManager::kInvalidUniformHandle) {
+    fRequiresTextureMatrix = false;
+}
 
 GrGLGradientEffect::~GrGLGradientEffect() { }
 
@@ -688,13 +690,37 @@
 }
 
 void GrGLGradientEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
-    GrScalar yCoord = static_cast<const GrGradientEffect&>(*stage.getEffect()).getYCoord();
+    const GrGradientEffect& e = static_cast<const GrGradientEffect&>(*stage.getEffect());
+    const GrTexture* texture = e.texture(0);
+    fEffectMatrix.setData(uman, e.getMatrix(), stage.getCoordChangeMatrix(), texture);
+
+    GrScalar yCoord = e.getYCoord();
     if (yCoord != fCachedYCoord) {
         uman.set1f(fFSYUni, yCoord);
         fCachedYCoord = yCoord;
     }
 }
 
+GrGLEffect::EffectKey GrGLGradientEffect::GenMatrixKey(const GrEffectStage& s) {
+    const GrGradientEffect& e = static_cast<const GrGradientEffect&>(*s.getEffect());
+    const GrTexture* texture = e.texture(0);
+    return GrGLEffectMatrix::GenKey(e.getMatrix(), s.getCoordChangeMatrix(), texture); 
+}
+
+void GrGLGradientEffect::setupMatrix(GrGLShaderBuilder* builder,
+                                     EffectKey key,
+                                     const char* vertexCoords,
+                                     const char** fsCoordName,
+                                     const char** vsVaryingName,
+                                     GrSLType* vsVaryingType) {
+    fEffectMatrix.emitCodeMakeFSCoords2D(builder,
+                                         key & kMatrixKeyMask,
+                                         vertexCoords,
+                                         fsCoordName,
+                                         vsVaryingName,
+                                         vsVaryingType);
+}
+
 void GrGLGradientEffect::emitColorLookup(GrGLShaderBuilder* builder,
                                          const char* gradientTValue,
                                          const char* outputColor,
@@ -714,6 +740,7 @@
 
 GrGradientEffect::GrGradientEffect(GrContext* ctx,
                                    const SkGradientShaderBase& shader,
+                                   const SkMatrix& matrix,
                                    SkShader::TileMode tileMode)
     : INHERITED(1) {
     // TODO: check for simple cases where we don't need a texture:
@@ -721,6 +748,8 @@
     //shader.asAGradient(&info);
     //if (info.fColorCount == 2) { ...
 
+    fMatrix = matrix;
+
     SkBitmap bitmap;
     shader.getGradientTableBitmap(&bitmap);
 
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index 9f14e7f..2437911 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -193,12 +193,13 @@
 #if SK_SUPPORT_GPU
 
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLEffectMatrix.h"
 
 class GrEffectStage;
 class GrBackendEffectFactory;
 
 /*
- * The intepretation of the texture matrix depends on the sample mode. The
+ * The interpretation of the texture matrix depends on the sample mode. The
  * texture matrix is applied both when the texture coordinates are explicit
  * and  when vertex positions are used as texture  coordinates. In the latter
  * case the texture matrix is applied to the pre-view-matrix position
@@ -228,6 +229,7 @@
 
     GrGradientEffect(GrContext* ctx,
                      const SkGradientShaderBase& shader,
+                     const SkMatrix& matrix,
                      SkShader::TileMode tileMode);
 
     virtual ~GrGradientEffect();
@@ -236,11 +238,12 @@
 
     bool useAtlas() const { return SkToBool(-1 != fRow); }
     GrScalar getYCoord() const { return fYCoord; };
+    const SkMatrix& getMatrix() const { return fMatrix;}
 
     virtual bool isEqual(const GrEffect& effect) const SK_OVERRIDE {
         const GrGradientEffect& s = static_cast<const GrGradientEffect&>(effect);
         return INHERITED::isEqual(effect) && this->useAtlas() == s.useAtlas() &&
-               fYCoord == s.getYCoord();
+               fYCoord == s.getYCoord() && fMatrix.cheapEqualTo(s.getMatrix());
     }
 
 protected:
@@ -263,6 +266,7 @@
     GrScalar fYCoord;
     GrTextureStripAtlas* fAtlas;
     int fRow;
+    SkMatrix fMatrix;
 
     typedef GrEffect INHERITED;
 
@@ -279,6 +283,36 @@
     virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
 
 protected:
+    /**
+     * Subclasses must reserve the lower kMatrixKeyBitCnt of their key for use by
+     * GrGLGradientEffect.
+     */
+    enum {
+        kMatrixKeyBitCnt = GrGLEffectMatrix::kKeyBits,
+        kMatrixKeyMask = (1 << kMatrixKeyBitCnt) - 1,
+    };
+
+    /**
+     * Subclasses must call this. It will return a value restricted to the lower kMatrixKeyBitCnt
+     * bits.
+     */
+    static EffectKey GenMatrixKey(const GrEffectStage& s);
+
+    /**
+     * Inserts code to implement the GrGradientEffect's matrix. This should be called before a
+     * subclass emits its own code. The name of the 2D coords is output via fsCoordName and already
+     * incorporates any perspective division. The caller can also optionally retrieve the name of
+     * the varying inserted in the VS and its type, which may be either vec2f or vec3f depending
+     * upon whether the matrix has perspective or not. It is not necessary to mask the key before
+     * calling.
+     */
+    void setupMatrix(GrGLShaderBuilder* builder,
+                     EffectKey key,
+                     const char* vertexCoords,
+                     const char** fsCoordName,
+                     const char** vsVaryingName = NULL,
+                     GrSLType* vsVaryingType = NULL);
+
     // 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);
@@ -295,6 +329,7 @@
 private:
     GrScalar fCachedYCoord;
     GrGLUniformManager::UniformHandle fFSYUni;
+    GrGLEffectMatrix fEffectMatrix;
 
     typedef GrGLEffect INHERITED;
 };
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index d957656..7161450 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -495,7 +495,9 @@
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
 
-    static EffectKey GenKey(const GrEffectStage&, const GrGLCaps& caps) { return 0; }
+    static EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
+        return GenMatrixKey(stage);
+    }
 
 private:
 
@@ -507,8 +509,11 @@
 class GrLinearGradient : public GrGradientEffect {
 public:
 
-    GrLinearGradient(GrContext* ctx, const SkLinearGradient& shader, SkShader::TileMode tm)
-        : INHERITED(ctx, shader, tm) { }
+    GrLinearGradient(GrContext* ctx,
+                     const SkLinearGradient& shader,
+                     const SkMatrix& matrix,
+                     SkShader::TileMode tm)
+        : INHERITED(ctx, shader, matrix, tm) { }
     virtual ~GrLinearGradient() { }
 
     static const char* Name() { return "Linear Gradient"; }
@@ -553,15 +558,18 @@
 /////////////////////////////////////////////////////////////////////
 
 void GrGLLinearGradient::emitCode(GrGLShaderBuilder* builder,
-                                  const GrEffectStage&,
-                                  EffectKey,
+                                  const GrEffectStage& stage,
+                                  EffectKey key,
                                   const char* vertexCoords,
                                   const char* outputColor,
                                   const char* inputColor,
                                   const TextureSamplerArray& samplers) {
     this->emitYCoordUniform(builder);
+    const char* coords;
+    this->setupMatrix(builder, key, vertexCoords, &coords);
     SkString t;
-    t.printf("%s.x", builder->defaultTexCoordsName());
+    t.append(coords);
+    t.append(".x");
     this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]);
 }
 
@@ -574,7 +582,7 @@
         return false;
     }
     matrix.postConcat(fPtsToUnit);
-    stage->setEffect(SkNEW_ARGS(GrLinearGradient, (context, *this, fTileMode)), matrix)->unref();
+    stage->setEffect(SkNEW_ARGS(GrLinearGradient, (context, *this, matrix, fTileMode)))->unref();
     return true;
 }
 
diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp
index a20ea35..02a56da 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -490,7 +490,9 @@
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
 
-    static EffectKey GenKey(const GrEffectStage&, const GrGLCaps& caps) { return 0; }
+    static EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
+        return GenMatrixKey(stage);
+    }
 
 private:
 
@@ -503,8 +505,11 @@
 class GrRadialGradient : public GrGradientEffect {
 public:
 
-    GrRadialGradient(GrContext* ctx, const SkRadialGradient& shader, SkShader::TileMode tm)
-        : INHERITED(ctx, shader, tm) {
+    GrRadialGradient(GrContext* ctx,
+                     const SkRadialGradient& shader,
+                     const SkMatrix& matrix,
+                     SkShader::TileMode tm)
+        : INHERITED(ctx, shader, matrix, tm) {
     }
 
     virtual ~GrRadialGradient() { }
@@ -551,15 +556,18 @@
 /////////////////////////////////////////////////////////////////////
 
 void GrGLRadialGradient::emitCode(GrGLShaderBuilder* builder,
-                                  const GrEffectStage&,
-                                  EffectKey,
+                                  const GrEffectStage& stage,
+                                  EffectKey key,
                                   const char* vertexCoords,
                                   const char* outputColor,
                                   const char* inputColor,
                                   const TextureSamplerArray& samplers) {
     this->emitYCoordUniform(builder);
-    SkString t;
-    t.printf("length(%s.xy)", builder->defaultTexCoordsName());
+    const char* coords;
+    this->setupMatrix(builder, key, vertexCoords, &coords);
+    SkString t("length(");
+    t.append(coords);
+    t.append(")");
     this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]);
 }
 
@@ -573,7 +581,7 @@
         return false;
     }
     matrix.postConcat(fPtsToUnit);
-    stage->setEffect(SkNEW_ARGS(GrRadialGradient, (context, *this, fTileMode)), matrix)->unref();
+    stage->setEffect(SkNEW_ARGS(GrRadialGradient, (context, *this, matrix, fTileMode)))->unref();
     return true;
 }
 
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index a783e37..589cf4a 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -399,7 +399,9 @@
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
 
-    static EffectKey GenKey(const GrEffectStage&, const GrGLCaps& caps) { return 0; }
+    static EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
+        return GenMatrixKey(stage);
+    }
 
 private:
 
@@ -413,8 +415,9 @@
 public:
 
     GrSweepGradient(GrContext* ctx,
-                    const SkSweepGradient& shader)
-    : INHERITED(ctx, shader, SkShader::kClamp_TileMode) { }
+                    const SkSweepGradient& shader,
+                    const SkMatrix& matrix)
+    : INHERITED(ctx, shader, matrix, SkShader::kClamp_TileMode) { }
     virtual ~GrSweepGradient() { }
 
     static const char* Name() { return "Sweep Gradient"; }
@@ -457,16 +460,17 @@
 /////////////////////////////////////////////////////////////////////
 
 void GrGLSweepGradient::emitCode(GrGLShaderBuilder* builder,
-                                 const GrEffectStage&,
-                                 EffectKey,
+                                 const GrEffectStage& stage,
+                                 EffectKey key,
                                  const char* vertexCoords,
                                  const char* outputColor,
                                  const char* inputColor,
                                  const TextureSamplerArray& samplers) {
     this->emitYCoordUniform(builder);
+    const char* coords;
+    this->setupMatrix(builder, key, vertexCoords, &coords);
     SkString t;
-    t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5",
-        builder->defaultTexCoordsName(), builder->defaultTexCoordsName());
+    t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5", coords, coords);
     this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]);
 }
 
@@ -478,7 +482,7 @@
         return false;
     }
     matrix.postConcat(fPtsToUnit);
-    stage->setEffect(SkNEW_ARGS(GrSweepGradient, (context, *this)), matrix)->unref();
+    stage->setEffect(SkNEW_ARGS(GrSweepGradient, (context, *this, matrix)))->unref();
     return true;
 }
 
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp
index f93f660..41292bb 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -371,8 +371,9 @@
 
     GrConical2Gradient(GrContext* ctx,
                        const SkTwoPointConicalGradient& shader,
+                       const SkMatrix& matrix,
                        SkShader::TileMode tm)
-        : INHERITED(ctx, shader, tm)
+        : INHERITED(ctx, shader, matrix, tm)
         , fCenterX1(shader.getCenterX1())
         , fRadius0(shader.getStartRadius())
         , fDiffRadius(shader.getDiffRadius()) { }
@@ -468,12 +469,17 @@
 }
 
 void GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder,
-                                    const GrEffectStage&,
-                                    EffectKey,
+                                    const GrEffectStage& stage,
+                                    EffectKey key,
                                     const char* vertexCoords,
                                     const char* outputColor,
                                     const char* inputColor,
                                     const TextureSamplerArray& samplers) {
+    const char* fsCoords;
+    const char* vsCoordsVarying;
+    GrSLType coordsVaryingType;
+    this->setupMatrix(builder, key, vertexCoords, &fsCoords, &vsCoordsVarying, &coordsVaryingType);
+
     this->emitYCoordUniform(builder);
     // 2 copies of uniform array, 1 for each of vertex & fragment shader,
     // to work around Xoom bug. Doesn't seem to cause performance decrease
@@ -485,7 +491,7 @@
 
     // For radial gradients without perspective we can pass the linear
     // part of the quadratic as a varying.
-    if (!builder->defaultTextureMatrixIsPerspective()) {
+    if (kVec2f_GrSLType == coordsVaryingType) {
         builder->addVarying(kFloat_GrSLType, "Conical2BCoeff",
                             &fVSVaryingName, &fFSVaryingName);
     }
@@ -502,11 +508,11 @@
 
         // For radial gradients without perspective we can pass the linear
         // part of the quadratic as a varying.
-        if (!builder->defaultTextureMatrixIsPerspective()) {
+        if (kVec2f_GrSLType == coordsVaryingType) {
             // r2Var = -2 * (r2Parm[2] * varCoord.x - r2Param[3] * r2Param[5])
             code->appendf("\t%s = -2.0 * (%s * %s.x + %s * %s);\n",
                           fVSVaryingName, p2.c_str(),
-                          vertexCoords, p3.c_str(), p5.c_str());
+                          vsCoordsVarying, p3.c_str(), p5.c_str());
         }
     }
 
@@ -538,12 +544,12 @@
         // If we we're able to interpolate the linear component,
         // bVar is the varying; otherwise compute it
         SkString bVar;
-        if (!builder->defaultTextureMatrixIsPerspective()) {
+        if (kVec2f_GrSLType == coordsVaryingType) {
             bVar = fFSVaryingName;
         } else {
             bVar = "b";
             code->appendf("\tfloat %s = -2.0 * (%s * %s.x + %s * %s);\n",
-                          bVar.c_str(), p2.c_str(), builder->defaultTexCoordsName(),
+                          bVar.c_str(), p2.c_str(), fsCoords,
                           p3.c_str(), p5.c_str());
         }
 
@@ -553,7 +559,7 @@
 
         // c = (x^2)+(y^2) - params[4]
         code->appendf("\tfloat %s = dot(%s, %s) - %s;\n", cName.c_str(),
-                      builder->defaultTexCoordsName(), builder->defaultTexCoordsName(),
+                      fsCoords, fsCoords,
                       p4.c_str());
 
         // Non-degenerate case (quadratic)
@@ -669,7 +675,15 @@
 }
 
 GrGLEffect::EffectKey GrGLConical2Gradient::GenKey(const GrEffectStage& s, const GrGLCaps&) {
-    return (static_cast<const GrConical2Gradient&>(*s.getEffect()).isDegenerate());
+    enum {
+        kIsDegenerate = 1 << kMatrixKeyBitCnt,
+    };
+
+    EffectKey key = GenMatrixKey(s);
+    if (static_cast<const GrConical2Gradient&>(*s.getEffect()).isDegenerate()) {
+        key |= kIsDegenerate;
+    }
+    return key;
 }
 
 /////////////////////////////////////////////////////////////////////
@@ -695,7 +709,7 @@
         matrix.postConcat(rot);
     }
 
-    stage->setEffect(SkNEW_ARGS(GrConical2Gradient, (context, *this, fTileMode)), matrix)->unref();
+    stage->setEffect(SkNEW_ARGS(GrConical2Gradient, (context, *this, matrix, fTileMode)))->unref();
 
     return true;
 }
diff --git a/src/effects/gradients/SkTwoPointRadialGradient.cpp b/src/effects/gradients/SkTwoPointRadialGradient.cpp
index 659bce0..d018629 100644
--- a/src/effects/gradients/SkTwoPointRadialGradient.cpp
+++ b/src/effects/gradients/SkTwoPointRadialGradient.cpp
@@ -404,8 +404,11 @@
 class GrRadial2Gradient : public GrGradientEffect {
 public:
 
-    GrRadial2Gradient(GrContext* ctx, const SkTwoPointRadialGradient& shader, SkShader::TileMode tm)
-        : INHERITED(ctx, shader, tm)
+    GrRadial2Gradient(GrContext* ctx,
+                      const SkTwoPointRadialGradient& shader,
+                      const SkMatrix& matrix,
+                      SkShader::TileMode tm)
+        : INHERITED(ctx, shader, matrix, tm)
         , fCenterX1(shader.getCenterX1())
         , fRadius0(shader.getStartRadius())
         , fPosRoot(shader.getDiffRadius() < 0) { }
@@ -501,14 +504,19 @@
 }
 
 void GrGLRadial2Gradient::emitCode(GrGLShaderBuilder* builder,
-                                   const GrEffectStage&,
-                                   EffectKey,
+                                   const GrEffectStage& stage,
+                                   EffectKey key,
                                    const char* vertexCoords,
                                    const char* outputColor,
                                    const char* inputColor,
                                    const TextureSamplerArray& samplers) {
 
     this->emitYCoordUniform(builder);
+    const char* fsCoords;
+    const char* vsCoordsVarying;
+    GrSLType coordsVaryingType;
+    this->setupMatrix(builder, key, vertexCoords, &fsCoords, &vsCoordsVarying, &coordsVaryingType);
+
     // 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.
@@ -519,9 +527,8 @@
 
     // For radial gradients without perspective we can pass the linear
     // part of the quadratic as a varying.
-    if (!builder->defaultTextureMatrixIsPerspective()) {
-        builder->addVarying(kFloat_GrSLType, "Radial2BCoeff",
-                          &fVSVaryingName, &fFSVaryingName);
+    if (kVec2f_GrSLType == coordsVaryingType) {
+        builder->addVarying(kFloat_GrSLType, "Radial2BCoeff", &fVSVaryingName, &fFSVaryingName);
     }
 
     // VS
@@ -534,11 +541,11 @@
 
         // For radial gradients without perspective we can pass the linear
         // part of the quadratic as a varying.
-        if (!builder->defaultTextureMatrixIsPerspective()) {
+        if (kVec2f_GrSLType == coordsVaryingType) {
             // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
             code->appendf("\t%s = 2.0 *(%s * %s.x - %s);\n",
                           fVSVaryingName, p2.c_str(),
-                          vertexCoords, p3.c_str());
+                          vsCoordsVarying, p3.c_str());
         }
     }
 
@@ -565,20 +572,19 @@
         // If we we're able to interpolate the linear component,
         // bVar is the varying; otherwise compute it
         SkString bVar;
-        if (!builder->defaultTextureMatrixIsPerspective()) {
+        if (kVec2f_GrSLType == coordsVaryingType) {
             bVar = fFSVaryingName;
         } else {
             bVar = "b";
             code->appendf("\tfloat %s = 2.0 * (%s * %s.x - %s);\n",
-                          bVar.c_str(), p2.c_str(),
-                          builder->defaultTexCoordsName(), p3.c_str());
+                          bVar.c_str(), p2.c_str(), fsCoords, p3.c_str());
         }
 
         // c = (x^2)+(y^2) - params[4]
         code->appendf("\tfloat %s = dot(%s, %s) - %s;\n",
                       cName.c_str(),
-                      builder->defaultTexCoordsName(),
-                      builder->defaultTexCoordsName(),
+                      fsCoords,
+                      fsCoords,
                       p4.c_str());
 
         // If we aren't degenerate, emit some extra code, and accept a slightly
@@ -643,7 +649,15 @@
 }
 
 GrGLEffect::EffectKey GrGLRadial2Gradient::GenKey(const GrEffectStage& s, const GrGLCaps&) {
-    return (static_cast<const GrRadial2Gradient&>(*s.getEffect()).isDegenerate());
+    enum {
+        kIsDegenerate = 1 << kMatrixKeyBitCnt,
+    };
+
+    EffectKey key = GenMatrixKey(s);
+    if (static_cast<const GrRadial2Gradient&>(*s.getEffect()).isDegenerate()) {
+        key |= kIsDegenerate;
+    }
+    return key;
 }
 
 /////////////////////////////////////////////////////////////////////
@@ -667,7 +681,7 @@
         matrix.postConcat(rot);
     }
 
-    stage->setEffect(SkNEW_ARGS(GrRadial2Gradient, (context, *this, fTileMode)), matrix)->unref();
+    stage->setEffect(SkNEW_ARGS(GrRadial2Gradient, (context, *this, matrix, fTileMode)))->unref();
     return true;
 }