Make morphology, convolution, and table color filter opt out of default texture matrices.
Review URL: https://codereview.appspot.com/6817077

git-svn-id: http://skia.googlecode.com/svn/trunk@6280 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/gpu/GrBackendEffectFactory.h b/include/gpu/GrBackendEffectFactory.h
index c496f5a..7b43711 100644
--- a/include/gpu/GrBackendEffectFactory.h
+++ b/include/gpu/GrBackendEffectFactory.h
@@ -32,7 +32,7 @@
 public:
     typedef uint32_t EffectKey;
     enum {
-        kEffectKeyBits = 10,
+        kEffectKeyBits = 12,
         /**
          * Some aspects of the generated code may be determined by the particular textures that are
          * associated with the effect. These manipulations are performed by GrGLShaderBuilder beyond
@@ -64,12 +64,15 @@
     }
 
     static EffectKey GenID() {
+        static const int32_t kClassIDBits = 8 * sizeof(EffectKey) -
+                                            kTextureKeyBits -
+                                            kEffectKeyBits;
         // fCurrEffectClassID has been initialized to kIllegalEffectClassID. The
         // atomic inc returns the old value not the incremented value. So we add
         // 1 to the returned value.
         int32_t id = sk_atomic_inc(&fCurrEffectClassID) + 1;
-        GrAssert(id < (1 << (8 * sizeof(EffectKey) - kEffectKeyBits)));
-        return id;
+        GrAssert(id < (1 << kClassIDBits));
+        return static_cast<EffectKey>(id);
     }
 
     EffectKey fEffectClassID;
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
index 2c88f53..897b1cd 100644
--- a/src/effects/SkMorphologyImageFilter.cpp
+++ b/src/effects/SkMorphologyImageFilter.cpp
@@ -15,6 +15,7 @@
 #include "GrTexture.h"
 #include "GrTBackendEffectFactory.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLEffectMatrix.h"
 #include "effects/Gr1DKernelEffect.h"
 #endif
 
@@ -289,6 +290,7 @@
     int                                 fRadius;
     GrMorphologyEffect::MorphologyType  fType;
     GrGLUniformManager::UniformHandle   fImageIncrementUni;
+    GrGLEffectMatrix                    fEffectMatrix;
 
     typedef GrGLEffect INHERITED;
 };
@@ -300,15 +302,18 @@
     const GrMorphologyEffect& m = static_cast<const GrMorphologyEffect&>(effect);
     fRadius = m.radius();
     fType = m.type();
+    fRequiresTextureMatrix = false;
 }
 
 void GrGLMorphologyEffect::emitCode(GrGLShaderBuilder* builder,
                                     const GrEffectStage&,
-                                    EffectKey,
+                                    EffectKey key,
                                     const char* vertexCoords,
                                     const char* outputColor,
                                     const char* inputColor,
                                     const TextureSamplerArray& samplers) {
+    const char* coords;
+    fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, vertexCoords, &coords);
     fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                              kVec2f_GrSLType, "ImageIncrement");
 
@@ -331,8 +336,7 @@
     }
     const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
 
-    code->appendf("\t\tvec2 coord = %s - %d.0 * %s;\n",
-                   builder->defaultTexCoordsName(), fRadius, imgInc);
+    code->appendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords, fRadius, imgInc);
     code->appendf("\t\tfor (int i = 0; i < %d; i++) {\n", this->width());
     code->appendf("\t\t\t%s = %s(%s, ", outputColor, func, outputColor);
     builder->appendTextureLookup(&builder->fFSCode, samplers[0], "coord");
@@ -346,7 +350,11 @@
     const GrMorphologyEffect& m = static_cast<const GrMorphologyEffect&>(*s.getEffect());
     EffectKey key = static_cast<EffectKey>(m.radius());
     key |= (m.type() << 8);
-    return key;
+    key <<= GrGLEffectMatrix::kKeyBits;
+    EffectKey matrixKey = GrGLEffectMatrix::GenKey(m.getMatrix(),
+                                                   s.getCoordChangeMatrix(),
+                                                   m.texture(0));
+    return key | matrixKey;
 }
 
 void GrGLMorphologyEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
@@ -366,6 +374,7 @@
             GrCrash("Unknown filter direction.");
     }
     uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement);
+    fEffectMatrix.setData(uman, kern.getMatrix(), stage.getCoordChangeMatrix(), kern.texture(0));
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -420,10 +429,11 @@
                            int radius,
                            GrMorphologyEffect::MorphologyType morphType,
                            Gr1DKernelEffect::Direction direction) {
-    SkMatrix sampleM;
-    sampleM.setIDiv(texture->width(), texture->height());
     GrPaint paint;
-    paint.colorStage(0)->setEffect(SkNEW_ARGS(GrMorphologyEffect, (texture, direction, radius, morphType)), sampleM)->unref();
+    paint.colorStage(0)->setEffect(SkNEW_ARGS(GrMorphologyEffect, (texture,
+                                                                   direction,
+                                                                   radius,
+                                                                   morphType)))->unref();
     context->drawRect(paint, rect);
 }
 
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
index 0ae7e19..c23f2a5 100644
--- a/src/effects/SkTableColorFilter.cpp
+++ b/src/effects/SkTableColorFilter.cpp
@@ -270,6 +270,8 @@
 GLColorTableEffect::GLColorTableEffect(
     const GrBackendEffectFactory& factory, const GrEffect& effect)
     : INHERITED(factory) {
+    // texture coords are computed from the incoming color.
+    fRequiresTextureMatrix = false;
  }
 
 void GLColorTableEffect::emitCode(GrGLShaderBuilder* builder,
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 2ad5cf8..ceb37cd 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -199,12 +199,10 @@
     GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kReset_ASRInit);
     GrDrawState* drawState = target->drawState();
     drawState->setRenderTarget(rt);
-    SkMatrix sampleM;
-    sampleM.setIDiv(texture->width(), texture->height());
     SkAutoTUnref<GrConvolutionEffect> conv(SkNEW_ARGS(GrConvolutionEffect,
                                                       (texture, direction, radius,
                                                        sigma)));
-    drawState->stage(0)->setEffect(conv, sampleM);
+    drawState->stage(0)->setEffect(conv);
     target->drawSimpleRect(rect, NULL);
 }
 
diff --git a/src/gpu/effects/Gr1DKernelEffect.h b/src/gpu/effects/Gr1DKernelEffect.h
index 9ef7652..f176cdd 100644
--- a/src/gpu/effects/Gr1DKernelEffect.h
+++ b/src/gpu/effects/Gr1DKernelEffect.h
@@ -9,6 +9,8 @@
 #define Gr1DKernelEffect_DEFINED
 
 #include "GrSingleTextureEffect.h"
+#include "GrTexture.h"
+#include "SkMatrix.h"
 
 /**
  * Base class for 1D kernel effects. The kernel operates either in X or Y and
@@ -18,6 +20,16 @@
  * read. Since the center pixel is also read, the total width is one larger than
  * two times the radius.
  */
+
+namespace {
+inline SkMatrix make_texture_matrix(GrTexture* tex) {
+    GrAssert(NULL != tex);
+    SkMatrix mat;
+    mat.setIDiv(tex->width(), tex->height());
+    return mat;
+}
+}
+
 class Gr1DKernelEffect : public GrSingleTextureEffect {
 
 public:
@@ -29,7 +41,7 @@
     Gr1DKernelEffect(GrTexture* texture,
                      Direction direction,
                      int radius)
-        : GrSingleTextureEffect(texture)
+        : GrSingleTextureEffect(texture, make_texture_matrix(texture))
         , fDirection(direction)
         , fRadius(radius) {}
 
diff --git a/src/gpu/effects/GrConvolutionEffect.cpp b/src/gpu/effects/GrConvolutionEffect.cpp
index d0d9f5d..0ab215c 100644
--- a/src/gpu/effects/GrConvolutionEffect.cpp
+++ b/src/gpu/effects/GrConvolutionEffect.cpp
@@ -7,6 +7,7 @@
 
 #include "GrConvolutionEffect.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLEffectMatrix.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLTexture.h"
 #include "GrTBackendEffectFactory.h"
@@ -34,9 +35,10 @@
 private:
     int width() const { return Gr1DKernelEffect::WidthFromRadius(fRadius); }
 
-    int             fRadius;
-    UniformHandle   fKernelUni;
-    UniformHandle   fImageIncrementUni;
+    int                 fRadius;
+    UniformHandle       fKernelUni;
+    UniformHandle       fImageIncrementUni;
+    GrGLEffectMatrix    fEffectMatrix;
 
     typedef GrGLEffect INHERITED;
 };
@@ -49,15 +51,18 @@
     const GrConvolutionEffect& c =
         static_cast<const GrConvolutionEffect&>(effect);
     fRadius = c.radius();
+    fRequiresTextureMatrix = false;
 }
 
 void GrGLConvolutionEffect::emitCode(GrGLShaderBuilder* builder,
                                      const GrEffectStage&,
-                                     EffectKey,
+                                     EffectKey key,
                                      const char* vertexCoords,
                                      const char* outputColor,
                                      const char* inputColor,
                                      const TextureSamplerArray& samplers) {
+    const char* coords;
+    fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, vertexCoords, &coords);
     fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                              kVec2f_GrSLType, "ImageIncrement");
     fKernelUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_ShaderType,
