Add a GrCustomCoordsTextureEffect class

Extracts a GrCustomCoordsTextureEffect class from
GrSimpleTextureEffect. This way there are no effects that can
conditionally require a vertex shader. They either always need one or
never do. Also removes kCustom_CoordsType from the CoordsType enum in
GrEffect (that enum is really only meant for coords provided by the
framework), and updates GrSimpleTextureEffect::TestCreate to make the
effect with position as well, instead of just local coords.

R=bsalomon@google.com

Author: cdalton@nvidia.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@11531 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index 83462f6..4536286 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -133,6 +133,8 @@
       '<(skia_src_path)/gpu/effects/GrConvolutionEffect.h',
       '<(skia_src_path)/gpu/effects/GrBicubicEffect.cpp',
       '<(skia_src_path)/gpu/effects/GrBicubicEffect.h',
+      '<(skia_src_path)/gpu/effects/GrCustomCoordsTextureEffect.cpp',
+      '<(skia_src_path)/gpu/effects/GrCustomCoordsTextureEffect.h',
       '<(skia_src_path)/gpu/effects/GrSimpleTextureEffect.cpp',
       '<(skia_src_path)/gpu/effects/GrSimpleTextureEffect.h',
       '<(skia_src_path)/gpu/effects/GrSingleTextureEffect.cpp',
diff --git a/include/gpu/GrEffect.h b/include/gpu/GrEffect.h
index 78ad28b..e7590b6 100644
--- a/include/gpu/GrEffect.h
+++ b/include/gpu/GrEffect.h
@@ -85,15 +85,11 @@
     /**
      * The types of vertex coordinates available to an effect in the vertex shader. Effects can
      * require their own vertex attribute but these coordinates are made available by the framework
-     * in all programs. kCustom_CoordsType is provided to signify that an alternative set of coords
-     * is used (usually an explicit vertex attribute) but its meaning is determined by the effect
-     * subclass.
+     * in all programs.
      */
     enum CoordsType {
         kLocal_CoordsType,
         kPosition_CoordsType,
-
-        kCustom_CoordsType,
     };
 
     virtual ~GrEffect();
diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp
index b050305..1f25c90 100644
--- a/src/gpu/GrTextContext.cpp
+++ b/src/gpu/GrTextContext.cpp
@@ -17,6 +17,7 @@
 #include "GrTextStrike_impl.h"
 #include "SkPath.h"
 #include "SkStrokeRec.h"
+#include "effects/GrCustomCoordsTextureEffect.h"
 
 static const int kGlyphCoordsAttributeIndex = 1;
 
