A simple change to move a bunch of stuff out of Gr*Geometry.h

BUG=skia:

Review URL: https://codereview.chromium.org/920863002
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index 1b66517..65407e6 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -11,6 +11,8 @@
 #include "GrClipData.h"
 #include "GrClipMaskManager.h"
 #include "GrContext.h"
+#include "GrPathProcessor.h"
+#include "GrPrimitiveProcessor.h"
 #include "GrIndexBuffer.h"
 #include "GrPathRendering.h"
 #include "GrPipelineBuilder.h"
diff --git a/src/gpu/GrGeometryProcessor.cpp b/src/gpu/GrGeometryProcessor.cpp
index c707efc..23989cf 100644
--- a/src/gpu/GrGeometryProcessor.cpp
+++ b/src/gpu/GrGeometryProcessor.cpp
@@ -7,70 +7,7 @@
 
 #include "GrGeometryProcessor.h"
 
-#include "GrCoordTransform.h"
 #include "GrInvariantOutput.h"
-#include "gl/GrGLGeometryProcessor.h"
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-/**
- * The key for an individual coord transform is made up of a matrix type, a precision, and a bit
- * that indicates the source of the input coords.
- */
-enum {
-    kMatrixTypeKeyBits   = 1,
-    kMatrixTypeKeyMask   = (1 << kMatrixTypeKeyBits) - 1,
-
-    kPrecisionBits       = 2,
-    kPrecisionShift      = kMatrixTypeKeyBits,
-
-    kPositionCoords_Flag = (1 << (kPrecisionShift + kPrecisionBits)),
-    kDeviceCoords_Flag   = kPositionCoords_Flag + kPositionCoords_Flag,
-
-    kTransformKeyBits    = kMatrixTypeKeyBits + kPrecisionBits + 2,
-};
-
-GR_STATIC_ASSERT(kHigh_GrSLPrecision < (1 << kPrecisionBits));
-
-/**
- * We specialize the vertex code for each of these matrix types.
- */
-enum MatrixType {
-    kNoPersp_MatrixType  = 0,
-    kGeneral_MatrixType  = 1,
-};
-
-uint32_t
-GrPrimitiveProcessor::getTransformKey(const SkTArray<const GrCoordTransform*, true>& coords) const {
-    uint32_t totalKey = 0;
-    for (int t = 0; t < coords.count(); ++t) {
-        uint32_t key = 0;
-        const GrCoordTransform* coordTransform = coords[t];
-        if (coordTransform->getMatrix().hasPerspective()) {
-            key |= kGeneral_MatrixType;
-        } else {
-            key |= kNoPersp_MatrixType;
-        }
-
-        if (kLocal_GrCoordSet == coordTransform->sourceCoords() &&
-            !this->hasExplicitLocalCoords()) {
-            key |= kPositionCoords_Flag;
-        } else if (kDevice_GrCoordSet == coordTransform->sourceCoords()) {
-            key |= kDeviceCoords_Flag;
-        }
-
-        GR_STATIC_ASSERT(kGrSLPrecisionCount <= (1 << kPrecisionBits));
-        key |= (coordTransform->precision() << kPrecisionShift);
-
-        key <<= kTransformKeyBits * t;
-
-        SkASSERT(0 == (totalKey & key)); // keys for each transform ought not to overlap
-        totalKey |= key;
-    }
-    return totalKey;
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
 
 void GrGeometryProcessor::getInvariantOutputColor(GrInitInvariantOutput* out) const {
     if (fHasVertexColor) {
@@ -89,483 +26,4 @@
     this->onGetInvariantOutputCoverage(out);
 }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-#include "gl/builders/GrGLProgramBuilder.h"
-
-SkMatrix GrGLPrimitiveProcessor::GetTransformMatrix(const SkMatrix& localMatrix,
-                                                    const GrCoordTransform& coordTransform) {
-    SkMatrix combined;
-    // We only apply the localmatrix to localcoords
-    if (kLocal_GrCoordSet == coordTransform.sourceCoords()) {
-        combined.setConcat(coordTransform.getMatrix(), localMatrix);
-    } else {
-        combined = coordTransform.getMatrix();
-    }
-    if (coordTransform.reverseY()) {
-        // combined.postScale(1,-1);
-        // combined.postTranslate(0,1);
-        combined.set(SkMatrix::kMSkewY,
-            combined[SkMatrix::kMPersp0] - combined[SkMatrix::kMSkewY]);
-        combined.set(SkMatrix::kMScaleY,
-            combined[SkMatrix::kMPersp1] - combined[SkMatrix::kMScaleY]);
-        combined.set(SkMatrix::kMTransY,
-            combined[SkMatrix::kMPersp2] - combined[SkMatrix::kMTransY]);
-    }
-    return combined;
-}
-
-void
-GrGLPrimitiveProcessor::setupColorPassThrough(GrGLGPBuilder* pb,
-                                              GrGPInput inputType,
-                                              const char* outputName,
-                                              const GrGeometryProcessor::Attribute* colorAttr,
-                                              UniformHandle* colorUniform) {
-    GrGLGPFragmentBuilder* fs = pb->getFragmentShaderBuilder();
-    if (kUniform_GrGPInput == inputType) {
-        SkASSERT(colorUniform);
-        const char* stagedLocalVarName;
-        *colorUniform = pb->addUniform(GrGLProgramBuilder::kFragment_Visibility,
-                                       kVec4f_GrSLType,
-                                       kDefault_GrSLPrecision,
-                                       "Color",
-                                       &stagedLocalVarName);
-        fs->codeAppendf("%s = %s;", outputName, stagedLocalVarName);
-    } else if (kAttribute_GrGPInput == inputType) {
-        SkASSERT(colorAttr);
-        pb->addPassThroughAttribute(colorAttr, outputName);
-    } else if (kAllOnes_GrGPInput == inputType) {
-        fs->codeAppendf("%s = vec4(1);", outputName);
-    }
-}
-
-void GrGLPrimitiveProcessor::addUniformViewMatrix(GrGLGPBuilder* pb) {
-    fViewMatrixUniform = pb->addUniform(GrGLProgramBuilder::kVertex_Visibility,
-                                        kMat33f_GrSLType, kDefault_GrSLPrecision,
-                                        "uViewM",
-                                        &fViewMatrixName);
-}
-
-void GrGLPrimitiveProcessor::setUniformViewMatrix(const GrGLProgramDataManager& pdman,
-                                                  const SkMatrix& viewMatrix) {
-    if (!fViewMatrix.cheapEqualTo(viewMatrix)) {
-        SkASSERT(fViewMatrixUniform.isValid());
-        fViewMatrix = viewMatrix;
-
-        GrGLfloat viewMatrix[3 * 3];
-        GrGLGetMatrix<3>(viewMatrix, fViewMatrix);
-        pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-
-void GrGLGeometryProcessor::emitCode(EmitArgs& args) {
-    GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
-    GrGPArgs gpArgs;
-    this->onEmitCode(args, &gpArgs);
-    vsBuilder->transformToNormalizedDeviceSpace(gpArgs.fPositionVar);
-}
-
-void GrGLGeometryProcessor::emitTransforms(GrGLGPBuilder* pb,
-                                           const GrShaderVar& posVar,
-                                           const char* localCoords,
-                                           const SkMatrix& localMatrix,
-                                           const TransformsIn& tin,
-                                           TransformsOut* tout) {
-    GrGLVertexBuilder* vb = pb->getVertexShaderBuilder();
-    tout->push_back_n(tin.count());
-    fInstalledTransforms.push_back_n(tin.count());
-    for (int i = 0; i < tin.count(); i++) {
-        const ProcCoords& coordTransforms = tin[i];
-        fInstalledTransforms[i].push_back_n(coordTransforms.count());
-        for (int t = 0; t < coordTransforms.count(); t++) {
-            SkString strUniName("StageMatrix");
-            strUniName.appendf("_%i_%i", i, t);
-            GrSLType varyingType;
-
-            GrCoordSet coordType = coordTransforms[t]->sourceCoords();
-            uint32_t type = coordTransforms[t]->getMatrix().getType();
-            if (kLocal_GrCoordSet == coordType) {
-                type |= localMatrix.getType();
-            }
-            varyingType = SkToBool(SkMatrix::kPerspective_Mask & type) ? kVec3f_GrSLType :
-                                                                         kVec2f_GrSLType;
-            GrSLPrecision precision = coordTransforms[t]->precision();
-
-            const char* uniName;
-            fInstalledTransforms[i][t].fHandle =
-                    pb->addUniform(GrGLProgramBuilder::kVertex_Visibility,
-                                   kMat33f_GrSLType, precision,
-                                   strUniName.c_str(),
-                                   &uniName).toShaderBuilderIndex();
-
-            SkString strVaryingName("MatrixCoord");
-            strVaryingName.appendf("_%i_%i", i, t);
-
-            GrGLVertToFrag v(varyingType);
-            pb->addVarying(strVaryingName.c_str(), &v, precision);
-
-            SkASSERT(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType);
-            SkNEW_APPEND_TO_TARRAY(&(*tout)[i], GrGLProcessor::TransformedCoords,
-                                   (SkString(v.fsIn()), varyingType));
-
-            // varying = matrix * coords (logically)
-            if (kDevice_GrCoordSet == coordType) {
-                if (kVec2f_GrSLType == varyingType) {
-                    if (kVec2f_GrSLType == posVar.getType()) {
-                        vb->codeAppendf("%s = (%s * vec3(%s, 1)).xy;",
-                                        v.vsOut(), uniName, posVar.c_str());
-                    } else {
-                        // The brackets here are just to scope the temp variable
-                        vb->codeAppendf("{ vec3 temp = %s * %s;", uniName, posVar.c_str());
-                        vb->codeAppendf("%s = vec2(temp.x/temp.z, temp.y/temp.z); }", v.vsOut());
-                    }
-                } else {
-                    if (kVec2f_GrSLType == posVar.getType()) {
-                        vb->codeAppendf("%s = %s * vec3(%s, 1);",
-                                        v.vsOut(), uniName, posVar.c_str());
-                    } else {
-                        vb->codeAppendf("%s = %s * %s;", v.vsOut(), uniName, posVar.c_str());
-                    }
-                }
-            } else {
-                if (kVec2f_GrSLType == varyingType) {
-                    vb->codeAppendf("%s = (%s * vec3(%s, 1)).xy;", v.vsOut(), uniName, localCoords);
-                } else {
-                    vb->codeAppendf("%s = %s * vec3(%s, 1);", v.vsOut(), uniName, localCoords);
-                }
-            }
-        }
-    }
-}
-
-
-void
-GrGLGeometryProcessor::setTransformData(const GrPrimitiveProcessor& primProc,
-                                        const GrGLProgramDataManager& pdman,
-                                        int index,
-                                        const SkTArray<const GrCoordTransform*, true>& transforms) {
-    SkSTArray<2, Transform, true>& procTransforms = fInstalledTransforms[index];
-    int numTransforms = transforms.count();
-    for (int t = 0; t < numTransforms; ++t) {
-        SkASSERT(procTransforms[t].fHandle.isValid());
-        const SkMatrix& transform = GetTransformMatrix(primProc.localMatrix(), *transforms[t]);
-        if (!procTransforms[t].fCurrentValue.cheapEqualTo(transform)) {
-            pdman.setSkMatrix(procTransforms[t].fHandle.convertToUniformHandle(), transform);
-            procTransforms[t].fCurrentValue = transform;
-        }
-    }
-}
-
-void GrGLGeometryProcessor::SetupPosition(GrGLVertexBuilder* vsBuilder,
-                                          GrGPArgs* gpArgs,
-                                          const char* posName,
-                                          const SkMatrix& mat,
-                                          const char* matName) {
-    if (mat.isIdentity()) {
-        gpArgs->fPositionVar.set(kVec2f_GrSLType, "pos2");
-
-        vsBuilder->codeAppendf("vec2 %s = %s;", gpArgs->fPositionVar.c_str(), posName);
-    } else if (!mat.hasPerspective()) {
-        gpArgs->fPositionVar.set(kVec2f_GrSLType, "pos2");
-
-        vsBuilder->codeAppendf("vec2 %s = vec2(%s * vec3(%s, 1));",
-                               gpArgs->fPositionVar.c_str(), matName, posName);
-    } else {
-        gpArgs->fPositionVar.set(kVec3f_GrSLType, "pos3");
-
-        vsBuilder->codeAppendf("vec3 %s = %s * vec3(%s, 1);",
-                               gpArgs->fPositionVar.c_str(), matName, posName);
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-#include "gl/GrGLGpu.h"
-#include "gl/GrGLPathRendering.h"
-
-struct PathBatchTracker {
-    GrGPInput fInputColorType;
-    GrGPInput fInputCoverageType;
-    GrColor fColor;
-    bool fUsesLocalCoords;
-};
-
-GrGLPathProcessor::GrGLPathProcessor(const GrPathProcessor&, const GrBatchTracker&)
-    : fColor(GrColor_ILLEGAL) {}
-
-void GrGLPathProcessor::emitCode(EmitArgs& args) {
-    GrGLGPBuilder* pb = args.fPB;
-    GrGLGPFragmentBuilder* fs = args.fPB->getFragmentShaderBuilder();
-    const PathBatchTracker& local = args.fBT.cast<PathBatchTracker>();
-
-    // emit transforms
-    this->emitTransforms(args.fPB, args.fTransformsIn, args.fTransformsOut);
-
-    // Setup uniform color
-    if (kUniform_GrGPInput == local.fInputColorType) {
-        const char* stagedLocalVarName;
-        fColorUniform = pb->addUniform(GrGLProgramBuilder::kFragment_Visibility,
-                                       kVec4f_GrSLType,
-                                       kDefault_GrSLPrecision,
-                                       "Color",
-                                       &stagedLocalVarName);
-        fs->codeAppendf("%s = %s;", args.fOutputColor, stagedLocalVarName);
-    }
-
-    // setup constant solid coverage
-    if (kAllOnes_GrGPInput == local.fInputCoverageType) {
-        fs->codeAppendf("%s = vec4(1);", args.fOutputCoverage);
-    }
-}
-
-void GrGLPathProcessor::GenKey(const GrPathProcessor&,
-                               const GrBatchTracker& bt,
-                               const GrGLCaps&,
-                               GrProcessorKeyBuilder* b) {
-    const PathBatchTracker& local = bt.cast<PathBatchTracker>();
-    b->add32(local.fInputColorType | local.fInputCoverageType << 16);
-}
-
-void GrGLPathProcessor::setData(const GrGLProgramDataManager& pdman,
-                                const GrPrimitiveProcessor& primProc,
-                                const GrBatchTracker& bt) {
-    const PathBatchTracker& local = bt.cast<PathBatchTracker>();
-    if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
-        GrGLfloat c[4];
-        GrColorToRGBAFloat(local.fColor, c);
-        pdman.set4fv(fColorUniform, 1, c);
-        fColor = local.fColor;
-    }
-}
-
-class GrGLLegacyPathProcessor : public GrGLPathProcessor {
-public:
-    GrGLLegacyPathProcessor(const GrPathProcessor& pathProc, const GrBatchTracker& bt,
-                            int maxTexCoords)
-        : INHERITED(pathProc, bt)
-        , fTexCoordSetCnt(0) {
-            SkDEBUGCODE(fMaxTexCoords = maxTexCoords;)
-    }
-
-    int addTexCoordSets(int count) {
-        int firstFreeCoordSet = fTexCoordSetCnt;
-        fTexCoordSetCnt += count;
-        SkASSERT(fMaxTexCoords >= fTexCoordSetCnt);
-        return firstFreeCoordSet;
-    }
-
-    void emitTransforms(GrGLGPBuilder*, const TransformsIn& tin, TransformsOut* tout) SK_OVERRIDE {
-        tout->push_back_n(tin.count());
-        fInstalledTransforms.push_back_n(tin.count());
-        for (int i = 0; i < tin.count(); i++) {
-            const ProcCoords& coordTransforms = tin[i];
-            int texCoordIndex = this->addTexCoordSets(coordTransforms.count());
-
-            // Use the first uniform location as the texcoord index.
-            fInstalledTransforms[i].push_back_n(1);
-            fInstalledTransforms[i][0].fHandle = ShaderVarHandle(texCoordIndex);
-
-            SkString name;
-            for (int t = 0; t < coordTransforms.count(); ++t) {
-                GrSLType type = coordTransforms[t]->getMatrix().hasPerspective() ? kVec3f_GrSLType :
-                                                                                   kVec2f_GrSLType;
-
-                name.printf("%s(gl_TexCoord[%i])", GrGLSLTypeString(type), texCoordIndex++);
-                SkNEW_APPEND_TO_TARRAY(&(*tout)[i], GrGLProcessor::TransformedCoords, (name, type));
-            }
-        }
-    }
-
-    void setTransformData(const GrPrimitiveProcessor& primProc,
-                          int index,
-                          const SkTArray<const GrCoordTransform*, true>& transforms,
-                          GrGLPathRendering* glpr,
-                          GrGLuint) SK_OVERRIDE {
-        // We've hidden the texcoord index in the first entry of the transforms array for each
-        // effect
-        int texCoordIndex = fInstalledTransforms[index][0].fHandle.handle();
-        for (int t = 0; t < transforms.count(); ++t) {
-            const SkMatrix& transform = GetTransformMatrix(primProc.localMatrix(), *transforms[t]);
-            GrGLPathRendering::PathTexGenComponents components =
-                    GrGLPathRendering::kST_PathTexGenComponents;
-            if (transform.hasPerspective()) {
-                components = GrGLPathRendering::kSTR_PathTexGenComponents;
-            }
-            glpr->enablePathTexGen(texCoordIndex++, components, transform);
-        }
-    }
-
-    void didSetData(GrGLPathRendering* glpr) SK_OVERRIDE {
-        glpr->flushPathTexGenSettings(fTexCoordSetCnt);
-    }
-
-private:
-    SkDEBUGCODE(int fMaxTexCoords;)
-    int fTexCoordSetCnt;
-
-    typedef GrGLPathProcessor INHERITED;
-};
-
-class GrGLNormalPathProcessor : public GrGLPathProcessor {
-public:
-    GrGLNormalPathProcessor(const GrPathProcessor& pathProc, const GrBatchTracker& bt)
-        : INHERITED(pathProc, bt) {}
-
-    void emitTransforms(GrGLGPBuilder* pb, const TransformsIn& tin,
-                        TransformsOut* tout) SK_OVERRIDE {
-        tout->push_back_n(tin.count());
-        fInstalledTransforms.push_back_n(tin.count());
-        for (int i = 0; i < tin.count(); i++) {
-            const ProcCoords& coordTransforms = tin[i];
-            fInstalledTransforms[i].push_back_n(coordTransforms.count());
-            for (int t = 0; t < coordTransforms.count(); t++) {
-                GrSLType varyingType =
-                        coordTransforms[t]->getMatrix().hasPerspective() ? kVec3f_GrSLType :
-                                                                           kVec2f_GrSLType;
-
-
-                SkString strVaryingName("MatrixCoord");
-                strVaryingName.appendf("_%i_%i", i, t);
-                GrGLVertToFrag v(varyingType);
-                pb->addVarying(strVaryingName.c_str(), &v);
-                SeparableVaryingInfo& varyingInfo = fSeparableVaryingInfos.push_back();
-                varyingInfo.fVariable = pb->getFragmentShaderBuilder()->fInputs.back();
-                varyingInfo.fLocation = fSeparableVaryingInfos.count() - 1;
-                varyingInfo.fType = varyingType;
-                fInstalledTransforms[i][t].fHandle = ShaderVarHandle(varyingInfo.fLocation);
-                fInstalledTransforms[i][t].fType = varyingType;
-
-                SkNEW_APPEND_TO_TARRAY(&(*tout)[i], GrGLProcessor::TransformedCoords,
-                                       (SkString(v.fsIn()), varyingType));
-            }
-        }
-    }
-
-    void resolveSeparableVaryings(GrGLGpu* gpu, GrGLuint programId) {
-        int count = fSeparableVaryingInfos.count();
-        for (int i = 0; i < count; ++i) {
-            GrGLint location;
-            GR_GL_CALL_RET(gpu->glInterface(),
-                           location,
-                           GetProgramResourceLocation(programId,
-                                                      GR_GL_FRAGMENT_INPUT,
-                                                      fSeparableVaryingInfos[i].fVariable.c_str()));
-            fSeparableVaryingInfos[i].fLocation = location;
-        }
-    }
-
-    void setTransformData(const GrPrimitiveProcessor& primProc,
-                          int index,
-                          const SkTArray<const GrCoordTransform*, true>& coordTransforms,
-                          GrGLPathRendering* glpr,
-                          GrGLuint programID) SK_OVERRIDE {
-        SkSTArray<2, Transform, true>& transforms = fInstalledTransforms[index];
-        int numTransforms = transforms.count();
-        for (int t = 0; t < numTransforms; ++t) {
-            SkASSERT(transforms[t].fHandle.isValid());
-            const SkMatrix& transform = GetTransformMatrix(primProc.localMatrix(),
-                                                           *coordTransforms[t]);
-            if (transforms[t].fCurrentValue.cheapEqualTo(transform)) {
-                continue;
-            }
-            transforms[t].fCurrentValue = transform;
-            const SeparableVaryingInfo& fragmentInput =
-                    fSeparableVaryingInfos[transforms[t].fHandle.handle()];
-            SkASSERT(transforms[t].fType == kVec2f_GrSLType ||
-                     transforms[t].fType == kVec3f_GrSLType);
-            unsigned components = transforms[t].fType == kVec2f_GrSLType ? 2 : 3;
-            glpr->setProgramPathFragmentInputTransform(programID,
-                                                       fragmentInput.fLocation,
-                                                       GR_GL_OBJECT_LINEAR,
-                                                       components,
-                                                       transform);
-        }
-    }
-
-private:
-    struct SeparableVaryingInfo {
-        GrSLType      fType;
-        GrGLShaderVar fVariable;
-        GrGLint       fLocation;
-    };
-
-
-    typedef SkSTArray<8, SeparableVaryingInfo, true> SeparableVaryingInfoArray;
-
-    SeparableVaryingInfoArray fSeparableVaryingInfos;
-
-    typedef GrGLPathProcessor INHERITED;
-};
-
-GrPathProcessor::GrPathProcessor(GrColor color,
-                                 const SkMatrix& viewMatrix,
-                                 const SkMatrix& localMatrix)
-    : INHERITED(viewMatrix, localMatrix, true)
-    , fColor(color) {
-    this->initClassID<GrPathProcessor>();
-}
-
-void GrPathProcessor::getInvariantOutputColor(GrInitInvariantOutput* out) const {
-    out->setKnownFourComponents(fColor);
-}
-
-void GrPathProcessor::getInvariantOutputCoverage(GrInitInvariantOutput* out) const {
-    out->setKnownSingleComponent(0xff);
-}
-
-void GrPathProcessor::initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const {
-    PathBatchTracker* local = bt->cast<PathBatchTracker>();
-    if (init.fColorIgnored) {
-        local->fInputColorType = kIgnored_GrGPInput;
-        local->fColor = GrColor_ILLEGAL;
-    } else {
-        local->fInputColorType = kUniform_GrGPInput;
-        local->fColor = GrColor_ILLEGAL == init.fOverrideColor ? this->color() :
-                                                                 init.fOverrideColor;
-    }
-
-    local->fInputCoverageType = init.fCoverageIgnored ? kIgnored_GrGPInput : kAllOnes_GrGPInput;
-    local->fUsesLocalCoords = init.fUsesLocalCoords;
-}
-
-bool GrPathProcessor::canMakeEqual(const GrBatchTracker& m,
-                                   const GrPrimitiveProcessor& that,
-                                   const GrBatchTracker& t) const {
-    if (this->classID() != that.classID() || !this->hasSameTextureAccesses(that)) {
-        return false;
-    }
-
-    if (!this->viewMatrix().cheapEqualTo(that.viewMatrix())) {
-        return false;
-    }
-
-    const PathBatchTracker& mine = m.cast<PathBatchTracker>();
-    const PathBatchTracker& theirs = t.cast<PathBatchTracker>();
-    return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords,
-                                   that, theirs.fUsesLocalCoords) &&
-           CanCombineOutput(mine.fInputColorType, mine.fColor,
-                            theirs.fInputColorType, theirs.fColor) &&
-           CanCombineOutput(mine.fInputCoverageType, 0xff,
-                            theirs.fInputCoverageType, 0xff);
-}
-
-void GrPathProcessor::getGLProcessorKey(const GrBatchTracker& bt,
-                                        const GrGLCaps& caps,
-                                        GrProcessorKeyBuilder* b) const {
-    GrGLPathProcessor::GenKey(*this, bt, caps, b);
-}
-
-GrGLPrimitiveProcessor* GrPathProcessor::createGLInstance(const GrBatchTracker& bt,
-                                                          const GrGLCaps& caps) const {
-    SkASSERT(caps.nvprSupport() != GrGLCaps::kNone_NvprSupport);
-    if (caps.nvprSupport() == GrGLCaps::kLegacy_NvprSupport) {
-        return SkNEW_ARGS(GrGLLegacyPathProcessor, (*this, bt,
-                                                    caps.maxFixedFunctionTextureCoords()));
-    } else {
-        return SkNEW_ARGS(GrGLNormalPathProcessor, (*this, bt));
-    }
-}
 
diff --git a/src/gpu/GrGeometryProcessor.h b/src/gpu/GrGeometryProcessor.h
index a7fea76..7f8d041 100644
--- a/src/gpu/GrGeometryProcessor.h
+++ b/src/gpu/GrGeometryProcessor.h
@@ -8,224 +8,7 @@
 #ifndef GrGeometryProcessor_DEFINED
 #define GrGeometryProcessor_DEFINED
 
-#include "GrColor.h"
-#include "GrProcessor.h"
-#include "GrShaderVar.h"
-
-/*
- * The GrPrimitiveProcessor represents some kind of geometric primitive.  This includes the shape
- * of the primitive and the inherent color of the primitive.  The GrPrimitiveProcessor is
- * responsible for providing a color and coverage input into the Ganesh rendering pipeline.  Through
- * optimization, Ganesh may decide a different color, no color, and / or no coverage are required
- * from the GrPrimitiveProcessor, so the GrPrimitiveProcessor must be able to support this
- * functionality.  We also use the GrPrimitiveProcessor to make batching decisions.
- *
- * There are two feedback loops between the GrFragmentProcessors, the GrXferProcessor, and the
- * GrPrimitiveProcessor.  These loops run on the CPU and compute any invariant components which
- * might be useful for correctness / optimization decisions.  The GrPrimitiveProcessor seeds these
- * loops, one with initial color and one with initial coverage, in its
- * onComputeInvariantColor / Coverage calls.  These seed values are processed by the subsequent
- * stages of the rendering pipeline and the output is then fed back into the GrPrimitiveProcessor in
- * the initBatchTracker call, where the GrPrimitiveProcessor can then initialize the GrBatchTracker
- * struct with the appropriate values.
- *
- * We are evolving this system to move towards generating geometric meshes and their associated
- * vertex data after we have batched and reordered draws.  This system, known as 'deferred geometry'
- * will allow the GrPrimitiveProcessor much greater control over how data is transmitted to shaders.
- *
- * In a deferred geometry world, the GrPrimitiveProcessor can always 'batch'  To do this, each
- * primitive type is associated with one GrPrimitiveProcessor, who has complete control of how
- * it draws.  Each primitive draw will bundle all required data to perform the draw, and these
- * bundles of data will be owned by an instance of the associated GrPrimitiveProcessor.  Bundles
- * can be updated alongside the GrBatchTracker struct itself, ultimately allowing the
- * GrPrimitiveProcessor complete control of how it gets data into the fragment shader as long as
- * it emits the appropriate color, or none at all, as directed.
- */
-
-/*
- * A struct for tracking batching decisions.  While this lives on GrOptState, it is managed
- * entirely by the derived classes of the GP.
- * // TODO this was an early attempt at handling out of order batching.  It should be
- * used carefully as it is being replaced by GrBatch
- */
-class GrBatchTracker {
-public:
-    template <typename T> const T& cast() const {
-        SkASSERT(sizeof(T) <= kMaxSize);
-        return *reinterpret_cast<const T*>(fData.get());
-    }
-
-    template <typename T> T* cast() {
-        SkASSERT(sizeof(T) <= kMaxSize);
-        return reinterpret_cast<T*>(fData.get());
-    }
-
-    static const size_t kMaxSize = 32;
-
-private:
-    SkAlignedSStorage<kMaxSize> fData;
-};
-
-class GrIndexBufferAllocPool;
-class GrGLCaps;
-class GrGLPrimitiveProcessor;
-class GrVertexBufferAllocPool;
-
-struct GrInitInvariantOutput;
-
-/*
- * This struct allows the GrPipeline to communicate information about the pipeline.  Most of this
- * is overrides, but some of it is general information.  Logically it should live in GrPipeline.h,
- * but this is problematic due to circular dependencies.
- */
-struct GrPipelineInfo {
-    bool fColorIgnored;
-    bool fCoverageIgnored;
-    GrColor fOverrideColor;
-    bool fUsesLocalCoords;
-};
-
-/*
- * This enum is shared by GrPrimitiveProcessors and GrGLPrimitiveProcessors to coordinate shaders
- * with vertex attributes / uniforms.
- */
-enum GrGPInput {
-    kAllOnes_GrGPInput,
-    kAttribute_GrGPInput,
-    kUniform_GrGPInput,
-    kIgnored_GrGPInput,
-};
-
-/*
- * GrPrimitiveProcessor defines an interface which all subclasses must implement.  All
- * GrPrimitiveProcessors must proivide seed color and coverage for the Ganesh color / coverage
- * pipelines, and they must provide some notion of equality
- */
-class GrPrimitiveProcessor : public GrProcessor {
-public:
-    // TODO let the PrimProc itself set this in its setData call, this should really live on the
-    // bundle of primitive data
-    const SkMatrix& viewMatrix() const { return fViewMatrix; }
-    const SkMatrix& localMatrix() const { return fLocalMatrix; }
-
-    virtual void initBatchTracker(GrBatchTracker*, const GrPipelineInfo&) const = 0;
-
-    virtual bool canMakeEqual(const GrBatchTracker& mine,
-                              const GrPrimitiveProcessor& that,
-                              const GrBatchTracker& theirs) const = 0;
-
-    virtual void getInvariantOutputColor(GrInitInvariantOutput* out) const = 0;
-    virtual void getInvariantOutputCoverage(GrInitInvariantOutput* out) const = 0;
-
-    // Only the GrGeometryProcessor subclass actually has a geo shader or vertex attributes, but
-    // we put these calls on the base class to prevent having to cast
-    virtual bool willUseGeoShader() const = 0;
-
-    /*
-     * This is a safeguard to prevent GrPrimitiveProcessor's from going beyond platform specific
-     * attribute limits. This number can almost certainly be raised if required.
-     */
-    static const int kMaxVertexAttribs = 6;
-
-    struct Attribute {
-        Attribute()
-            : fName(NULL)
-            , fType(kFloat_GrVertexAttribType)
-            , fOffset(0) {}
-        Attribute(const char* name, GrVertexAttribType type)
-            : fName(name)
-            , fType(type)
-            , fOffset(SkAlign4(GrVertexAttribTypeSize(type))) {}
-        const char* fName;
-        GrVertexAttribType fType;
-        size_t fOffset;
-    };
-
-    int numAttribs() const { return fNumAttribs; }
-    const Attribute& getAttrib(int index) const {
-        SkASSERT(index < fNumAttribs);
-        return fAttribs[index];
-    }
-
-    // Returns the vertex stride of the GP.  A common use case is to request geometry from a
-    // drawtarget based off of the stride, and to populate this memory using an implicit array of
-    // structs.  In this case, it is best to assert the vertexstride == sizeof(VertexStruct).
-    size_t getVertexStride() const { return fVertexStride; }
-
-    /**
-     * Gets a transformKey from an array of coord transforms
-     */
-    uint32_t getTransformKey(const SkTArray<const GrCoordTransform*, true>&) const;
-
-    /**
-     * Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this geometry
-     * processor's GL backend implementation.
-     */
-    virtual void getGLProcessorKey(const GrBatchTracker& bt,
-                                   const GrGLCaps& caps,
-                                   GrProcessorKeyBuilder* b) const = 0;
-
-
-    /** Returns a new instance of the appropriate *GL* implementation class
-        for the given GrProcessor; caller is responsible for deleting
-        the object. */
-    virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
-                                                     const GrGLCaps& caps) const = 0;
-
-    bool isPathRendering() const { return fIsPathRendering; }
-
-protected:
-    GrPrimitiveProcessor(const SkMatrix& viewMatrix, const SkMatrix& localMatrix,
-                         bool isPathRendering)
-        : fNumAttribs(0)
-        , fVertexStride(0)
-        , fViewMatrix(viewMatrix)
-        , fLocalMatrix(localMatrix)
-        , fIsPathRendering(isPathRendering) {}
-
-    /*
-     * CanCombineOutput will return true if two draws are 'batchable' from a color perspective.
-     * TODO remove this when GPs can upgrade to attribute color
-     */
-    static bool CanCombineOutput(GrGPInput left, GrColor lColor, GrGPInput right, GrColor rColor) {
-        if (left != right) {
-            return false;
-        }
-
-        if (kUniform_GrGPInput == left && lColor != rColor) {
-            return false;
-        }
-
-        return true;
-    }
-
-    static bool CanCombineLocalMatrices(const GrPrimitiveProcessor& left,
-                                        bool leftUsesLocalCoords,
-                                        const GrPrimitiveProcessor& right,
-                                        bool rightUsesLocalCoords) {
-        if (leftUsesLocalCoords != rightUsesLocalCoords) {
-            return false;
-        }
-
-        if (leftUsesLocalCoords && !left.localMatrix().cheapEqualTo(right.localMatrix())) {
-            return false;
-        }
-        return true;
-    }
-
-    Attribute fAttribs[kMaxVertexAttribs];
-    int fNumAttribs;
-    size_t fVertexStride;
-
-private:
-    virtual bool hasExplicitLocalCoords() const = 0;
-
-    const SkMatrix fViewMatrix;
-    SkMatrix fLocalMatrix;
-    bool fIsPathRendering;
-
-    typedef GrProcessor INHERITED;
-};
+#include "GrPrimitiveProcessor.h"
 
 /**
  * A GrGeometryProcessor is a flexible method for rendering a primitive.  The GrGeometryProcessor
@@ -370,49 +153,4 @@
     typedef GrPrimitiveProcessor INHERITED;
 };
 
-/*
- * The path equivalent of the GP.  For now this just manages color. In the long term we plan on
- * extending this class to handle all nvpr uniform / varying / program work.
- */
-class GrPathProcessor : public GrPrimitiveProcessor {
-public:
-    static GrPathProcessor* Create(GrColor color,
-                                   const SkMatrix& viewMatrix = SkMatrix::I(),
-                                   const SkMatrix& localMatrix = SkMatrix::I()) {
-        return SkNEW_ARGS(GrPathProcessor, (color, viewMatrix, localMatrix));
-    }
-    
-    void initBatchTracker(GrBatchTracker*, const GrPipelineInfo&) const SK_OVERRIDE;
-
-    bool canMakeEqual(const GrBatchTracker& mine,
-                      const GrPrimitiveProcessor& that,
-                      const GrBatchTracker& theirs) const SK_OVERRIDE;
-
-    const char* name() const SK_OVERRIDE { return "PathProcessor"; }
-
-    GrColor color() const { return fColor; }
-
-    void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE;
-    void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE;
-
-    bool willUseGeoShader() const SK_OVERRIDE { return false; }
-
-    virtual void getGLProcessorKey(const GrBatchTracker& bt,
-                                   const GrGLCaps& caps,
-                                   GrProcessorKeyBuilder* b) const SK_OVERRIDE;
-
-    virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
-                                                     const GrGLCaps& caps) const SK_OVERRIDE;
-
-protected:
-    GrPathProcessor(GrColor color, const SkMatrix& viewMatrix, const SkMatrix& localMatrix);
-
-private:
-    bool hasExplicitLocalCoords() const SK_OVERRIDE { return false; }
-
-    GrColor fColor;
-
-    typedef GrPrimitiveProcessor INHERITED;
-};
-
 #endif
diff --git a/src/gpu/GrPathProcessor.cpp b/src/gpu/GrPathProcessor.cpp
new file mode 100644
index 0000000..f6c1640
--- /dev/null
+++ b/src/gpu/GrPathProcessor.cpp
@@ -0,0 +1,73 @@
+#include "GrPathProcessor.h"
+
+#include "gl/GrGLPathProcessor.h"
+#include "gl/GrGLGpu.h"
+
+GrPathProcessor::GrPathProcessor(GrColor color,
+                                 const SkMatrix& viewMatrix,
+                                 const SkMatrix& localMatrix)
+    : INHERITED(viewMatrix, localMatrix, true)
+    , fColor(color) {
+    this->initClassID<GrPathProcessor>();
+}
+
+void GrPathProcessor::getInvariantOutputColor(GrInitInvariantOutput* out) const {
+    out->setKnownFourComponents(fColor);
+}
+
+void GrPathProcessor::getInvariantOutputCoverage(GrInitInvariantOutput* out) const {
+    out->setKnownSingleComponent(0xff);
+}
+
+void GrPathProcessor::initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const {
+    PathBatchTracker* local = bt->cast<PathBatchTracker>();
+    if (init.fColorIgnored) {
+        local->fInputColorType = kIgnored_GrGPInput;
+        local->fColor = GrColor_ILLEGAL;
+    } else {
+        local->fInputColorType = kUniform_GrGPInput;
+        local->fColor = GrColor_ILLEGAL == init.fOverrideColor ? this->color() :
+                                                                 init.fOverrideColor;
+    }
+
+    local->fInputCoverageType = init.fCoverageIgnored ? kIgnored_GrGPInput : kAllOnes_GrGPInput;
+    local->fUsesLocalCoords = init.fUsesLocalCoords;
+}
+
+bool GrPathProcessor::canMakeEqual(const GrBatchTracker& m,
+                                   const GrPrimitiveProcessor& that,
+                                   const GrBatchTracker& t) const {
+    if (this->classID() != that.classID() || !this->hasSameTextureAccesses(that)) {
+        return false;
+    }
+
+    if (!this->viewMatrix().cheapEqualTo(that.viewMatrix())) {
+        return false;
+    }
+
+    const PathBatchTracker& mine = m.cast<PathBatchTracker>();
+    const PathBatchTracker& theirs = t.cast<PathBatchTracker>();
+    return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords,
+                                   that, theirs.fUsesLocalCoords) &&
+           CanCombineOutput(mine.fInputColorType, mine.fColor,
+                            theirs.fInputColorType, theirs.fColor) &&
+           CanCombineOutput(mine.fInputCoverageType, 0xff,
+                            theirs.fInputCoverageType, 0xff);
+}
+
+void GrPathProcessor::getGLProcessorKey(const GrBatchTracker& bt,
+                                        const GrGLCaps& caps,
+                                        GrProcessorKeyBuilder* b) const {
+    GrGLPathProcessor::GenKey(*this, bt, caps, b);
+}
+
+GrGLPrimitiveProcessor* GrPathProcessor::createGLInstance(const GrBatchTracker& bt,
+                                                          const GrGLCaps& caps) const {
+    SkASSERT(caps.nvprSupport() != GrGLCaps::kNone_NvprSupport);
+    if (caps.nvprSupport() == GrGLCaps::kLegacy_NvprSupport) {
+        return SkNEW_ARGS(GrGLLegacyPathProcessor, (*this, bt,
+                                                    caps.maxFixedFunctionTextureCoords()));
+    } else {
+        return SkNEW_ARGS(GrGLNormalPathProcessor, (*this, bt));
+    }
+}
diff --git a/src/gpu/GrPathProcessor.h b/src/gpu/GrPathProcessor.h
new file mode 100644
index 0000000..03d3907
--- /dev/null
+++ b/src/gpu/GrPathProcessor.h
@@ -0,0 +1,65 @@
+/*
+ * 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 GrPathProcessor_DEFINED
+#define GrPathProcessor_DEFINED
+
+#include "GrPrimitiveProcessor.h"
+
+struct PathBatchTracker {
+    GrGPInput fInputColorType;
+    GrGPInput fInputCoverageType;
+    GrColor fColor;
+    bool fUsesLocalCoords;
+};
+
+/*
+ * The path equivalent of the GP.  For now this just manages color. In the long term we plan on
+ * extending this class to handle all nvpr uniform / varying / program work.
+ */
+class GrPathProcessor : public GrPrimitiveProcessor {
+public:
+    static GrPathProcessor* Create(GrColor color,
+                                   const SkMatrix& viewMatrix = SkMatrix::I(),
+                                   const SkMatrix& localMatrix = SkMatrix::I()) {
+        return SkNEW_ARGS(GrPathProcessor, (color, viewMatrix, localMatrix));
+    }
+
+    void initBatchTracker(GrBatchTracker*, const GrPipelineInfo&) const SK_OVERRIDE;
+
+    bool canMakeEqual(const GrBatchTracker& mine,
+                      const GrPrimitiveProcessor& that,
+                      const GrBatchTracker& theirs) const SK_OVERRIDE;
+
+    const char* name() const SK_OVERRIDE { return "PathProcessor"; }
+
+    GrColor color() const { return fColor; }
+
+    void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE;
+    void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE;
+
+    bool willUseGeoShader() const SK_OVERRIDE { return false; }
+
+    virtual void getGLProcessorKey(const GrBatchTracker& bt,
+                                   const GrGLCaps& caps,
+                                   GrProcessorKeyBuilder* b) const SK_OVERRIDE;
+
+    virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
+                                                     const GrGLCaps& caps) const SK_OVERRIDE;
+
+protected:
+    GrPathProcessor(GrColor color, const SkMatrix& viewMatrix, const SkMatrix& localMatrix);
+
+private:
+    bool hasExplicitLocalCoords() const SK_OVERRIDE { return false; }
+
+    GrColor fColor;
+
+    typedef GrPrimitiveProcessor INHERITED;
+};
+
+#endif
diff --git a/src/gpu/GrPipelineBuilder.h b/src/gpu/GrPipelineBuilder.h
index 5743c39..c6adf87 100644
--- a/src/gpu/GrPipelineBuilder.h
+++ b/src/gpu/GrPipelineBuilder.h
@@ -11,7 +11,6 @@
 #include "GrBatch.h"
 #include "GrBlend.h"
 #include "GrDrawTargetCaps.h"