@@ -70,8 +75,7 @@
     const GrGLShaderVar& kernel = builder->getUniformVariable(fKernelUni);
     const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
 
-    code->appendf("\t\tvec2 coord = %s - %d.0 * %s;\n",
-                  builder->defaultTexCoordsName(), fRadius, imgInc);
+    code->appendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords, fRadius, imgInc);
 
     // Manually unroll loop because some drivers don't; yields 20-30% speedup.
     for (int i = 0; i < width; i++) {
@@ -105,10 +109,17 @@
     }
     uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement);
     uman.set1fv(fKernelUni, 0, this->width(), conv.kernel());
+    fEffectMatrix.setData(uman, conv.getMatrix(), stage.getCoordChangeMatrix(), conv.texture(0));
 }
 
 GrGLEffect::EffectKey GrGLConvolutionEffect::GenKey(const GrEffectStage& s, const GrGLCaps&) {
-    return static_cast<const GrConvolutionEffect&>(*s.getEffect()).radius();
+    const GrConvolutionEffect& conv = static_cast<const GrConvolutionEffect&>(*s.getEffect());
+    EffectKey key = static_cast<const GrConvolutionEffect&>(*s.getEffect()).radius();
+    key <<= GrGLEffectMatrix::kKeyBits;
+    EffectKey matrixKey = GrGLEffectMatrix::GenKey(conv.getMatrix(),
+                                                   s.getCoordChangeMatrix(),
+                                                   conv.texture(0));
+    return key | matrixKey;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -119,11 +130,10 @@
                                          const float* kernel)
     : Gr1DKernelEffect(texture, direction, radius) {
     GrAssert(radius <= kMaxKernelRadius);
+    GrAssert(NULL != kernel);
     int width = this->width();
-    if (NULL != kernel) {
-        for (int i = 0; i < width; i++) {
-            fKernel[i] = kernel[i];
-        }
+    for (int i = 0; i < width; i++) {
+        fKernel[i] = kernel[i];
     }
 }
 
diff --git a/src/gpu/effects/GrConvolutionEffect.h b/src/gpu/effects/GrConvolutionEffect.h
index 5ff6d16..3638c0c 100644
--- a/src/gpu/effects/GrConvolutionEffect.h
+++ b/src/gpu/effects/GrConvolutionEffect.h
@@ -23,11 +23,12 @@
 
     /// Convolve with an arbitrary user-specified kernel
     GrConvolutionEffect(GrTexture*, Direction,
-                        int halfWidth, const float* kernel = NULL);
+                        int halfWidth, const float* kernel);
 
-    /// Convolve with a gaussian kernel
+    /// Convolve with a Gaussian kernel
     GrConvolutionEffect(GrTexture*, Direction,
-                        int halfWidth, float gaussianSigma);
+                        int halfWidth,
+                        float gaussianSigma);
     virtual ~GrConvolutionEffect();
 
     const float* kernel() const { return fKernel; }