@@ -37,7 +38,7 @@
 
         // This effect could be stored with one of the cache objects (atlas?)
         drawState->addCoverageEffect(
-                                GrSimpleTextureEffect::CreateWithCustomCoords(fCurrTexture, params),
+                                GrCustomCoordsTextureEffect::Create(fCurrTexture, params),
                                 kGlyphCoordsAttributeIndex)->unref();
 
         if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) {
diff --git a/src/gpu/effects/GrCustomCoordsTextureEffect.cpp b/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
new file mode 100644
index 0000000..a5c28c5
--- /dev/null
+++ b/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrCustomCoordsTextureEffect.h"
+#include "gl/GrGLEffect.h"
+#include "gl/GrGLEffectMatrix.h"
+#include "gl/GrGLSL.h"
+#include "gl/GrGLTexture.h"
+#include "GrTBackendEffectFactory.h"
+#include "GrTexture.h"
+
+class GrGLCustomCoordsTextureEffect : public GrGLEffect {
+public:
+    GrGLCustomCoordsTextureEffect(const GrBackendEffectFactory& factory, const GrDrawEffect& drawEffect)
+        : INHERITED (factory) {}
+
+    virtual void emitCode(GrGLShaderBuilder* builder,
+                          const GrDrawEffect& drawEffect,
+                          EffectKey key,
+                          const char* outputColor,
+                          const char* inputColor,
+                          const TextureSamplerArray& samplers) SK_OVERRIDE {
+        GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
+        SkASSERT(NULL != vertexBuilder);
+        SkASSERT(1 == drawEffect.castEffect<GrCustomCoordsTextureEffect>().numVertexAttribs());
+
+        SkString fsCoordName;
+        const char* vsVaryingName;
+        const char* fsVaryingNamePtr;
+        vertexBuilder->addVarying(kVec2f_GrSLType, "textureCoords", &vsVaryingName, &fsVaryingNamePtr);
+        fsCoordName = fsVaryingNamePtr;
+
+        const char* attrName =
+            vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0])->c_str();
+        vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsVaryingName, attrName);
+
+        builder->fsCodeAppendf("\t%s = ", outputColor);
+        builder->fsAppendTextureLookupAndModulate(inputColor,
+                                                  samplers[0],
+                                                  fsCoordName.c_str(),
+                                                  kVec2f_GrSLType);
+        builder->fsCodeAppend(";\n");
+    }
+
+    static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
+        return 1 << GrGLEffectMatrix::kKeyBits;
+    }
+
+    virtual void setData(const GrGLUniformManager& uman,
+                         const GrDrawEffect& drawEffect) SK_OVERRIDE {}
+
+private:
+    typedef GrGLEffect INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrCustomCoordsTextureEffect::GrCustomCoordsTextureEffect(GrTexture* texture,
+                                                         const GrTextureParams& params)
+    : fTextureAccess(texture, params) {
+    this->addTextureAccess(&fTextureAccess);
+    this->addVertexAttrib(kVec2f_GrSLType);
+}
+
+bool GrCustomCoordsTextureEffect::onIsEqual(const GrEffect& other) const {
+    const GrCustomCoordsTextureEffect& cte = CastEffect<GrCustomCoordsTextureEffect>(other);
+    return fTextureAccess == cte.fTextureAccess;
+}
+
+void GrCustomCoordsTextureEffect::getConstantColorComponents(GrColor* color,
+                                                             uint32_t* validFlags) const {
+    if ((*validFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(*color) &&
+        GrPixelConfigIsOpaque(this->texture(0)->config())) {
+        *validFlags = kA_GrColorComponentFlag;
+    } else {
+        *validFlags = 0;
+    }
+}
+
+const GrBackendEffectFactory& GrCustomCoordsTextureEffect::getFactory() const {
+    return GrTBackendEffectFactory<GrCustomCoordsTextureEffect>::getInstance();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GR_DEFINE_EFFECT_TEST(GrCustomCoordsTextureEffect);
+
+GrEffectRef* GrCustomCoordsTextureEffect::TestCreate(SkRandom* random,
+                                                     GrContext*,
+                                                     const GrDrawTargetCaps&,
+                                                     GrTexture* textures[]) {
+    int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
+                                      GrEffectUnitTest::kAlphaTextureIdx;
+    static const SkShader::TileMode kTileModes[] = {
+        SkShader::kClamp_TileMode,
+        SkShader::kRepeat_TileMode,
+        SkShader::kMirror_TileMode,
+    };
+    SkShader::TileMode tileModes[] = {
+        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
+        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
+    };
+    GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
+                                                           GrTextureParams::kNone_FilterMode);
+
+    return GrCustomCoordsTextureEffect::Create(textures[texIdx], params);
+}
diff --git a/src/gpu/effects/GrCustomCoordsTextureEffect.h b/src/gpu/effects/GrCustomCoordsTextureEffect.h
new file mode 100644
index 0000000..fad35c8
--- /dev/null
+++ b/src/gpu/effects/GrCustomCoordsTextureEffect.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrCustomCoordsTextureEffect_DEFINED
+#define GrCustomCoordsTextureEffect_DEFINED
+
+#include "GrEffect.h"
+
+class GrGLCustomCoordsTextureEffect;
+
+/**
+ * The output color of this effect is a modulation of the input color and a sample from a texture.
+ * It allows explicit specification of the filtering and wrap modes (GrTextureParams). The input
+ * coords are a custom attribute.
+ */
+class GrCustomCoordsTextureEffect : public GrEffect {
+public:
+    static GrEffectRef* Create(GrTexture* tex, const GrTextureParams& p) {
+        AutoEffectUnref effect(SkNEW_ARGS(GrCustomCoordsTextureEffect, (tex, p)));
+        return CreateEffectRef(effect);
+    }
+
+    virtual ~GrCustomCoordsTextureEffect() {}
+
+    static const char* Name() { return "Texture"; }
+
+    virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
+
+    typedef GrGLCustomCoordsTextureEffect GLEffect;
+
+    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
+
+private:
+    GrCustomCoordsTextureEffect(GrTexture* texture, const GrTextureParams& params);
+
+    virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
+
+    GrTextureAccess fTextureAccess;
+
+    GR_DECLARE_EFFECT_TEST;
+
+    typedef GrEffect INHERITED;
+};
+
+#endif
diff --git a/src/gpu/effects/GrSimpleTextureEffect.cpp b/src/gpu/effects/GrSimpleTextureEffect.cpp
index cf08d3b..0ee6f78 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.cpp
+++ b/src/gpu/effects/GrSimpleTextureEffect.cpp
@@ -16,12 +16,8 @@
 class GrGLSimpleTextureEffect : public GrGLEffect {
 public:
     GrGLSimpleTextureEffect(const GrBackendEffectFactory& factory, const GrDrawEffect& drawEffect)
-    : INHERITED (factory) {
-        GrEffect::CoordsType coordsType =
-            drawEffect.castEffect<GrSimpleTextureEffect>().coordsType();
-        if (GrEffect::kCustom_CoordsType != coordsType) {
-            SkNEW_IN_TLAZY(&fEffectMatrix, GrGLEffectMatrix, (coordsType));
-        }
+        : INHERITED (factory)
+        , fEffectMatrix(drawEffect.castEffect<GrSimpleTextureEffect>().coordsType()) {
     }
 
     virtual void emitCode(GrGLShaderBuilder* builder,
@@ -30,25 +26,10 @@
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
-        const GrSimpleTextureEffect& ste = drawEffect.castEffect<GrSimpleTextureEffect>();
         SkString fsCoordName;
         GrSLType fsCoordSLType;
-        if (GrEffect::kCustom_CoordsType == ste.coordsType()) {
-            SkASSERT(ste.getMatrix().isIdentity());
-            SkASSERT(1 == ste.numVertexAttribs());
-            fsCoordSLType = kVec2f_GrSLType;
-            const char* vsVaryingName;
-            const char* fsVaryingNamePtr;
-            GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
-            SkASSERT(NULL != vertexBuilder);
-            vertexBuilder->addVarying(kVec2f_GrSLType, "textureCoords", &vsVaryingName, &fsVaryingNamePtr);
-            fsCoordName = fsVaryingNamePtr;
-            const char* attrName =
-                vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0])->c_str();
-            vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsVaryingName, attrName);
-        } else {
-            fsCoordSLType = fEffectMatrix.get()->emitCode(builder, key, &fsCoordName);
-        }
+        fsCoordSLType = fEffectMatrix.emitCode(builder, key, &fsCoordName);
+
         builder->fsCodeAppendf("\t%s = ", outputColor);
         builder->fsAppendTextureLookupAndModulate(inputColor,
                                                   samplers[0],
@@ -59,28 +40,20 @@
 
     static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
         const GrSimpleTextureEffect& ste = drawEffect.castEffect<GrSimpleTextureEffect>();
-        if (GrEffect::kCustom_CoordsType == ste.coordsType()) {
-            return 1 << GrGLEffectMatrix::kKeyBits;
-        } else {
-            return GrGLEffectMatrix::GenKey(ste.getMatrix(),
-                                            drawEffect,
-                                            ste.coordsType(),
-                                            ste.texture(0));
-        }
+        return GrGLEffectMatrix::GenKey(ste.getMatrix(),
+                                        drawEffect,
+                                        ste.coordsType(),
+                                        ste.texture(0));
     }
 
     virtual void setData(const GrGLUniformManager& uman,
                          const GrDrawEffect& drawEffect) SK_OVERRIDE {
         const GrSimpleTextureEffect& ste = drawEffect.castEffect<GrSimpleTextureEffect>();
-        if (GrEffect::kCustom_CoordsType == ste.coordsType()) {
-            SkASSERT(ste.getMatrix().isIdentity());
-        } else {
-            fEffectMatrix.get()->setData(uman, ste.getMatrix(), drawEffect, ste.texture(0));
-        }
+        fEffectMatrix.setData(uman, ste.getMatrix(), drawEffect, ste.texture(0));
     }
 
 private:
-    SkTLazy<GrGLEffectMatrix> fEffectMatrix;
+    GrGLEffectMatrix fEffectMatrix;
     typedef GrGLEffect INHERITED;
 };
 