-#include "GrGeometryProcessor.h"
 #include "GrGpuResourceRef.h"
 #include "GrFragmentStage.h"
 #include "GrProcOptInfo.h"
diff --git a/src/gpu/GrPrimitiveProcessor.cpp b/src/gpu/GrPrimitiveProcessor.cpp
new file mode 100644
index 0000000..6736568
--- /dev/null
+++ b/src/gpu/GrPrimitiveProcessor.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrPrimitiveProcessor.h"
+
+#include "GrCoordTransform.h"
+
+/**
+ * The key for an individual coord transform is made up of a matrix type, a precision, and a bit
+ * that indicates the source of the input coords.
+ */
+enum {
+    kMatrixTypeKeyBits   = 1,
+    kMatrixTypeKeyMask   = (1 << kMatrixTypeKeyBits) - 1,
+
+    kPrecisionBits       = 2,
+    kPrecisionShift      = kMatrixTypeKeyBits,
+
+    kPositionCoords_Flag = (1 << (kPrecisionShift + kPrecisionBits)),
+    kDeviceCoords_Flag   = kPositionCoords_Flag + kPositionCoords_Flag,
+
+    kTransformKeyBits    = kMatrixTypeKeyBits + kPrecisionBits + 2,
+};
+
+GR_STATIC_ASSERT(kHigh_GrSLPrecision < (1 << kPrecisionBits));
+
+/**
+ * We specialize the vertex code for each of these matrix types.
+ */
+enum MatrixType {
+    kNoPersp_MatrixType  = 0,
+    kGeneral_MatrixType  = 1,
+};
+
+uint32_t
+GrPrimitiveProcessor::getTransformKey(const SkTArray<const GrCoordTransform*, true>& coords) const {
+    uint32_t totalKey = 0;
+    for (int t = 0; t < coords.count(); ++t) {
+        uint32_t key = 0;
+        const GrCoordTransform* coordTransform = coords[t];
+        if (coordTransform->getMatrix().hasPerspective()) {
+            key |= kGeneral_MatrixType;
+        } else {
+            key |= kNoPersp_MatrixType;
+        }
+
+        if (kLocal_GrCoordSet == coordTransform->sourceCoords() &&
+            !this->hasExplicitLocalCoords()) {
+            key |= kPositionCoords_Flag;
+        } else if (kDevice_GrCoordSet == coordTransform->sourceCoords()) {
+            key |= kDeviceCoords_Flag;
+        }
+
+        GR_STATIC_ASSERT(kGrSLPrecisionCount <= (1 << kPrecisionBits));
+        key |= (coordTransform->precision() << kPrecisionShift);
+
+        key <<= kTransformKeyBits * t;
+
+        SkASSERT(0 == (totalKey & key)); // keys for each transform ought not to overlap
+        totalKey |= key;
+    }
+    return totalKey;
+}
diff --git a/src/gpu/GrPrimitiveProcessor.h b/src/gpu/GrPrimitiveProcessor.h
new file mode 100644
index 0000000..a088d38
--- /dev/null
+++ b/src/gpu/GrPrimitiveProcessor.h
@@ -0,0 +1,230 @@
+/*
+ * 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 GrPrimitiveProcessor_DEFINED
+#define GrPrimitiveProcessor_DEFINED
+
+#include "GrColor.h"
+#include "GrProcessor.h"
+#include "GrShaderVar.h"
+
+/*
+ * The GrPrimitiveProcessor represents some kind of geometric primitive.  This includes the shape
+ * of the primitive and the inherent color of the primitive.  The GrPrimitiveProcessor is
+ * responsible for providing a color and coverage input into the Ganesh rendering pipeline.  Through
+ * optimization, Ganesh may decide a different color, no color, and / or no coverage are required
+ * from the GrPrimitiveProcessor, so the GrPrimitiveProcessor must be able to support this
+ * functionality.  We also use the GrPrimitiveProcessor to make batching decisions.
+ *
+ * There are two feedback loops between the GrFragmentProcessors, the GrXferProcessor, and the
+ * GrPrimitiveProcessor.  These loops run on the CPU and compute any invariant components which
+ * might be useful for correctness / optimization decisions.  The GrPrimitiveProcessor seeds these
+ * loops, one with initial color and one with initial coverage, in its
+ * onComputeInvariantColor / Coverage calls.  These seed values are processed by the subsequent
+ * stages of the rendering pipeline and the output is then fed back into the GrPrimitiveProcessor in
+ * the initBatchTracker call, where the GrPrimitiveProcessor can then initialize the GrBatchTracker
+ * struct with the appropriate values.
+ *
+ * We are evolving this system to move towards generating geometric meshes and their associated
+ * vertex data after we have batched and reordered draws.  This system, known as 'deferred geometry'
+ * will allow the GrPrimitiveProcessor much greater control over how data is transmitted to shaders.
+ *
+ * In a deferred geometry world, the GrPrimitiveProcessor can always 'batch'  To do this, each
+ * primitive type is associated with one GrPrimitiveProcessor, who has complete control of how
+ * it draws.  Each primitive draw will bundle all required data to perform the draw, and these
+ * bundles of data will be owned by an instance of the associated GrPrimitiveProcessor.  Bundles
+ * can be updated alongside the GrBatchTracker struct itself, ultimately allowing the
+ * GrPrimitiveProcessor complete control of how it gets data into the fragment shader as long as
+ * it emits the appropriate color, or none at all, as directed.
+ */
+
+/*
+ * A struct for tracking batching decisions.  While this lives on GrOptState, it is managed
+ * entirely by the derived classes of the GP.
+ * // TODO this was an early attempt at handling out of order batching.  It should be
+ * used carefully as it is being replaced by GrBatch
+ */
+class GrBatchTracker {
+public:
+    template <typename T> const T& cast() const {
+        SkASSERT(sizeof(T) <= kMaxSize);
+        return *reinterpret_cast<const T*>(fData.get());
+    }
+
+    template <typename T> T* cast() {
+        SkASSERT(sizeof(T) <= kMaxSize);
+        return reinterpret_cast<T*>(fData.get());
+    }
+
+    static const size_t kMaxSize = 32;
+
+private:
+    SkAlignedSStorage<kMaxSize> fData;
+};
+
+class GrIndexBufferAllocPool;
+class GrGLCaps;
+class GrGLPrimitiveProcessor;
+class GrVertexBufferAllocPool;
+
+struct GrInitInvariantOutput;
+
+/*
+ * This struct allows the GrPipeline to communicate information about the pipeline.  Most of this
+ * is overrides, but some of it is general information.  Logically it should live in GrPipeline.h,
+ * but this is problematic due to circular dependencies.
+ */
+struct GrPipelineInfo {
+    bool fColorIgnored;
+    bool fCoverageIgnored;
+    GrColor fOverrideColor;
+    bool fUsesLocalCoords;
+};
+
+/*
+ * This enum is shared by GrPrimitiveProcessors and GrGLPrimitiveProcessors to coordinate shaders
+ * with vertex attributes / uniforms.
+ */
+enum GrGPInput {
+    kAllOnes_GrGPInput,
+    kAttribute_GrGPInput,
+    kUniform_GrGPInput,
+    kIgnored_GrGPInput,
+};
+
+/*
+ * GrPrimitiveProcessor defines an interface which all subclasses must implement.  All
+ * GrPrimitiveProcessors must proivide seed color and coverage for the Ganesh color / coverage
+ * pipelines, and they must provide some notion of equality
+ */
+class GrPrimitiveProcessor : public GrProcessor {
+public:
+    // TODO let the PrimProc itself set this in its setData call, this should really live on the
+    // bundle of primitive data
+    const SkMatrix& viewMatrix() const { return fViewMatrix; }
+    const SkMatrix& localMatrix() const { return fLocalMatrix; }
+
+    virtual void initBatchTracker(GrBatchTracker*, const GrPipelineInfo&) const = 0;
+
+    virtual bool canMakeEqual(const GrBatchTracker& mine,
+                              const GrPrimitiveProcessor& that,
+                              const GrBatchTracker& theirs) const = 0;
+
+    virtual void getInvariantOutputColor(GrInitInvariantOutput* out) const = 0;
+    virtual void getInvariantOutputCoverage(GrInitInvariantOutput* out) const = 0;
+
+    // Only the GrGeometryProcessor subclass actually has a geo shader or vertex attributes, but
+    // we put these calls on the base class to prevent having to cast
+    virtual bool willUseGeoShader() const = 0;
+
+    /*
+     * This is a safeguard to prevent GrPrimitiveProcessor's from going beyond platform specific
+     * attribute limits. This number can almost certainly be raised if required.
+     */
+    static const int kMaxVertexAttribs = 6;
+
+    struct Attribute {
+        Attribute()
+            : fName(NULL)
+            , fType(kFloat_GrVertexAttribType)
+            , fOffset(0) {}
+        Attribute(const char* name, GrVertexAttribType type)
+            : fName(name)
+            , fType(type)
+            , fOffset(SkAlign4(GrVertexAttribTypeSize(type))) {}
+        const char* fName;
+        GrVertexAttribType fType;
+        size_t fOffset;
+    };
+
+    int numAttribs() const { return fNumAttribs; }
+    const Attribute& getAttrib(int index) const {
+        SkASSERT(index < fNumAttribs);
+        return fAttribs[index];
+    }
+
+    // Returns the vertex stride of the GP.  A common use case is to request geometry from a
+    // drawtarget based off of the stride, and to populate this memory using an implicit array of
+    // structs.  In this case, it is best to assert the vertexstride == sizeof(VertexStruct).
+    size_t getVertexStride() const { return fVertexStride; }
+
+    /**
+     * Gets a transformKey from an array of coord transforms
+     */
+    uint32_t getTransformKey(const SkTArray<const GrCoordTransform*, true>&) const;
+
+    /**
+     * Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this geometry
+     * processor's GL backend implementation.
+     */
+    virtual void getGLProcessorKey(const GrBatchTracker& bt,
+                                   const GrGLCaps& caps,
+                                   GrProcessorKeyBuilder* b) const = 0;
+
+
+    /** Returns a new instance of the appropriate *GL* implementation class
+        for the given GrProcessor; caller is responsible for deleting
+        the object. */
+    virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
+                                                     const GrGLCaps& caps) const = 0;
+
+    bool isPathRendering() const { return fIsPathRendering; }
+
+protected:
+    GrPrimitiveProcessor(const SkMatrix& viewMatrix, const SkMatrix& localMatrix,
+                         bool isPathRendering)
+        : fNumAttribs(0)
+        , fVertexStride(0)
+        , fViewMatrix(viewMatrix)
+        , fLocalMatrix(localMatrix)
+        , fIsPathRendering(isPathRendering) {}
+
+    /*
+     * CanCombineOutput will return true if two draws are 'batchable' from a color perspective.
+     * TODO remove this when GPs can upgrade to attribute color
+     */
+    static bool CanCombineOutput(GrGPInput left, GrColor lColor, GrGPInput right, GrColor rColor) {
+        if (left != right) {
+            return false;
+        }
+
+        if (kUniform_GrGPInput == left && lColor != rColor) {
+            return false;
+        }
+
+        return true;
+    }
+
+    static bool CanCombineLocalMatrices(const GrPrimitiveProcessor& left,
+                                        bool leftUsesLocalCoords,
+                                        const GrPrimitiveProcessor& right,
+                                        bool rightUsesLocalCoords) {
+        if (leftUsesLocalCoords != rightUsesLocalCoords) {
+            return false;
+        }
+
+        if (leftUsesLocalCoords && !left.localMatrix().cheapEqualTo(right.localMatrix())) {
+            return false;
+        }
+        return true;
+    }
+
+    Attribute fAttribs[kMaxVertexAttribs];
+    int fNumAttribs;
+    size_t fVertexStride;
+
+private:
+    virtual bool hasExplicitLocalCoords() const = 0;
+
+    const SkMatrix fViewMatrix;
+    SkMatrix fLocalMatrix;
+    bool fIsPathRendering;
+
+    typedef GrProcessor INHERITED;
+};
+
+#endif
diff --git a/src/gpu/gl/GrGLGeometryProcessor.cpp b/src/gpu/gl/GrGLGeometryProcessor.cpp
new file mode 100644
index 0000000..a8d020a
--- /dev/null
+++ b/src/gpu/gl/GrGLGeometryProcessor.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrGLGeometryProcessor.h"
+
+#include "builders/GrGLProgramBuilder.h"
+
+void GrGLGeometryProcessor::emitCode(EmitArgs& args) {
+    GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
+    GrGPArgs gpArgs;
+    this->onEmitCode(args, &gpArgs);
+    vsBuilder->transformToNormalizedDeviceSpace(gpArgs.fPositionVar);
+}
+
+void GrGLGeometryProcessor::emitTransforms(GrGLGPBuilder* pb,
+                                           const GrShaderVar& posVar,
+                                           const char* localCoords,
+                                           const SkMatrix& localMatrix,
+                                           const TransformsIn& tin,
+                                           TransformsOut* tout) {
+    GrGLVertexBuilder* vb = pb->getVertexShaderBuilder();
+    tout->push_back_n(tin.count());
+    fInstalledTransforms.push_back_n(tin.count());
+    for (int i = 0; i < tin.count(); i++) {
+        const ProcCoords& coordTransforms = tin[i];
+        fInstalledTransforms[i].push_back_n(coordTransforms.count());
+        for (int t = 0; t < coordTransforms.count(); t++) {
+            SkString strUniName("StageMatrix");
+            strUniName.appendf("_%i_%i", i, t);
+            GrSLType varyingType;
+
+            GrCoordSet coordType = coordTransforms[t]->sourceCoords();
+            uint32_t type = coordTransforms[t]->getMatrix().getType();
+            if (kLocal_GrCoordSet == coordType) {
+                type |= localMatrix.getType();
+            }
+            varyingType = SkToBool(SkMatrix::kPerspective_Mask & type) ? kVec3f_GrSLType :
+                                                                         kVec2f_GrSLType;
+            GrSLPrecision precision = coordTransforms[t]->precision();
+
+            const char* uniName;
+            fInstalledTransforms[i][t].fHandle =
+                    pb->addUniform(GrGLProgramBuilder::kVertex_Visibility,
+                                   kMat33f_GrSLType, precision,
+                                   strUniName.c_str(),
+                                   &uniName).toShaderBuilderIndex();
+
+            SkString strVaryingName("MatrixCoord");
+            strVaryingName.appendf("_%i_%i", i, t);
+
+            GrGLVertToFrag v(varyingType);
+            pb->addVarying(strVaryingName.c_str(), &v, precision);
+
+            SkASSERT(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType);
+            SkNEW_APPEND_TO_TARRAY(&(*tout)[i], GrGLProcessor::TransformedCoords,
+                                   (SkString(v.fsIn()), varyingType));
+
+            // varying = matrix * coords (logically)
+            if (kDevice_GrCoordSet == coordType) {
+                if (kVec2f_GrSLType == varyingType) {
+                    if (kVec2f_GrSLType == posVar.getType()) {
+                        vb->codeAppendf("%s = (%s * vec3(%s, 1)).xy;",
+                                        v.vsOut(), uniName, posVar.c_str());
+                    } else {
+                        // The brackets here are just to scope the temp variable
+                        vb->codeAppendf("{ vec3 temp = %s * %s;", uniName, posVar.c_str());
+                        vb->codeAppendf("%s = vec2(temp.x/temp.z, temp.y/temp.z); }", v.vsOut());
+                    }
+                } else {
+                    if (kVec2f_GrSLType == posVar.getType()) {
+                        vb->codeAppendf("%s = %s * vec3(%s, 1);",
+                                        v.vsOut(), uniName, posVar.c_str());
+                    } else {
+                        vb->codeAppendf("%s = %s * %s;", v.vsOut(), uniName, posVar.c_str());
+                    }
+                }
+            } else {
+                if (kVec2f_GrSLType == varyingType) {
+                    vb->codeAppendf("%s = (%s * vec3(%s, 1)).xy;", v.vsOut(), uniName, localCoords);
+                } else {
+                    vb->codeAppendf("%s = %s * vec3(%s, 1);", v.vsOut(), uniName, localCoords);
+                }
+            }
+        }
+    }
+}
+
+void
+GrGLGeometryProcessor::setTransformData(const GrPrimitiveProcessor& primProc,
+                                        const GrGLProgramDataManager& pdman,
+                                        int index,
+                                        const SkTArray<const GrCoordTransform*, true>& transforms) {
+    SkSTArray<2, Transform, true>& procTransforms = fInstalledTransforms[index];
+    int numTransforms = transforms.count();
+    for (int t = 0; t < numTransforms; ++t) {
+        SkASSERT(procTransforms[t].fHandle.isValid());
+        const SkMatrix& transform = GetTransformMatrix(primProc.localMatrix(), *transforms[t]);
+        if (!procTransforms[t].fCurrentValue.cheapEqualTo(transform)) {
+            pdman.setSkMatrix(procTransforms[t].fHandle.convertToUniformHandle(), transform);
+            procTransforms[t].fCurrentValue = transform;
+        }
+    }
+}
+
+void GrGLGeometryProcessor::SetupPosition(GrGLVertexBuilder* vsBuilder,
+                                          GrGPArgs* gpArgs,
+                                          const char* posName,
+                                          const SkMatrix& mat,
+                                          const char* matName) {
+    if (mat.isIdentity()) {
+        gpArgs->fPositionVar.set(kVec2f_GrSLType, "pos2");
+
+        vsBuilder->codeAppendf("vec2 %s = %s;", gpArgs->fPositionVar.c_str(), posName);
+    } else if (!mat.hasPerspective()) {
+        gpArgs->fPositionVar.set(kVec2f_GrSLType, "pos2");
+
+        vsBuilder->codeAppendf("vec2 %s = vec2(%s * vec3(%s, 1));",
+                               gpArgs->fPositionVar.c_str(), matName, posName);
+    } else {
+        gpArgs->fPositionVar.set(kVec3f_GrSLType, "pos3");
+
+        vsBuilder->codeAppendf("vec3 %s = %s * vec3(%s, 1);",
+                               gpArgs->fPositionVar.c_str(), matName, posName);
+    }
+}
diff --git a/src/gpu/gl/GrGLGeometryProcessor.h b/src/gpu/gl/GrGLGeometryProcessor.h
index da6c347..e8b16af 100644
--- a/src/gpu/gl/GrGLGeometryProcessor.h
+++ b/src/gpu/gl/GrGLGeometryProcessor.h
@@ -8,126 +8,10 @@
 #ifndef GrGLGeometryProcessor_DEFINED
 #define GrGLGeometryProcessor_DEFINED
 
