This CL wires up the backend portion necessary for sending transformed coords via vertex attributes.

BUG=skia:

Review URL: https://codereview.chromium.org/1243583002
diff --git a/src/gpu/GrDefaultGeoProcFactory.cpp b/src/gpu/GrDefaultGeoProcFactory.cpp
index 639a593..f8d30f8 100644
--- a/src/gpu/GrDefaultGeoProcFactory.cpp
+++ b/src/gpu/GrDefaultGeoProcFactory.cpp
@@ -16,6 +16,14 @@
  * matrix. It also leaves coverage untouched.  Behind the scenes, we may add per vertex color or
  * local coords.
  */
+
+enum GPFlag {
+    kColor_GPFlag =                 0x1,
+    kLocalCoord_GPFlag =            0x2,
+    kCoverage_GPFlag=               0x4,
+    kTransformedLocalCoord_GPFlag = 0x8,
+};
+
 class DefaultGeoProc : public GrGeometryProcessor {
 public:
     static GrGeometryProcessor* Create(uint32_t gpTypeFlags,
@@ -77,10 +85,14 @@
             this->setupPosition(pb, gpArgs, gp.inPosition()->fName, gp.viewMatrix(),
                                 &fViewMatrixUniform);
 
-            if (gp.inLocalCoords()) {
+            if (gp.hasExplicitLocalCoords()) {
                 // emit transforms with explicit local coords
                 this->emitTransforms(pb, gpArgs->fPositionVar, gp.inLocalCoords()->fName,
                                      gp.localMatrix(), args.fTransformsIn, args.fTransformsOut);
+            } else if(gp.hasTransformedLocalCoords()) {
+                // transforms have already been applied to vertex attributes on the cpu
+                this->emitTransforms(pb, gp.inLocalCoords()->fName,
+                                     args.fTransformsIn, args.fTransformsOut);
             } else {
                 // emit transforms with position
                 this->emitTransforms(pb, gpArgs->fPositionVar, gp.inPosition()->fName,
@@ -199,9 +211,11 @@
         , fLocalCoordsWillBeRead(localCoordsWillBeRead)
         , fCoverageWillBeIgnored(coverageWillBeIgnored) {
         this->initClassID<DefaultGeoProc>();
-        bool hasColor = SkToBool(gpTypeFlags & GrDefaultGeoProcFactory::kColor_GPType);
-        bool hasLocalCoord = SkToBool(gpTypeFlags & GrDefaultGeoProcFactory::kLocalCoord_GPType);
-        bool hasCoverage = SkToBool(gpTypeFlags & GrDefaultGeoProcFactory::kCoverage_GPType);
+        bool hasColor = SkToBool(gpTypeFlags & kColor_GPFlag);
+        bool hasExplicitLocalCoords = SkToBool(gpTypeFlags & kLocalCoord_GPFlag);
+        bool hasTransformedLocalCoords = SkToBool(gpTypeFlags & kTransformedLocalCoord_GPFlag);
+        bool hasLocalCoord = hasExplicitLocalCoords || hasTransformedLocalCoords;
+        bool hasCoverage = SkToBool(gpTypeFlags & kCoverage_GPFlag);
         fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
                                                        kHigh_GrSLPrecision));
         if (hasColor) {
@@ -210,7 +224,12 @@
         if (hasLocalCoord) {
             fInLocalCoords = &this->addVertexAttrib(Attribute("inLocalCoord",
                                                               kVec2f_GrVertexAttribType));
-            this->setHasLocalCoords();
+            if (hasExplicitLocalCoords) {
+                this->setHasExplicitLocalCoords();
+            } else {
+                SkASSERT(hasTransformedLocalCoords);
+                this->setHasTransformedLocalCoords();
+            }
         }
         if (hasCoverage) {
             fInCoverage = &this->addVertexAttrib(Attribute("inCoverage",
@@ -240,13 +259,16 @@
 GrGeometryProcessor* DefaultGeoProc::TestCreate(GrProcessorTestData* d) {
     uint32_t flags = 0;
     if (d->fRandom->nextBool()) {
-        flags |= GrDefaultGeoProcFactory::kColor_GPType;
+        flags |= kColor_GPFlag;
     }
     if (d->fRandom->nextBool()) {
-        flags |= GrDefaultGeoProcFactory::kCoverage_GPType;
+        flags |= kCoverage_GPFlag;
     }
     if (d->fRandom->nextBool()) {
-        flags |= GrDefaultGeoProcFactory::kLocalCoord_GPType;
+        flags |= kLocalCoord_GPFlag;
+    }
+    if (d->fRandom->nextBool()) {
+        flags |= kTransformedLocalCoord_GPFlag;
     }
 
     return DefaultGeoProc::Create(flags,
@@ -263,9 +285,11 @@
                                                            const LocalCoords& localCoords,
                                                            const SkMatrix& viewMatrix) {
     uint32_t flags = 0;
-    flags |= color.fType == Color::kAttribute_Type ? kColor_GPType : 0;
-    flags |= coverage.fType == Coverage::kAttribute_Type ? kCoverage_GPType : 0;
-    flags |= localCoords.fType == LocalCoords::kHasExplicit_Type ? kLocalCoord_GPType : 0;
+    flags |= color.fType == Color::kAttribute_Type ? kColor_GPFlag : 0;
+    flags |= coverage.fType == Coverage::kAttribute_Type ? kCoverage_GPFlag : 0;
+    flags |= localCoords.fType == LocalCoords::kHasExplicit_Type ? kLocalCoord_GPFlag : 0;
+    flags |= localCoords.fType == LocalCoords::kHasTransformed_Type ?
+                                  kTransformedLocalCoord_GPFlag : 0;
 
     uint8_t inCoverage = coverage.fCoverage;
     bool coverageWillBeIgnored = coverage.fType == Coverage::kNone_Type;
diff --git a/src/gpu/GrDefaultGeoProcFactory.h b/src/gpu/GrDefaultGeoProcFactory.h
index cd886a2..2d80558 100644
--- a/src/gpu/GrDefaultGeoProcFactory.h
+++ b/src/gpu/GrDefaultGeoProcFactory.h
@@ -64,14 +64,6 @@
         GrColor fCoverage;
     };
 
-    enum GPType {
-        kPosition_GPType = 0x0, // we ALWAYS have position
-        kColor_GPType = 0x01,
-        kLocalCoord_GPType = 0x02,
-        kCoverage_GPType= 0x04,
-        kLastGPType = kCoverage_GPType
-    };
-
     struct Color {
         enum Type {
             kNone_Type,
@@ -113,6 +105,7 @@
             kUnused_Type,
             kUsePosition_Type,
             kHasExplicit_Type,
+            kHasTransformed_Type,
         };
         LocalCoords(Type type) : fType(type), fMatrix(NULL) {}
         LocalCoords(Type type, const SkMatrix* matrix) : fType(type), fMatrix(matrix) {
diff --git a/src/gpu/GrGeometryProcessor.h b/src/gpu/GrGeometryProcessor.h
index ea4e890..96c1cb6 100644
--- a/src/gpu/GrGeometryProcessor.h
+++ b/src/gpu/GrGeometryProcessor.h
@@ -22,7 +22,7 @@
     GrGeometryProcessor()
         : INHERITED(false)
         , fWillUseGeoShader(false)
-        , fHasLocalCoords(false) {}
+        , fLocalCoordsType(kUnused_LocalCoordsType) {}
 
     bool willUseGeoShader() const override { return fWillUseGeoShader; }
 
@@ -45,6 +45,14 @@
         SkFAIL("Unsupported\n");
     }
 
+    bool hasTransformedLocalCoords() const override {
+        return kHasTransformed_LocalCoordsType == fLocalCoordsType;
+    }
+
+    bool hasExplicitLocalCoords() const override {
+        return kHasExplicit_LocalCoordsType == fLocalCoordsType;
+    }
+
 protected:
     /**
      * Subclasses call this from their constructor to register vertex attributes.  Attributes
@@ -64,14 +72,32 @@
 
     void setWillUseGeoShader() { fWillUseGeoShader = true; }
 
-    // TODO hack see above
-    void setHasLocalCoords() { fHasLocalCoords = true; }
+    /**
+     * If a GrFragmentProcessor in the GrPipeline needs localCoods, we will provide them in one of
+     * three ways
+     * 1) LocalCoordTransform * Position - in Shader
+     * 2) LocalCoordTransform * ExplicitLocalCoords- in Shader
+     * 3) A transformation on the CPU uploaded via vertex attribute
+     * TODO make this GrBatches responsibility
+     */
+    enum LocalCoordsType {
+        kUnused_LocalCoordsType,
+        kHasExplicit_LocalCoordsType,
+        kHasTransformed_LocalCoordsType
+    };
+
+    void setHasExplicitLocalCoords() {
+        SkASSERT(kUnused_LocalCoordsType == fLocalCoordsType);
+        fLocalCoordsType = kHasExplicit_LocalCoordsType;
+    }
+    void setHasTransformedLocalCoords() {
+        SkASSERT(kUnused_LocalCoordsType == fLocalCoordsType);
+        fLocalCoordsType = kHasTransformed_LocalCoordsType;
+    }
 
 private:
-    bool hasExplicitLocalCoords() const override { return fHasLocalCoords; }
-
     bool fWillUseGeoShader;
-    bool fHasLocalCoords;
+    LocalCoordsType fLocalCoordsType;
 
     typedef GrPrimitiveProcessor INHERITED;
 };
diff --git a/src/gpu/GrPathProcessor.h b/src/gpu/GrPathProcessor.h
index 7c1ab2b..1959795 100644
--- a/src/gpu/GrPathProcessor.h
+++ b/src/gpu/GrPathProcessor.h
@@ -54,6 +54,8 @@
     virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
                                                      const GrGLSLCaps& caps) const override;
 
+    bool hasTransformedLocalCoords() const override { return false; }
+
 private:
     GrPathProcessor(GrColor color, const SkMatrix& viewMatrix, const SkMatrix& localMatrix);
 
diff --git a/src/gpu/GrPrimitiveProcessor.h b/src/gpu/GrPrimitiveProcessor.h
index e5635a8..54d7d8d 100644
--- a/src/gpu/GrPrimitiveProcessor.h
+++ b/src/gpu/GrPrimitiveProcessor.h
@@ -220,6 +220,12 @@
 
     bool isPathRendering() const { return fIsPathRendering; }
 
+    /**
+     * No Local Coord Transformation is needed in the shader, instead transformed local coords will
+     * be provided via vertex attribute.
+     */
+    virtual bool hasTransformedLocalCoords() const = 0;
+
 protected:
     GrPrimitiveProcessor(bool isPathRendering)
         : fNumAttribs(0)
diff --git a/src/gpu/gl/GrGLGeometryProcessor.cpp b/src/gpu/gl/GrGLGeometryProcessor.cpp
index dc4518f..4026c72 100644
--- a/src/gpu/gl/GrGLGeometryProcessor.cpp
+++ b/src/gpu/gl/GrGLGeometryProcessor.cpp
@@ -89,6 +89,35 @@
     }
 }
 
+void GrGLGeometryProcessor::emitTransforms(GrGLGPBuilder* pb,
+                                           const char* localCoords,
+                                           const TransformsIn& tin,
+                                           TransformsOut* tout) {
+    GrGLVertexBuilder* vb = pb->getVertexShaderBuilder();
+    tout->push_back_n(tin.count());
+    for (int i = 0; i < tin.count(); i++) {
+        const ProcCoords& coordTransforms = tin[i];
+        for (int t = 0; t < coordTransforms.count(); t++) {
+            GrSLType varyingType = kVec2f_GrSLType;
+
+            // Device coords aren't supported
+            SkASSERT(kDevice_GrCoordSet != coordTransforms[t]->sourceCoords());
+            GrSLPrecision precision = coordTransforms[t]->precision();
+
+            SkString strVaryingName("MatrixCoord");
+            strVaryingName.appendf("_%i_%i", i, t);
+
+            GrGLVertToFrag v(varyingType);
+            pb->addVarying(strVaryingName.c_str(), &v, precision);
+            vb->codeAppendf("%s = %s;", v.vsOut(), localCoords);
+
+            SkNEW_APPEND_TO_TARRAY(&(*tout)[i],
+                                   GrGLProcessor::TransformedCoords,
+                                   (SkString(v.fsIn()), varyingType));
+        }
+    }
+}
+
 void GrGLGeometryProcessor::setupPosition(GrGLGPBuilder* pb,
                                           GrGPArgs* gpArgs,
                                           const char* posName) {
diff --git a/src/gpu/gl/GrGLGeometryProcessor.h b/src/gpu/gl/GrGLGeometryProcessor.h
index 747d82a..88baecf 100644
--- a/src/gpu/gl/GrGLGeometryProcessor.h
+++ b/src/gpu/gl/GrGLGeometryProcessor.h
@@ -41,7 +41,7 @@
     }
 
 protected:
-    // A helper for subclasses which don't have an explicit local matrix
+    // Emit a uniform matrix for each coord transform.
     void emitTransforms(GrGLGPBuilder* gp,
                         const GrShaderVar& posVar,
                         const char* localCoords,
@@ -50,6 +50,7 @@
         this->emitTransforms(gp, posVar, localCoords, SkMatrix::I(), tin, tout);
     }
 
+    // Emit pre-transformed coords as a vertex attribute per coord-transform.
     void emitTransforms(GrGLGPBuilder*,
                         const GrShaderVar& posVar,
                         const char* localCoords,
@@ -57,6 +58,12 @@
                         const TransformsIn&,
                         TransformsOut*);
 
+    // caller has emitted transforms via attributes
+    void emitTransforms(GrGLGPBuilder*,
+                        const char* localCoords,
+                        const TransformsIn& tin,
+                        TransformsOut* tout);
+
     struct GrGPArgs {
         // The variable used by a GP to store its position. It can be
         // either a vec2 or a vec3 depending on the presence of perspective.
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index daa2480..c7528f0 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -197,12 +197,15 @@
     const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
     int totalTextures = primProc.numTextures();
     const int maxTextureUnits = fGpu->glCaps().maxFragmentTextureUnits();
-    SkSTArray<8, GrGLProcessor::TransformedCoordsArray> outCoords;
+
     for (int i = 0; i < this->pipeline().numFragmentStages(); i++) {
         const GrFragmentProcessor* processor = this->pipeline().getFragmentStage(i).processor();
-        SkSTArray<2, const GrCoordTransform*, true>& procCoords = fCoordTransforms.push_back();
 
-        append_gr_fp_coord_transforms(processor, &procCoords);
+        if (!primProc.hasTransformedLocalCoords()) {
+            SkSTArray<2, const GrCoordTransform*, true>& procCoords = fCoordTransforms.push_back();
+
+            append_gr_fp_coord_transforms(processor, &procCoords);
+        }
 
         totalTextures += processor->numTexturesIncludeChildProcs();
         if (totalTextures >= maxTextureUnits) {