@@ -118,15 +91,10 @@
 
     static const CoordsType kCoordsTypes[] = {
         kLocal_CoordsType,
-        kPosition_CoordsType,
-        kCustom_CoordsType
+        kPosition_CoordsType
     };
     CoordsType coordsType = kCoordsTypes[random->nextULessThan(GR_ARRAY_COUNT(kCoordsTypes))];
 
-    if (kCustom_CoordsType == coordsType) {
-        return GrSimpleTextureEffect::CreateWithCustomCoords(textures[texIdx], params);
-    } else {
-        const SkMatrix& matrix = GrEffectUnitTest::TestMatrix(random);
-        return GrSimpleTextureEffect::Create(textures[texIdx], matrix);
-    }
+    const SkMatrix& matrix = GrEffectUnitTest::TestMatrix(random);
+    return GrSimpleTextureEffect::Create(textures[texIdx], matrix, coordsType);
 }
diff --git a/src/gpu/effects/GrSimpleTextureEffect.h b/src/gpu/effects/GrSimpleTextureEffect.h
index bcce46b..c694197 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.h
+++ b/src/gpu/effects/GrSimpleTextureEffect.h
@@ -26,7 +26,6 @@
     static GrEffectRef* Create(GrTexture* tex,
                                const SkMatrix& matrix,
                                CoordsType coordsType = kLocal_CoordsType) {
-        SkASSERT(kLocal_CoordsType == coordsType || kPosition_CoordsType == coordsType);
         AutoEffectUnref effect(SkNEW_ARGS(GrSimpleTextureEffect, (tex, matrix, GrTextureParams::kNone_FilterMode, coordsType)));
         return CreateEffectRef(effect);
     }