-#include "GrGLProcessor.h"
+#include "GrGLPrimitiveProcessor.h"
 
-class GrBatchTracker;
-class GrFragmentProcessor;
-class GrGLGPBuilder;
-
-class GrGLPrimitiveProcessor {
-public:
-    GrGLPrimitiveProcessor() : fViewMatrixName(NULL) { fViewMatrix = SkMatrix::InvalidMatrix(); }
-    virtual ~GrGLPrimitiveProcessor() {}
-
-    typedef GrGLProgramDataManager::UniformHandle UniformHandle;
-    typedef GrGLProcessor::TextureSamplerArray TextureSamplerArray;
-
-    typedef SkSTArray<2, const GrCoordTransform*, true> ProcCoords;
-    typedef SkSTArray<8, ProcCoords> TransformsIn;
-    typedef SkSTArray<8, GrGLProcessor::TransformedCoordsArray> TransformsOut;
-
-    struct EmitArgs {
-        EmitArgs(GrGLGPBuilder* pb,
-                 const GrPrimitiveProcessor& gp,
-                 const GrBatchTracker& bt,
-                 const char* outputColor,
-                 const char* outputCoverage,
-                 const TextureSamplerArray& samplers,
-                 const TransformsIn& transformsIn,
-                 TransformsOut* transformsOut)
-            : fPB(pb)
-            , fGP(gp)
-            , fBT(bt)
-            , fOutputColor(outputColor)
-            , fOutputCoverage(outputCoverage)
-            , fSamplers(samplers)
-            , fTransformsIn(transformsIn)
-            , fTransformsOut(transformsOut) {}
-        GrGLGPBuilder* fPB;
-        const GrPrimitiveProcessor& fGP;
-        const GrBatchTracker& fBT;
-        const char* fOutputColor;
-        const char* fOutputCoverage;
-        const TextureSamplerArray& fSamplers;
-        const TransformsIn& fTransformsIn;
-        TransformsOut* fTransformsOut;
-    };
-
-    /**
-     * This is similar to emitCode() in the base class, except it takes a full shader builder.
-     * This allows the effect subclass to emit vertex code.
-     */
-    virtual void emitCode(EmitArgs&) = 0;
-
-
-    /** A GrGLPrimitiveProcessor instance can be reused with any GrGLPrimitiveProcessor that
-        produces the same stage key; this function reads data from a GrGLPrimitiveProcessor and
-        uploads any uniform variables required  by the shaders created in emitCode(). The
-        GrPrimitiveProcessor parameter is guaranteed to be of the same type that created this
-        GrGLPrimitiveProcessor and to have an identical processor key as the one that created this
-        GrGLPrimitiveProcessor.  */
-    virtual void setData(const GrGLProgramDataManager&,
-                         const GrPrimitiveProcessor&,
-                         const GrBatchTracker&) = 0;
-
-    static SkMatrix GetTransformMatrix(const SkMatrix& localMatrix, const GrCoordTransform&);
-
-protected:
-    /** a helper which can setup vertex, constant, or uniform color depending on inputType.
-     *  This function will only do the minimum required to emit the correct shader code.  If
-     *  inputType == attribute, then colorAttr must not be NULL.  Likewise, if inputType == Uniform
-     *  then colorUniform must not be NULL.
-     */
-    void setupColorPassThrough(GrGLGPBuilder* pb,
-                               GrGPInput inputType,
-                               const char* inputName,
-                               const GrGeometryProcessor::Attribute* colorAttr,
-                               UniformHandle* colorUniform);
-
-    const char* uViewM() const { return fViewMatrixName; }
-
-    /** a helper function to setup the uniform handle for the uniform view matrix */
-    void addUniformViewMatrix(GrGLGPBuilder*);
-
-
-    /** a helper function to upload a uniform viewmatrix.
-     * TODO we can remove this function when we have deferred geometry in place
-     */
-    void setUniformViewMatrix(const GrGLProgramDataManager&,
-                              const SkMatrix& viewMatrix);
-
-    class ShaderVarHandle {
-    public:
-        bool isValid() const { return fHandle > -1; }
-        ShaderVarHandle() : fHandle(-1) {}
-        ShaderVarHandle(int value) : fHandle(value) { SkASSERT(this->isValid()); }
-        int handle() const { SkASSERT(this->isValid()); return fHandle; }
-        UniformHandle convertToUniformHandle() {
-            SkASSERT(this->isValid());
-            return GrGLProgramDataManager::UniformHandle::CreateFromUniformIndex(fHandle);
-        }
-
-    private:
-        int fHandle;
-    };
-
-    struct Transform {
-        Transform() : fType(kVoid_GrSLType) { fCurrentValue = SkMatrix::InvalidMatrix(); }
-        ShaderVarHandle fHandle;
-        SkMatrix       fCurrentValue;
-        GrSLType       fType;
-    };
-
-    SkSTArray<8, SkSTArray<2, Transform, true> > fInstalledTransforms;
-
-private:
-    UniformHandle fViewMatrixUniform;
-    SkMatrix fViewMatrix;
-    const char* fViewMatrixName;
-};
-
-class GrGLPathRendering;
 class GrGLVertexBuilder;