@@ -36,7 +35,6 @@
                                const SkMatrix& matrix,
                                GrTextureParams::FilterMode filterMode,
                                CoordsType coordsType = kLocal_CoordsType) {
-        SkASSERT(kLocal_CoordsType == coordsType || kPosition_CoordsType == coordsType);
         AutoEffectUnref effect(
             SkNEW_ARGS(GrSimpleTextureEffect, (tex, matrix, filterMode, coordsType)));
         return CreateEffectRef(effect);
@@ -46,21 +44,10 @@
                                const SkMatrix& matrix,
                                const GrTextureParams& p,
                                CoordsType coordsType = kLocal_CoordsType) {
-        SkASSERT(kLocal_CoordsType == coordsType || kPosition_CoordsType == coordsType);
         AutoEffectUnref effect(SkNEW_ARGS(GrSimpleTextureEffect, (tex, matrix, p, coordsType)));
         return CreateEffectRef(effect);
     }
 
-    /** Variant that requires the client to install a custom kVec2 vertex attribute that will be
-        the source of the coords. No matrix is allowed in this mode. */
-    static GrEffectRef* CreateWithCustomCoords(GrTexture* tex, const GrTextureParams& p) {
-        AutoEffectUnref effect(SkNEW_ARGS(GrSimpleTextureEffect, (tex,
-                                                                  SkMatrix::I(),
-                                                                  p,
-                                                                  kCustom_CoordsType)));
-        return CreateEffectRef(effect);
-    }
-
     virtual ~GrSimpleTextureEffect() {}
 
     static const char* Name() { return "Texture"; }
@@ -77,7 +64,6 @@
                           GrTextureParams::FilterMode filterMode,
                           CoordsType coordsType)
         : GrSingleTextureEffect(texture, matrix, filterMode, coordsType) {
-        SkASSERT(kLocal_CoordsType == coordsType || kPosition_CoordsType == coordsType);
     }
 
     GrSimpleTextureEffect(GrTexture* texture,
@@ -85,10 +71,6 @@
                           const GrTextureParams& params,
                           CoordsType coordsType)
         : GrSingleTextureEffect(texture, matrix, params, coordsType) {
-        if (kCustom_CoordsType == coordsType) {
-            SkASSERT(matrix.isIdentity());
-            this->addVertexAttrib(kVec2f_GrSLType);
-        }
     }
 
     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
diff --git a/src/gpu/effects/GrSingleTextureEffect.h b/src/gpu/effects/GrSingleTextureEffect.h
index 1331ae4..27a7d79 100644
--- a/src/gpu/effects/GrSingleTextureEffect.h
+++ b/src/gpu/effects/GrSingleTextureEffect.h
@@ -41,10 +41,8 @@
      * Helper for subclass onIsEqual() functions.
      */
     bool hasSameTextureParamsMatrixAndCoordsType(const GrSingleTextureEffect& other) const {
-        const GrTextureAccess& otherAccess = other.fTextureAccess;
         // We don't have to check the accesses' swizzles because they are inferred from the texture.
-        return fTextureAccess.getTexture() == otherAccess.getTexture() &&
-               fTextureAccess.getParams() == otherAccess.getParams() &&
+        return fTextureAccess == other.fTextureAccess &&
                this->getMatrix().cheapEqualTo(other.getMatrix()) &&
                fCoordsType == other.fCoordsType;
     }
diff --git a/src/gpu/gl/GrGLEffectMatrix.h b/src/gpu/gl/GrGLEffectMatrix.h
index 56dda45..c5ac5f0 100644
--- a/src/gpu/gl/GrGLEffectMatrix.h
+++ b/src/gpu/gl/GrGLEffectMatrix.h
@@ -60,8 +60,6 @@
 
     GrGLEffectMatrix(CoordsType coordsType)
         : fCoordsType(coordsType) {
-        SkASSERT(GrEffect::kLocal_CoordsType == coordsType ||
-                 GrEffect::kPosition_CoordsType == coordsType);
         fPrevMatrix = SkMatrix::InvalidMatrix();
     }