+
 /**
  * If a GL effect needs a GrGLFullShaderBuilder* object to emit vertex code, then it must inherit
  * from this class. Since paths don't have vertices, this class is only meant to be used internally
@@ -189,40 +73,4 @@
     typedef GrGLPrimitiveProcessor INHERITED;
 };
 
-class GrGLGpu;
-
-class GrGLPathProcessor : public GrGLPrimitiveProcessor {
-public:
-    GrGLPathProcessor(const GrPathProcessor&, const GrBatchTracker&);
-
-    static void GenKey(const GrPathProcessor&,
-                       const GrBatchTracker& bt,
-                       const GrGLCaps&,
-                       GrProcessorKeyBuilder* b);
-
-    void emitCode(EmitArgs&) SK_OVERRIDE;
-
-    virtual void emitTransforms(GrGLGPBuilder*, const TransformsIn&, TransformsOut*) = 0;
-
-    virtual void resolveSeparableVaryings(GrGLGpu* gpu, GrGLuint programId) {}
-
-    void setData(const GrGLProgramDataManager&,
-                 const GrPrimitiveProcessor&,
-                 const GrBatchTracker&) SK_OVERRIDE;
-
-    virtual void setTransformData(const GrPrimitiveProcessor&,
-                                  int index,
-                                  const SkTArray<const GrCoordTransform*, true>& transforms,
-                                  GrGLPathRendering*,
-                                  GrGLuint programID) = 0;
-
-    virtual void didSetData(GrGLPathRendering*) {}
-
-private:
-    UniformHandle fColorUniform;
-    GrColor fColor;
-
-    typedef GrGLPrimitiveProcessor INHERITED;
-};
-
 #endif
diff --git a/src/gpu/gl/GrGLPathProcessor.cpp b/src/gpu/gl/GrGLPathProcessor.cpp
new file mode 100644
index 0000000..3f3e5d9
--- /dev/null
+++ b/src/gpu/gl/GrGLPathProcessor.cpp
@@ -0,0 +1,183 @@
+/*
+ * 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 "GrGLPathProcessor.h"
+
+#include "GrPathProcessor.h"
+#include "GrGLGpu.h"
+#include "GrGLPathRendering.h"
+
+GrGLPathProcessor::GrGLPathProcessor(const GrPathProcessor&, const GrBatchTracker&)
+    : fColor(GrColor_ILLEGAL) {}
+
+void GrGLPathProcessor::emitCode(EmitArgs& args) {
+    GrGLGPBuilder* pb = args.fPB;
+    GrGLGPFragmentBuilder* fs = args.fPB->getFragmentShaderBuilder();
+    const PathBatchTracker& local = args.fBT.cast<PathBatchTracker>();
+
+    // emit transforms
+    this->emitTransforms(args.fPB, args.fTransformsIn, args.fTransformsOut);
+
+    // Setup uniform color
+    if (kUniform_GrGPInput == local.fInputColorType) {
+        const char* stagedLocalVarName;
+        fColorUniform = pb->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+                                       kVec4f_GrSLType,
+                                       kDefault_GrSLPrecision,
+                                       "Color",
+                                       &stagedLocalVarName);
+        fs->codeAppendf("%s = %s;", args.fOutputColor, stagedLocalVarName);
+    }
+
+    // setup constant solid coverage
+    if (kAllOnes_GrGPInput == local.fInputCoverageType) {
+        fs->codeAppendf("%s = vec4(1);", args.fOutputCoverage);
+    }
+}
+
+void GrGLPathProcessor::GenKey(const GrPathProcessor&,
+                               const GrBatchTracker& bt,
+                               const GrGLCaps&,
+                               GrProcessorKeyBuilder* b) {
+    const PathBatchTracker& local = bt.cast<PathBatchTracker>();
+    b->add32(local.fInputColorType | local.fInputCoverageType << 16);
+}
+
+void GrGLPathProcessor::setData(const GrGLProgramDataManager& pdman,
+                                const GrPrimitiveProcessor& primProc,
+                                const GrBatchTracker& bt) {
+    const PathBatchTracker& local = bt.cast<PathBatchTracker>();
+    if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
+        GrGLfloat c[4];
+        GrColorToRGBAFloat(local.fColor, c);
+        pdman.set4fv(fColorUniform, 1, c);
+        fColor = local.fColor;
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void GrGLLegacyPathProcessor::emitTransforms(GrGLGPBuilder*, const TransformsIn& tin,
+                                             TransformsOut* tout) {
+    tout->push_back_n(tin.count());
+    fInstalledTransforms.push_back_n(tin.count());
+    for (int i = 0; i < tin.count(); i++) {
+        const ProcCoords& coordTransforms = tin[i];
+        int texCoordIndex = this->addTexCoordSets(coordTransforms.count());
+
+        // Use the first uniform location as the texcoord index.
+        fInstalledTransforms[i].push_back_n(1);
+        fInstalledTransforms[i][0].fHandle = ShaderVarHandle(texCoordIndex);
+
+        SkString name;
+        for (int t = 0; t < coordTransforms.count(); ++t) {
+            GrSLType type = coordTransforms[t]->getMatrix().hasPerspective() ? kVec3f_GrSLType :
+                                                                               kVec2f_GrSLType;
+
+            name.printf("%s(gl_TexCoord[%i])", GrGLSLTypeString(type), texCoordIndex++);
+            SkNEW_APPEND_TO_TARRAY(&(*tout)[i], GrGLProcessor::TransformedCoords, (name, type));
+        }
+    }
+}
+
+void GrGLLegacyPathProcessor::setTransformData(
+        const GrPrimitiveProcessor& primProc,
+        int index,
+        const SkTArray<const GrCoordTransform*, true>& transforms,
+        GrGLPathRendering* glpr,
+        GrGLuint) {
+    // We've hidden the texcoord index in the first entry of the transforms array for each
+    // effect
+    int texCoordIndex = fInstalledTransforms[index][0].fHandle.handle();
+    for (int t = 0; t < transforms.count(); ++t) {
+        const SkMatrix& transform = GetTransformMatrix(primProc.localMatrix(), *transforms[t]);
+        GrGLPathRendering::PathTexGenComponents components =
+                GrGLPathRendering::kST_PathTexGenComponents;
+        if (transform.hasPerspective()) {
+            components = GrGLPathRendering::kSTR_PathTexGenComponents;
+        }
+        glpr->enablePathTexGen(texCoordIndex++, components, transform);
+    }
+}
+
+void GrGLLegacyPathProcessor::didSetData(GrGLPathRendering* glpr) {
+    glpr->flushPathTexGenSettings(fTexCoordSetCnt);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void GrGLNormalPathProcessor::emitTransforms(GrGLGPBuilder* pb, const TransformsIn& tin,
+                                             TransformsOut* tout) {
+    tout->push_back_n(tin.count());
+    fInstalledTransforms.push_back_n(tin.count());
+    for (int i = 0; i < tin.count(); i++) {
+        const ProcCoords& coordTransforms = tin[i];
+        fInstalledTransforms[i].push_back_n(coordTransforms.count());
+        for (int t = 0; t < coordTransforms.count(); t++) {
+            GrSLType varyingType =
+                    coordTransforms[t]->getMatrix().hasPerspective() ? kVec3f_GrSLType :
+                                                                       kVec2f_GrSLType;
+
+
+            SkString strVaryingName("MatrixCoord");
+            strVaryingName.appendf("_%i_%i", i, t);
+            GrGLVertToFrag v(varyingType);
+            pb->addVarying(strVaryingName.c_str(), &v);
+            SeparableVaryingInfo& varyingInfo = fSeparableVaryingInfos.push_back();
+            varyingInfo.fVariable = pb->getFragmentShaderBuilder()->fInputs.back();
+            varyingInfo.fLocation = fSeparableVaryingInfos.count() - 1;
+            varyingInfo.fType = varyingType;
+            fInstalledTransforms[i][t].fHandle = ShaderVarHandle(varyingInfo.fLocation);
+            fInstalledTransforms[i][t].fType = varyingType;
+
+            SkNEW_APPEND_TO_TARRAY(&(*tout)[i], GrGLProcessor::TransformedCoords,
+                                   (SkString(v.fsIn()), varyingType));
+        }
+    }
+}
+
+void GrGLNormalPathProcessor::resolveSeparableVaryings(GrGLGpu* gpu, GrGLuint programId) {
+    int count = fSeparableVaryingInfos.count();
+    for (int i = 0; i < count; ++i) {
+        GrGLint location;
+        GR_GL_CALL_RET(gpu->glInterface(),
+                       location,
+                       GetProgramResourceLocation(programId,
+                                                  GR_GL_FRAGMENT_INPUT,
+                                                  fSeparableVaryingInfos[i].fVariable.c_str()));
+        fSeparableVaryingInfos[i].fLocation = location;
+    }
+}
+
+void GrGLNormalPathProcessor::setTransformData(
+        const GrPrimitiveProcessor& primProc,
+        int index,
+        const SkTArray<const GrCoordTransform*, true>& coordTransforms,
+        GrGLPathRendering* glpr,
+        GrGLuint programID) {
+    SkSTArray<2, Transform, true>& transforms = fInstalledTransforms[index];
+    int numTransforms = transforms.count();
+    for (int t = 0; t < numTransforms; ++t) {
+        SkASSERT(transforms[t].fHandle.isValid());
+        const SkMatrix& transform = GetTransformMatrix(primProc.localMatrix(),
+                                                       *coordTransforms[t]);
+        if (transforms[t].fCurrentValue.cheapEqualTo(transform)) {
+            continue;
+        }
+        transforms[t].fCurrentValue = transform;
+        const SeparableVaryingInfo& fragmentInput =
+                fSeparableVaryingInfos[transforms[t].fHandle.handle()];
+        SkASSERT(transforms[t].fType == kVec2f_GrSLType ||
+                 transforms[t].fType == kVec3f_GrSLType);
+        unsigned components = transforms[t].fType == kVec2f_GrSLType ? 2 : 3;
+        glpr->setProgramPathFragmentInputTransform(programID,
+                                                   fragmentInput.fLocation,
+                                                   GR_GL_OBJECT_LINEAR,
+                                                   components,
+                                                   transform);
+    }
+}
diff --git a/src/gpu/gl/GrGLPathProcessor.h b/src/gpu/gl/GrGLPathProcessor.h
new file mode 100644
index 0000000..368f1f9
--- /dev/null
+++ b/src/gpu/gl/GrGLPathProcessor.h
@@ -0,0 +1,113 @@
+/*
+ * 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 GrGLPathProcessor_DEFINED
+#define GrGLPathProcessor_DEFINED
+
+#include "GrGLPrimitiveProcessor.h"
+
+class GrPathProcessor;
+class GrGLPathRendering;
+class GrGLGpu;
+
+class GrGLPathProcessor : public GrGLPrimitiveProcessor {
+public:
+    GrGLPathProcessor(const GrPathProcessor&, const GrBatchTracker&);
+
+    static void GenKey(const GrPathProcessor&,
+                       const GrBatchTracker& bt,
+                       const GrGLCaps&,
+                       GrProcessorKeyBuilder* b);
+
+    void emitCode(EmitArgs&) SK_OVERRIDE;
+
+    virtual void emitTransforms(GrGLGPBuilder*, const TransformsIn&, TransformsOut*) = 0;
+
+    virtual void resolveSeparableVaryings(GrGLGpu* gpu, GrGLuint programId) {}
+
+    void setData(const GrGLProgramDataManager&,
+                 const GrPrimitiveProcessor&,
+                 const GrBatchTracker&) SK_OVERRIDE;
+
+    virtual void setTransformData(const GrPrimitiveProcessor&,
+                                  int index,
+                                  const SkTArray<const GrCoordTransform*, true>& transforms,
+                                  GrGLPathRendering*,
+                                  GrGLuint programID) = 0;
+
+    virtual void didSetData(GrGLPathRendering*) {}
+
+private:
+    UniformHandle fColorUniform;
+    GrColor fColor;
+
+    typedef GrGLPrimitiveProcessor INHERITED;
+};
+
+class GrGLLegacyPathProcessor : public GrGLPathProcessor {
+public:
+    GrGLLegacyPathProcessor(const GrPathProcessor& pathProc, const GrBatchTracker& bt,
+                            int maxTexCoords)
+        : INHERITED(pathProc, bt)
+        , fTexCoordSetCnt(0) {
+        SkDEBUGCODE(fMaxTexCoords = maxTexCoords;)
+    }
+
+    int addTexCoordSets(int count) {
+        int firstFreeCoordSet = fTexCoordSetCnt;
+        fTexCoordSetCnt += count;
+        SkASSERT(fMaxTexCoords >= fTexCoordSetCnt);
+        return firstFreeCoordSet;
+    }
+
+    void emitTransforms(GrGLGPBuilder*, const TransformsIn& tin, TransformsOut* tout) SK_OVERRIDE;
+
+    void setTransformData(const GrPrimitiveProcessor& primProc,
+                          int index,
+                          const SkTArray<const GrCoordTransform*, true>& transforms,
+                          GrGLPathRendering* glpr,
+                          GrGLuint) SK_OVERRIDE;
+
+    void didSetData(GrGLPathRendering* glpr) SK_OVERRIDE;
+
+private:
+    SkDEBUGCODE(int fMaxTexCoords;)
+    int fTexCoordSetCnt;
+
+    typedef GrGLPathProcessor INHERITED;
+};
+
+class GrGLNormalPathProcessor : public GrGLPathProcessor {
+public:
+    GrGLNormalPathProcessor(const GrPathProcessor& pathProc, const GrBatchTracker& bt)
+        : INHERITED(pathProc, bt) {}
+
+    void emitTransforms(GrGLGPBuilder* pb, const TransformsIn& tin,TransformsOut* tout) SK_OVERRIDE;
+
+    void resolveSeparableVaryings(GrGLGpu* gpu, GrGLuint programId);
+
+    void setTransformData(const GrPrimitiveProcessor& primProc,
+                          int index,
+                          const SkTArray<const GrCoordTransform*, true>& coordTransforms,
+                          GrGLPathRendering* glpr,
+                          GrGLuint programID) SK_OVERRIDE;
+
+private:
+    struct SeparableVaryingInfo {
+        GrSLType      fType;
+        GrGLShaderVar fVariable;
+        GrGLint       fLocation;
+    };
+
+    typedef SkSTArray<8, SeparableVaryingInfo, true> SeparableVaryingInfoArray;
+
+    SeparableVaryingInfoArray fSeparableVaryingInfos;
+
+    typedef GrGLPathProcessor INHERITED;
+};
+
+#endif
diff --git a/src/gpu/gl/GrGLPrimitiveProcessor.cpp b/src/gpu/gl/GrGLPrimitiveProcessor.cpp
new file mode 100644
index 0000000..335dc4f
--- /dev/null
+++ b/src/gpu/gl/GrGLPrimitiveProcessor.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrGLPrimitiveProcessor.h"
+
+#include "builders/GrGLProgramBuilder.h"
+
+SkMatrix GrGLPrimitiveProcessor::GetTransformMatrix(const SkMatrix& localMatrix,
+                                                    const GrCoordTransform& coordTransform) {
+    SkMatrix combined;
+    // We only apply the localmatrix to localcoords
+    if (kLocal_GrCoordSet == coordTransform.sourceCoords()) {
+        combined.setConcat(coordTransform.getMatrix(), localMatrix);
+    } else {
+        combined = coordTransform.getMatrix();
+    }
+    if (coordTransform.reverseY()) {
+        // combined.postScale(1,-1);
+        // combined.postTranslate(0,1);
+        combined.set(SkMatrix::kMSkewY,
+            combined[SkMatrix::kMPersp0] - combined[SkMatrix::kMSkewY]);
+        combined.set(SkMatrix::kMScaleY,
+            combined[SkMatrix::kMPersp1] - combined[SkMatrix::kMScaleY]);
+        combined.set(SkMatrix::kMTransY,
+            combined[SkMatrix::kMPersp2] - combined[SkMatrix::kMTransY]);
+    }
+    return combined;
+}
+
+void
+GrGLPrimitiveProcessor::setupColorPassThrough(GrGLGPBuilder* pb,
+                                              GrGPInput inputType,
+                                              const char* outputName,
+                                              const GrGeometryProcessor::Attribute* colorAttr,
+                                              UniformHandle* colorUniform) {
+    GrGLGPFragmentBuilder* fs = pb->getFragmentShaderBuilder();
+    if (kUniform_GrGPInput == inputType) {
+        SkASSERT(colorUniform);
+        const char* stagedLocalVarName;
+        *colorUniform = pb->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+                                       kVec4f_GrSLType,
+                                       kDefault_GrSLPrecision,
+                                       "Color",
+                                       &stagedLocalVarName);
+        fs->codeAppendf("%s = %s;", outputName, stagedLocalVarName);
+    } else if (kAttribute_GrGPInput == inputType) {
+        SkASSERT(colorAttr);
+        pb->addPassThroughAttribute(colorAttr, outputName);
+    } else if (kAllOnes_GrGPInput == inputType) {
+        fs->codeAppendf("%s = vec4(1);", outputName);
+    }
+}
+
+void GrGLPrimitiveProcessor::addUniformViewMatrix(GrGLGPBuilder* pb) {
+    fViewMatrixUniform = pb->addUniform(GrGLProgramBuilder::kVertex_Visibility,
+                                        kMat33f_GrSLType, kDefault_GrSLPrecision,
+                                        "uViewM",
+                                        &fViewMatrixName);
+}
+
+void GrGLPrimitiveProcessor::setUniformViewMatrix(const GrGLProgramDataManager& pdman,
+                                                  const SkMatrix& viewMatrix) {
+    if (!fViewMatrix.cheapEqualTo(viewMatrix)) {
+        SkASSERT(fViewMatrixUniform.isValid());
+        fViewMatrix = viewMatrix;
+
+        GrGLfloat viewMatrix[3 * 3];
+        GrGLGetMatrix<3>(viewMatrix, fViewMatrix);
+        pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
+    }
+}
diff --git a/src/gpu/gl/GrGLPrimitiveProcessor.h b/src/gpu/gl/GrGLPrimitiveProcessor.h
new file mode 100644
index 0000000..30b1c17
--- /dev/null
+++ b/src/gpu/gl/GrGLPrimitiveProcessor.h
@@ -0,0 +1,130 @@
+/*
+ * 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 GrGLPrimitiveProcessor_DEFINED
+#define GrGLPrimitiveProcessor_DEFINED
+
+#include "GrPrimitiveProcessor.h"
+#include "GrGLProcessor.h"
+
+class GrBatchTracker;
+class GrPrimitiveProcessor;
+class GrGLGPBuilder;
+
+class GrGLPrimitiveProcessor {
+public:
+    GrGLPrimitiveProcessor() : fViewMatrixName(NULL) { fViewMatrix = SkMatrix::InvalidMatrix(); }
+    virtual ~GrGLPrimitiveProcessor() {}
+
+    typedef GrGLProgramDataManager::UniformHandle UniformHandle;
+    typedef GrGLProcessor::TextureSamplerArray TextureSamplerArray;
+
+    typedef SkSTArray<2, const GrCoordTransform*, true> ProcCoords;
+    typedef SkSTArray<8, ProcCoords> TransformsIn;
+    typedef SkSTArray<8, GrGLProcessor::TransformedCoordsArray> TransformsOut;
+
+    struct EmitArgs {
+        EmitArgs(GrGLGPBuilder* pb,
+                 const GrPrimitiveProcessor& gp,
+                 const GrBatchTracker& bt,
+                 const char* outputColor,
+                 const char* outputCoverage,
+                 const TextureSamplerArray& samplers,
+                 const TransformsIn& transformsIn,
+                 TransformsOut* transformsOut)
+            : fPB(pb)
+            , fGP(gp)
+            , fBT(bt)
+            , fOutputColor(outputColor)
+            , fOutputCoverage(outputCoverage)
+            , fSamplers(samplers)
+            , fTransformsIn(transformsIn)
+            , fTransformsOut(transformsOut) {}
+        GrGLGPBuilder* fPB;
+        const GrPrimitiveProcessor& fGP;
+        const GrBatchTracker& fBT;
+        const char* fOutputColor;
+        const char* fOutputCoverage;
+        const TextureSamplerArray& fSamplers;
+        const TransformsIn& fTransformsIn;
+        TransformsOut* fTransformsOut;
+    };
+
+    /**
+     * This is similar to emitCode() in the base class, except it takes a full shader builder.
+     * This allows the effect subclass to emit vertex code.
+     */
+    virtual void emitCode(EmitArgs&) = 0;
+
+
+    /** A GrGLPrimitiveProcessor instance can be reused with any GrGLPrimitiveProcessor that
+        produces the same stage key; this function reads data from a GrGLPrimitiveProcessor and
+        uploads any uniform variables required  by the shaders created in emitCode(). The
+        GrPrimitiveProcessor parameter is guaranteed to be of the same type that created this
+        GrGLPrimitiveProcessor and to have an identical processor key as the one that created this
+        GrGLPrimitiveProcessor.  */
+    virtual void setData(const GrGLProgramDataManager&,
+                         const GrPrimitiveProcessor&,
+                         const GrBatchTracker&) = 0;
+
+    static SkMatrix GetTransformMatrix(const SkMatrix& localMatrix, const GrCoordTransform&);
+
+protected:
+    /** a helper which can setup vertex, constant, or uniform color depending on inputType.
+     *  This function will only do the minimum required to emit the correct shader code.  If
+     *  inputType == attribute, then colorAttr must not be NULL.  Likewise, if inputType == Uniform
+     *  then colorUniform must not be NULL.
+     */
+    void setupColorPassThrough(GrGLGPBuilder* pb,
+                               GrGPInput inputType,
+                               const char* inputName,
+                               const GrPrimitiveProcessor::Attribute* colorAttr,
+                               UniformHandle* colorUniform);
+
+    const char* uViewM() const { return fViewMatrixName; }
+
+    /** a helper function to setup the uniform handle for the uniform view matrix */
+    void addUniformViewMatrix(GrGLGPBuilder*);
+
+
+    /** a helper function to upload a uniform viewmatrix.
+     * TODO we can remove this function when we have deferred geometry in place
+     */
+    void setUniformViewMatrix(const GrGLProgramDataManager&,
+                              const SkMatrix& viewMatrix);
+
+    class ShaderVarHandle {
+    public:
+        bool isValid() const { return fHandle > -1; }
+        ShaderVarHandle() : fHandle(-1) {}
+        ShaderVarHandle(int value) : fHandle(value) { SkASSERT(this->isValid()); }
+        int handle() const { SkASSERT(this->isValid()); return fHandle; }
+        UniformHandle convertToUniformHandle() {
+            SkASSERT(this->isValid());
+            return GrGLProgramDataManager::UniformHandle::CreateFromUniformIndex(fHandle);
+        }
+
+    private:
+        int fHandle;
+    };
+
+    struct Transform {
+        Transform() : fType(kVoid_GrSLType) { fCurrentValue = SkMatrix::InvalidMatrix(); }
+        ShaderVarHandle fHandle;
+        SkMatrix       fCurrentValue;
+        GrSLType       fType;
+    };
+
+    SkSTArray<8, SkSTArray<2, Transform, true> > fInstalledTransforms;
+
+private:
+    UniformHandle fViewMatrixUniform;
+    SkMatrix fViewMatrix;
+    const char* fViewMatrixName;
+};
+
+#endif
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index eebcf6b..2f6b784 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -11,12 +11,12 @@
 #include "GrProcessor.h"
 #include "GrCoordTransform.h"
 #include "GrGLGeometryProcessor.h"
-#include "GrGLProcessor.h"
-#include "GrGLXferProcessor.h"
 #include "GrGLGpu.h"
+#include "GrGLPathProcessor.h"
 #include "GrGLPathRendering.h"
 #include "GrGLShaderVar.h"
 #include "GrGLSL.h"
+#include "GrGLXferProcessor.h"
 #include "GrPipeline.h"
 #include "GrXferProcessor.h"
 #include "SkXfermode.h"
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index bb278be..5a62303 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -6,11 +6,14 @@
  */
 
 #include "GrGLProgramBuilder.h"
+
+#include "gl/GrGLGeometryProcessor.h"
+#include "gl/GrGLGpu.h"
+#include "gl/GrGLPathProcessor.h"
 #include "gl/GrGLProgram.h"
 #include "gl/GrGLSLPrettyPrint.h"
 #include "gl/GrGLUniformHandle.h"
-#include "../GrGLXferProcessor.h"
-#include "../GrGLGpu.h"
+#include "gl/GrGLXferProcessor.h"
 #include "GrCoordTransform.h"
 #include "GrGLProgramBuilder.h"
 #include "GrTexture.h"
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h
index a9288cc..37908f9 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.h
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.h
@@ -13,7 +13,7 @@
 #include "GrGLVertexShaderBuilder.h"
 #include "../GrGLProgramDataManager.h"
 #include "../GrGLUniformHandle.h"
-#include "../GrGLGeometryProcessor.h"
+#include "../GrGLPrimitiveProcessor.h"
 #include "../GrGLXferProcessor.h"
 #include "../../GrPendingFragmentStage.h"
 #include "../../GrPipeline.h"