Revert of Remove GP from drawstate, revision of invariant output for GP (patchset #9 id:160001 of https://codereview.chromium.org/791743003/)

Reason for revert:
breaks mac

Original issue's description:
> Remove GP from drawstate, revision of invariant output for GP
>
> BUG=skia:
>
> Committed: https://skia.googlesource.com/skia/+/c6bc58eded89b0c0a36b8e20e193c200f297a0da

TBR=bsalomon@google.com,egdaniel@google.com,joshualitt@chromium.org
NOTREECHECKS=true
NOTRY=true
BUG=skia:

Review URL: https://codereview.chromium.org/794843002
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt
index bdce6d9..6c93e7a 100644
--- a/expectations/gm/ignored-tests.txt
+++ b/expectations/gm/ignored-tests.txt
@@ -72,8 +72,3 @@
 clipped-bitmap-shaders-clamp
 clipped-bitmap-shaders-clamp-hq
 
-# joshualitt
-path_primitive
-xfermodes3
-multipicturedraw_sierpinski_tiled
-multipicturedraw_sierpinski_simple
diff --git a/gm/beziereffects.cpp b/gm/beziereffects.cpp
index e7e63ea..6f19ac9 100644
--- a/gm/beziereffects.cpp
+++ b/gm/beziereffects.cpp
@@ -164,10 +164,11 @@
                         verts[v].fKLM[2] = eval_line(verts[v].fPosition, klmEqs + 6, 1.f);
                     }
 
+                    ds.setGeometryProcessor(gp);
                     ds.setRenderTarget(rt);
 
                     tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
-                    tt.target()->drawIndexed(&ds, gp, kTriangleFan_GrPrimitiveType, 0, 0,4,6);
+                    tt.target()->drawIndexed(&ds, kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
                 }
                 ++col;
                 if (numCols == col) {
@@ -319,10 +320,11 @@
                         verts[v].fKLM[2] = eval_line(verts[v].fPosition, klmEqs + 6, 1.f);
                     }
 
+                    ds.setGeometryProcessor(gp);
                     ds.setRenderTarget(rt);
 
                     tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
-                    tt.target()->drawIndexed(&ds, gp, kTriangleFan_GrPrimitiveType, 0, 0,4,6);
+                    tt.target()->drawIndexed(&ds, kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
                 }
                 ++col;
                 if (numCols == col) {
@@ -503,10 +505,11 @@
                     GrPathUtils::QuadUVMatrix DevToUV(pts);
                     DevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
 
+                    ds.setGeometryProcessor(gp);
                     ds.setRenderTarget(rt);
 
                     tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
-                    tt.target()->drawIndexed(&ds, gp, kTriangles_GrPrimitiveType, 0, 0, 4, 6);
+                    tt.target()->drawIndexed(&ds, kTriangles_GrPrimitiveType, 0, 0, 4, 6);
                 }
                 ++col;
                 if (numCols == col) {
diff --git a/gm/convexpolyeffect.cpp b/gm/convexpolyeffect.cpp
index 03b9ad2..365660d 100644
--- a/gm/convexpolyeffect.cpp
+++ b/gm/convexpolyeffect.cpp
@@ -133,8 +133,8 @@
                 }
 
                 GrDrawState ds;
-                SkAutoTUnref<const GrGeometryProcessor> gp(
-                        GrDefaultGeoProcFactory::Create(0xff000000));
+                const GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Create(0xff000000);
+                ds.setGeometryProcessor(gp)->unref();
                 ds.addCoverageProcessor(fp);
                 ds.setIdentityViewMatrix();
                 ds.setRenderTarget(rt);
@@ -150,7 +150,7 @@
                 bounds.toQuad(verts);
 
                 tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
-                tt.target()->drawIndexed(&ds, gp, kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
+                tt.target()->drawIndexed(&ds, kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
 
                 x += SkScalarCeilToScalar(path->getBounds().width() + 10.f);
             }
@@ -190,8 +190,8 @@
                 }
 
                 GrDrawState ds;
-                SkAutoTUnref<const GrGeometryProcessor> gp(
-                        GrDefaultGeoProcFactory::Create(0xff000000));
+                const GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Create(0xff000000);
+                ds.setGeometryProcessor(gp)->unref();
                 ds.addCoverageProcessor(fp);
                 ds.setIdentityViewMatrix();
                 ds.setRenderTarget(rt);
@@ -205,7 +205,7 @@
                 bounds.toQuad(verts);
 
                 tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
-                tt.target()->drawIndexed(&ds, gp, kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
+                tt.target()->drawIndexed(&ds, kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
 
                 x += SkScalarCeilToScalar(rect.width() + 10.f);
             }
diff --git a/include/gpu/GrFragmentProcessor.h b/include/gpu/GrFragmentProcessor.h
index 0c15599..3f308d7 100644
--- a/include/gpu/GrFragmentProcessor.h
+++ b/include/gpu/GrFragmentProcessor.h
@@ -67,16 +67,6 @@
         return this->onIsEqual(that);
     }
 
-    /**
-     * This function is used to perform optimizations. When called the invarientOuput param
-     * indicate whether the input components to this processor in the FS will have known values.
-     * In inout the validFlags member is a bitfield of GrColorComponentFlags. The isSingleComponent
-     * member indicates whether the input will be 1 or 4 bytes. The function updates the members of
-     * inout to indicate known values of its output. A component of the color member only has
-     * meaning if the corresponding bit in validFlags is set.
-     */
-    void computeInvariantOutput(GrInvariantOutput* inout) const;
-
 protected:
     /**
      * Fragment Processor subclasses call this from their constructor to register coordinate
@@ -111,11 +101,6 @@
      */
     void setWillNotUseInputColor() { fWillUseInputColor = false; }
 
-    /**
-     * Subclass implements this to support getConstantColorComponents(...).
-     */
-    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const = 0;
-
 private:
     /**
      * Subclass implements this to support isEqual(). It will only be called if it is known that
diff --git a/include/gpu/GrInvariantOutput.h b/include/gpu/GrInvariantOutput.h
index 269748a..1d3eda1 100644
--- a/include/gpu/GrInvariantOutput.h
+++ b/include/gpu/GrInvariantOutput.h
@@ -10,49 +10,6 @@
 
 #include "GrColor.h"
 
-struct GrInitInvariantOutput {
-    GrInitInvariantOutput()
-        : fValidFlags(0)
-        , fColor(0)
-        , fIsSingleComponent(false)
-        , fIsLCDCoverage(false) {}
-
-    void setKnownFourComponents(GrColor color) {
-        fColor = color;
-        fValidFlags = kRGBA_GrColorComponentFlags;
-        fIsSingleComponent = false;
-    }
-
-    void setUnknownFourComponents() {
-        fValidFlags = 0;
-        fIsSingleComponent = false;
-    }
-
-    void setUnknownOpaqueFourComponents() {
-        fColor = 0xff << GrColor_SHIFT_A;
-        fValidFlags = kA_GrColorComponentFlag;
-        fIsSingleComponent = false;
-    }
-
-    void setKnownSingleComponent(uint8_t alpha) {
-        fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
-        fValidFlags = kRGBA_GrColorComponentFlags;
-        fIsSingleComponent = true;
-    }
-
-    void setUnknownSingleComponent() {
-        fValidFlags = 0;
-        fIsSingleComponent = true;
-    }
-
-    void setUsingLCDCoverage() { fIsLCDCoverage = true; }
-
-    uint32_t fValidFlags;
-    GrColor fColor;
-    bool fIsSingleComponent;
-    bool fIsLCDCoverage; // Temorary data member until texture pixel configs are updated
-};
-
 class GrInvariantOutput {
 public:
     GrInvariantOutput(GrColor color, GrColorComponentFlags flags, bool isSingleComponent)
@@ -63,14 +20,6 @@
         , fWillUseInputColor(true)
         , fIsLCDCoverage(false) {}
 
-    GrInvariantOutput(const GrInitInvariantOutput& io)
-        : fColor(io.fColor)
-        , fValidFlags(io.fValidFlags)
-        , fIsSingleComponent(io.fIsSingleComponent)
-        , fNonMulStageFound(false)
-        , fWillUseInputColor(false)
-        , fIsLCDCoverage(io.fIsLCDCoverage) {}
-
     virtual ~GrInvariantOutput() {}
 
     enum ReadInput {
@@ -78,18 +27,18 @@
         kWillNot_ReadInput,
     };
 
-    void mulByUnknownOpaqueFourComponents() {
+    void mulByUnknownOpaqueColor() {
         if (this->isOpaque()) {
             fValidFlags = kA_GrColorComponentFlag;
             fIsSingleComponent = false;
         } else {
             // Since the current state is not opaque we no longer care if the color being
             // multiplied is opaque.
-            this->mulByUnknownFourComponents();
+            this->mulByUnknownColor(); 
         }
     }
 
-    void mulByUnknownFourComponents() {
+    void mulByUnknownColor() {
         if (this->hasZeroAlpha()) {
             this->internalSetToTransparentBlack();
         } else {
@@ -97,7 +46,7 @@
         }
     }
 
-    void mulByUnknownSingleComponent() {
+    void mulByUnknownAlpha() {
         if (this->hasZeroAlpha()) {
             this->internalSetToTransparentBlack();
         } else {
@@ -106,7 +55,7 @@
         }
     }
 
-    void mulByKnownSingleComponent(uint8_t alpha) {
+    void mulByKnownAlpha(uint8_t alpha) {
         if (this->hasZeroAlpha() || 0 == alpha) {
             this->internalSetToTransparentBlack();
         } else {
@@ -173,15 +122,6 @@
         fWillUseInputColor = true;
     }
 
-    void reset(const GrInitInvariantOutput& io) {
-        fColor = io.fColor;
-        fValidFlags = io.fValidFlags;
-        fIsSingleComponent = io.fIsSingleComponent;
-        fNonMulStageFound = false;
-        fWillUseInputColor = true;
-        fIsLCDCoverage = io.fIsLCDCoverage;
-    }
-
     void internalSetToTransparentBlack() {
         fValidFlags = kRGBA_GrColorComponentFlags;
         fColor = 0;
diff --git a/include/gpu/GrProcessor.h b/include/gpu/GrProcessor.h
index 8a8d685..6a497e7 100644
--- a/include/gpu/GrProcessor.h
+++ b/include/gpu/GrProcessor.h
@@ -61,6 +61,16 @@
 
     virtual ~GrProcessor();
 
+    /**
+     * This function is used to perform optimizations. When called the invarientOuput param
+     * indicate whether the input components to this processor in the FS will have known values.
+     * In inout the validFlags member is a bitfield of GrColorComponentFlags. The isSingleComponent
+     * member indicates whether the input will be 1 or 4 bytes. The function updates the members of
+     * inout to indicate known values of its output. A component of the color member only has
+     * meaning if the corresponding bit in validFlags is set.
+     */
+    void computeInvariantOutput(GrInvariantOutput* inout) const; 
+
     /** Human-meaningful string to identify this prcoessor; may be embedded
         in generated shader code. */
     virtual const char* name() const = 0;
@@ -122,6 +132,11 @@
     uint32_t fClassID;
 
 private:
+    /** 
+     * Subclass implements this to support getConstantColorComponents(...).
+     */
+    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const = 0;
+    
     static uint32_t GenClassID() {
         // fCurrProcessorClassID has been initialized to kIllegalProcessorClassID. The
         // atomic inc returns the old value not the incremented value. So we add
diff --git a/include/gpu/GrXferProcessor.h b/include/gpu/GrXferProcessor.h
index db0d6e8..696359b 100644
--- a/include/gpu/GrXferProcessor.h
+++ b/include/gpu/GrXferProcessor.h
@@ -134,11 +134,6 @@
      */
     void setWillReadDstColor() { fWillReadDstColor = true; }
 
-    /**
-     * Subclass implements this to support getConstantColorComponents(...).
-     */
-    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const = 0;
-
 private:
     virtual bool onIsEqual(const GrXferProcessor&) const = 0;
 
diff --git a/src/effects/SkAlphaThresholdFilter.cpp b/src/effects/SkAlphaThresholdFilter.cpp
index 317f6f0..2703a24 100644
--- a/src/effects/SkAlphaThresholdFilter.cpp
+++ b/src/effects/SkAlphaThresholdFilter.cpp
@@ -230,11 +230,11 @@
 
 void AlphaThresholdEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
     if (GrPixelConfigIsAlphaOnly(this->texture(0)->config())) {
-        inout->mulByUnknownSingleComponent();
+        inout->mulByUnknownAlpha();
     } else if (GrPixelConfigIsOpaque(this->texture(0)->config()) && fOuterThreshold >= 1.f) {
-        inout->mulByUnknownOpaqueFourComponents();
+        inout->mulByUnknownOpaqueColor();
     } else {
-        inout->mulByUnknownFourComponents();
+        inout->mulByUnknownColor();
     }
 }
 
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index 7c0bbb8..feb321a 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -817,7 +817,7 @@
 }
 
 void GrRectBlurEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
-    inout->mulByUnknownSingleComponent();
+    inout->mulByUnknownAlpha();
 }
 
 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRectBlurEffect);
@@ -979,7 +979,7 @@
 }
 
 void GrRRectBlurEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
-    inout->mulByUnknownSingleComponent();
+    inout->mulByUnknownAlpha();
 }
 
 GrRRectBlurEffect::GrRRectBlurEffect(float sigma, const SkRRect& rrect, GrTexture *ninePatchTexture)
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index e53cb02..adac45b 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -349,7 +349,7 @@
 
     virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE {
         // lighting shaders are complicated. We just throw up our hands.
-        inout->mulByUnknownFourComponents();
+        inout->mulByUnknownColor();
     }
 
 private:
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 3b73eae..0c14794 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -1158,9 +1158,9 @@
 
 void GrGradientEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
     if (fIsOpaque) {
-        inout->mulByUnknownOpaqueFourComponents();
+        inout->mulByUnknownOpaqueColor();
     } else {
-        inout->mulByUnknownFourComponents();
+        inout->mulByUnknownColor();
     }
 }
 
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index 0007e33..44782dd 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -596,8 +596,8 @@
         return true;
     }
 
-    virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
-        out->setUnknownSingleComponent();
+    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE {
+        inout->mulByUnknownAlpha();
     }
 
     const GrAttribute* fInPosition;
@@ -679,7 +679,8 @@
     // Our computed verts should all be within one pixel of the segment control points.
     devBounds.outset(SK_Scalar1, SK_Scalar1);
 
-    SkAutoTUnref<GrGeometryProcessor> quadProcessor(QuadEdgeEffect::Create(color));
+    GrGeometryProcessor* quadProcessor = QuadEdgeEffect::Create(color);
+    drawState->setGeometryProcessor(quadProcessor)->unref();
 
     GrDrawTarget::AutoReleaseGeometry arg(target, vCount, quadProcessor->getVertexStride(), iCount);
     SkASSERT(quadProcessor->getVertexStride() == sizeof(QuadVertex));
@@ -708,7 +709,6 @@
     for (int i = 0; i < draws.count(); ++i) {
         const Draw& draw = draws[i];
         target->drawIndexed(drawState,
-                            quadProcessor,
                             kTriangles_GrPrimitiveType,
                             vOffset,  // start vertex
                             0,        // start index
diff --git a/src/gpu/GrAADistanceFieldPathRenderer.cpp b/src/gpu/GrAADistanceFieldPathRenderer.cpp
index f79d96b..7a7c1e4 100755
--- a/src/gpu/GrAADistanceFieldPathRenderer.cpp
+++ b/src/gpu/GrAADistanceFieldPathRenderer.cpp
@@ -323,13 +323,14 @@
     flags |= vm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
 
     GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
-    if (flags != fEffectFlags || fCachedGeometryProcessor->color() != color) {
+    if (flags != fEffectFlags || fCachedGeometryProcessor->getColor() != color) {
         fCachedGeometryProcessor.reset(GrDistanceFieldNoGammaTextureEffect::Create(color,
                                                                                    texture,
                                                                                    params,
                                                                                    flags));
         fEffectFlags = flags;
     }
+    drawState->setGeometryProcessor(fCachedGeometryProcessor.get());
 
     void* vertices = NULL;
     bool success = target->reserveVertexAndIndexSpace(4,
@@ -371,8 +372,7 @@
     
     vm.mapRect(&r);
     target->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
-    target->drawIndexedInstances(drawState, fCachedGeometryProcessor.get(),
-                                 kTriangles_GrPrimitiveType, 1, 4, 6, &r);
+    target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 4, 6, &r);
     target->resetVertexSource();
     
     return true;
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
index a95f900..37150bd 100644
--- a/src/gpu/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp
@@ -644,7 +644,6 @@
 bool GrAAHairLinePathRenderer::createLineGeom(GrDrawTarget* target,
                                               GrDrawState* drawState,
                                               uint8_t coverage,
-                                              size_t vertexStride,
                                               GrDrawTarget::AutoReleaseGeometry* arg,
                                               SkRect* devBounds,
                                               const SkPath& path,
@@ -654,8 +653,9 @@
 
     int vertCnt = kLineSegNumVertices * lineCnt;
 
-    SkASSERT(vertexStride == sizeof(LineVertex));
-    if (!arg->set(target, vertCnt, vertexStride,  0)) {
+    size_t vstride = drawState->getGeometryProcessor()->getVertexStride();
+    SkASSERT(vstride == sizeof(LineVertex));
+    if (!arg->set(target, vertCnt, vstride,  0)) {
         return false;
     }
 
@@ -839,14 +839,13 @@
         uint32_t gpFlags = GrDefaultGeoProcFactory::kPosition_GPType |
                            GrDefaultGeoProcFactory::kCoverage_GPType;
         GrDrawState::AutoRestoreEffects are(drawState);
-        SkAutoTUnref<const GrGeometryProcessor> gp(GrDefaultGeoProcFactory::Create(color,
-                                                                                   gpFlags,
-                                                                                   newCoverage));
+        drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(color,
+                                                                        gpFlags,
+                                                                        newCoverage))->unref();
 
         if (!this->createLineGeom(target,
                                   drawState,
                                   newCoverage,
-                                  gp->getVertexStride(),
                                   &arg,
                                   &devBounds,
                                   path,
@@ -872,7 +871,6 @@
             while (lines < lineCnt) {
                 int n = SkTMin(lineCnt - lines, kLineSegsNumInIdxBuffer);
                 target->drawIndexed(drawState,
-                                    gp,
                                     kTriangles_GrPrimitiveType,
                                     kLineSegNumVertices*lines,     // startV
                                     0,                             // startI
@@ -917,20 +915,20 @@
                                             kQuadNumVertices * quadCnt + kQuadNumVertices * conicCnt));
 
         if (quadCnt > 0) {
-            SkAutoTUnref<GrGeometryProcessor> hairQuadProcessor(
+            GrGeometryProcessor* hairQuadProcessor =
                     GrQuadEffect::Create(color,
                                          kHairlineAA_GrProcessorEdgeType,
                                          *target->caps(),
-                                         newCoverage));
+                                         newCoverage);
             SkASSERT(hairQuadProcessor);
             GrDrawState::AutoRestoreEffects are(drawState);
             target->setIndexSourceToBuffer(fQuadsIndexBuffer);
 
+            drawState->setGeometryProcessor(hairQuadProcessor)->unref();
             int quads = 0;
             while (quads < quadCnt) {
                 int n = SkTMin(quadCnt - quads, kQuadsNumInIdxBuffer);
                 target->drawIndexed(drawState,
-                                    hairQuadProcessor,
                                     kTriangles_GrPrimitiveType,
                                     kQuadNumVertices*quads,               // startV
                                     0,                                    // startI
@@ -943,16 +941,15 @@
 
         if (conicCnt > 0) {
             GrDrawState::AutoRestoreEffects are(drawState);
-            SkAutoTUnref<GrGeometryProcessor> hairConicProcessor(
-                    GrConicEffect::Create(color, kHairlineAA_GrProcessorEdgeType, *target->caps(),
-                                          newCoverage));
+            GrGeometryProcessor* hairConicProcessor = GrConicEffect::Create(
+                    color, kHairlineAA_GrProcessorEdgeType, *target->caps(), newCoverage);
             SkASSERT(hairConicProcessor);
 
+            drawState->setGeometryProcessor(hairConicProcessor)->unref();
             int conics = 0;
             while (conics < conicCnt) {
                 int n = SkTMin(conicCnt - conics, kQuadsNumInIdxBuffer);
                 target->drawIndexed(drawState,
-                                    hairConicProcessor,
                                     kTriangles_GrPrimitiveType,
                                     kQuadNumVertices*(quadCnt + conics),  // startV
                                     0,                                    // startI
diff --git a/src/gpu/GrAAHairLinePathRenderer.h b/src/gpu/GrAAHairLinePathRenderer.h
index 5b7b785..5d00e7e 100644
--- a/src/gpu/GrAAHairLinePathRenderer.h
+++ b/src/gpu/GrAAHairLinePathRenderer.h
@@ -43,7 +43,6 @@
     bool createLineGeom(GrDrawTarget* target,
                         GrDrawState*,
                         uint8_t coverage,
-                        size_t vertexStride,
                         GrDrawTarget::AutoReleaseGeometry* arg,
                         SkRect* devBounds,
                         const SkPath& path,
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp
index 23757ce..0cf7575 100644
--- a/src/gpu/GrAARectRenderer.cpp
+++ b/src/gpu/GrAARectRenderer.cpp
@@ -25,21 +25,20 @@
 };
 }
 
-static const GrGeometryProcessor* create_rect_gp(const GrDrawState& drawState, GrColor color,
-                                                 CoverageAttribType* type) {
+static CoverageAttribType set_rect_attribs(GrDrawState* drawState, GrColor color) {
     uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType;
-    const GrGeometryProcessor* gp;
-    if (drawState.canTweakAlphaForCoverage()) {
-        gp = GrDefaultGeoProcFactory::Create(color, flags);
-        SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
-        *type = kUseColor_CoverageAttribType;
+    if (drawState->canTweakAlphaForCoverage()) {
+        drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(color, flags))->unref();
+        SkASSERT(drawState->getGeometryProcessor()->getVertexStride() ==
+                 sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
+        return kUseColor_CoverageAttribType;
     } else {
         flags |= GrDefaultGeoProcFactory::kCoverage_GPType;
-        gp = GrDefaultGeoProcFactory::Create(color, flags);
-        SkASSERT(gp->getVertexStride()==sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
-        *type = kUseCoverage_CoverageAttribType;
+        drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(color, flags))->unref();
+        SkASSERT(drawState->getGeometryProcessor()->getVertexStride() ==
+                 sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
+        return kUseCoverage_CoverageAttribType;
     }
-    return gp;
 }
 
 static void set_inset_fan(SkPoint* pts, size_t stride,
@@ -183,14 +182,13 @@
                                           const SkRect& devRect) {
     GrDrawState::AutoRestoreEffects are(drawState);
 
-    CoverageAttribType type;
-    SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*drawState, color, &type));
-    if (kUseCoverage_CoverageAttribType == type && GrColorIsOpaque(color)) {
+    CoverageAttribType covAttribType = set_rect_attribs(drawState, color);
+    if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
         drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
     }
 
-    size_t vertexStride = gp->getVertexStride();
-    GrDrawTarget::AutoReleaseGeometry geo(target, 8, vertexStride, 0);
+    size_t vstride = drawState->getGeometryProcessor()->getVertexStride();
+    GrDrawTarget::AutoReleaseGeometry geo(target, 8, vstride, 0);
     if (!geo.succeeded()) {
         SkDebugf("Failed to get space for vertices!\n");
         return;
@@ -211,7 +209,7 @@
     intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
 
     SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
-    SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
+    SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
 
     SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
     inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
@@ -225,8 +223,8 @@
         combinedMatrix.mapRect(&devRect, rect);
 #endif
 
-        set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
-        set_inset_fan(fan1Pos, vertexStride, devRect, inset,  inset);
+        set_inset_fan(fan0Pos, vstride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
+        set_inset_fan(fan1Pos, vstride, devRect, inset,  inset);
     } else {
         // compute transformed (1, 0) and (0, 1) vectors
         SkVector vec[2] = {
@@ -241,38 +239,38 @@
 
         // create the rotated rect
         fan0Pos->setRectFan(rect.fLeft, rect.fTop,
-                            rect.fRight, rect.fBottom, vertexStride);
-        combinedMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4);
+                            rect.fRight, rect.fBottom, vstride);
+        combinedMatrix.mapPointsWithStride(fan0Pos, vstride, 4);
 
         // Now create the inset points and then outset the original
         // rotated points
 
         // TL
-        *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) =
-            *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1];
-        *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1];
+        *((SkPoint*)((intptr_t)fan1Pos + 0 * vstride)) =
+            *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) + vec[0] + vec[1];
+        *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) -= vec[0] + vec[1];
         // BL
-        *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) =
-            *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1];
-        *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1];
+        *((SkPoint*)((intptr_t)fan1Pos + 1 * vstride)) =
+            *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) + vec[0] - vec[1];
+        *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) -= vec[0] - vec[1];
         // BR
-        *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) =
-            *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1];
-        *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1];
+        *((SkPoint*)((intptr_t)fan1Pos + 2 * vstride)) =
+            *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) - vec[0] - vec[1];
+        *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) += vec[0] + vec[1];
         // TR
-        *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) =
-            *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1];
-        *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1];
+        *((SkPoint*)((intptr_t)fan1Pos + 3 * vstride)) =
+            *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) - vec[0] + vec[1];
+        *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) += vec[0] - vec[1];
     }
 
     // Make verts point to vertex color and then set all the color and coverage vertex attrs values.
     verts += sizeof(SkPoint);
     for (int i = 0; i < 4; ++i) {
-        if (kUseCoverage_CoverageAttribType == type) {
-            *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
-            *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
+        if (kUseCoverage_CoverageAttribType == covAttribType) {
+            *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
+            *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
         } else {
-            *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
+            *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
         }
     }
 
@@ -284,23 +282,22 @@
         scale = 0xff;
     }
 
-    verts += 4 * vertexStride;
+    verts += 4 * vstride;
 
     float innerCoverage = GrNormalizeByteToFloat(scale);
     GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
 
     for (int i = 0; i < 4; ++i) {
-        if (kUseCoverage_CoverageAttribType == type) {
-            *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
-            *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = innerCoverage;
+        if (kUseCoverage_CoverageAttribType == covAttribType) {
+            *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
+            *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
         } else {
-            *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
+            *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor; 
         }
     }
 
     target->setIndexSourceToBuffer(indexBuffer);
     target->drawIndexedInstances(drawState,
-                                 gp,
                                  kTriangles_GrPrimitiveType,
                                  1,
                                  kVertsPerAAFillRect,
@@ -386,11 +383,9 @@
                                             const SkRect& devInside,
                                             bool miterStroke) {
     GrDrawState::AutoRestoreEffects are(drawState);
+    CoverageAttribType covAttribType = set_rect_attribs(drawState, color);
 
-    CoverageAttribType type;
-    SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*drawState, color, &type));
-
-    if (kUseCoverage_CoverageAttribType == type && GrColorIsOpaque(color)) {
+    if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
         drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
     }
 
@@ -398,7 +393,7 @@
     int outerVertexNum = miterStroke ? 4 : 8;
     int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
 
-    size_t vstride = gp->getVertexStride();
+    size_t vstride = drawState->getGeometryProcessor()->getVertexStride();
     GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, vstride, 0);
     if (!geo.succeeded()) {
         SkDebugf("Failed to get space for vertices!\n");
@@ -463,7 +458,7 @@
     // The outermost rect has 0 coverage
     verts += sizeof(SkPoint);
     for (int i = 0; i < outerVertexNum; ++i) {
-        if (kUseCoverage_CoverageAttribType == type) {
+        if (kUseCoverage_CoverageAttribType == covAttribType) {
             *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
             *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
         } else {
@@ -485,7 +480,7 @@
 
     verts += outerVertexNum * vstride;
     for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
-        if (kUseCoverage_CoverageAttribType == type) {
+        if (kUseCoverage_CoverageAttribType == covAttribType) {
             *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
             *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
         } else {
@@ -496,7 +491,7 @@
     // The innermost rect has 0 coverage
     verts += (outerVertexNum + innerVertexNum) * vstride;
     for (int i = 0; i < innerVertexNum; ++i) {
-        if (kUseCoverage_CoverageAttribType == type) {
+        if (kUseCoverage_CoverageAttribType == covAttribType) {
             *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
             *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
         } else {
@@ -506,7 +501,6 @@
 
     target->setIndexSourceToBuffer(indexBuffer);
     target->drawIndexedInstances(drawState,
-                                 gp,
                                  kTriangles_GrPrimitiveType,
                                  1,
                                  totalVertexNum,
diff --git a/src/gpu/GrBitmapTextContext.cpp b/src/gpu/GrBitmapTextContext.cpp
index 7ee5585..6a624ae 100755
--- a/src/gpu/GrBitmapTextContext.cpp
+++ b/src/gpu/GrBitmapTextContext.cpp
@@ -561,18 +561,19 @@
         if (kARGB_GrMaskFormat == fCurrMaskFormat) {
             uint32_t textureUniqueID = fCurrTexture->getUniqueID();
             if (textureUniqueID != fEffectTextureUniqueID ||
-                fCachedGeometryProcessor->color() != color) {
+                fCachedGeometryProcessor->getColor() != color) {
                 uint32_t flags = GrDefaultGeoProcFactory::kLocalCoord_GPType;
                 fCachedGeometryProcessor.reset(GrDefaultGeoProcFactory::Create(color, flags));
                 fCachedTextureProcessor.reset(GrSimpleTextureEffect::Create(fCurrTexture,
                                                                             SkMatrix::I(),
                                                                             params));
             }
+            drawState.setGeometryProcessor(fCachedGeometryProcessor.get());
             drawState.addColorProcessor(fCachedTextureProcessor.get());
         } else {
             uint32_t textureUniqueID = fCurrTexture->getUniqueID();
             if (textureUniqueID != fEffectTextureUniqueID ||
-                fCachedGeometryProcessor->color() != color) {
+                fCachedGeometryProcessor->getColor() != color) {
                 bool hasColor = kA8_GrMaskFormat == fCurrMaskFormat;
                 fCachedGeometryProcessor.reset(GrBitmapTextGeoProc::Create(color,
                                                                                    fCurrTexture,
@@ -580,12 +581,12 @@
                                                                                    hasColor));
                 fEffectTextureUniqueID = textureUniqueID;
             }
+            drawState.setGeometryProcessor(fCachedGeometryProcessor.get());
         }
 
         int nGlyphs = fCurrVertex / kVerticesPerGlyph;
         fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
         fDrawTarget->drawIndexedInstances(&drawState,
-                                          fCachedGeometryProcessor.get(),
                                           kTriangles_GrPrimitiveType,
                                           nGlyphs,
                                           kVerticesPerGlyph,
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index bfbce35..9d07fdf 100755
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -315,8 +315,8 @@
 
         uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType |
                          GrDefaultGeoProcFactory::kLocalCoord_GPType;
-        SkAutoTUnref<const GrGeometryProcessor> gp(
-                GrDefaultGeoProcFactory::Create(GrColor_WHITE, flags));
+        const GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Create(GrColor_WHITE, flags);
+        drawState.setGeometryProcessor(gp)->unref();
 
         GrDrawTarget::AutoReleaseGeometry arg(fDrawBuffer, 4, gp->getVertexStride(),  0);
         SkASSERT(gp->getVertexStride() == 2 * sizeof(SkPoint));
@@ -325,7 +325,7 @@
             SkPoint* verts = (SkPoint*) arg.vertices();
             verts[0].setIRectFan(0, 0, texture->width(), texture->height(), 2 * sizeof(SkPoint));
             verts[1].setIRectFan(0, 0, 1, 1, 2 * sizeof(SkPoint));
-            fDrawBuffer->drawNonIndexed(&drawState, gp, kTriangleFan_GrPrimitiveType, 0, 4);
+            fDrawBuffer->drawNonIndexed(&drawState, kTriangleFan_GrPrimitiveType, 0, 4);
         }
     } else {
         // TODO: Our CPU stretch doesn't filter. But we create separate
@@ -758,7 +758,8 @@
         // unitSquareVertexBuffer()
 
         static const int worstCaseVertCount = 10;
-        SkAutoTUnref<const GrGeometryProcessor> gp(GrDefaultGeoProcFactory::Create(color));
+        const GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Create(color);
+        drawState.setGeometryProcessor(gp)->unref();
         GrDrawTarget::AutoReleaseGeometry geo(target,
                                               worstCaseVertCount,
                                               gp->getVertexStride(),
@@ -789,7 +790,7 @@
             vertex[4].set(rect.fLeft, rect.fTop);
         }
 
-        target->drawNonIndexed(&drawState, gp, primType, 0, vertCount);
+        target->drawNonIndexed(&drawState, primType, 0, vertCount);
     } else {
         // filled BW rect
         target->drawSimpleRect(&drawState, color, rect);
@@ -812,11 +813,12 @@
     target->drawRect(&drawState, paint.getColor(), dstRect, &localRect, localMatrix);
 }
 
-static const GrGeometryProcessor* set_vertex_attributes(const SkPoint* texCoords,
-                                                        const GrColor* colors,
-                                                        int* colorOffset,
-                                                        int* texOffset,
-                                                        GrColor color) {
+static void set_vertex_attributes(GrDrawState* drawState,
+                                  const SkPoint* texCoords,
+                                  const GrColor* colors,
+                                  int* colorOffset,
+                                  int* texOffset,
+                                  GrColor color) {
     *texOffset = -1;
     *colorOffset = -1;
 
@@ -833,7 +835,7 @@
         *colorOffset = sizeof(SkPoint);
         flags |= GrDefaultGeoProcFactory::kColor_GPType;
     }
-    return GrDefaultGeoProcFactory::Create(color, flags);
+    drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(color, flags))->unref();
 }
 
 void GrContext::drawVertices(const GrPaint& paint,
@@ -856,10 +858,10 @@
     GR_CREATE_TRACE_MARKER("GrContext::drawVertices", target);
 
     int colorOffset = -1, texOffset = -1;
-    SkAutoTUnref<const GrGeometryProcessor> gp(
-            set_vertex_attributes(texCoords, colors, &colorOffset, &texOffset, paint.getColor()));
+    set_vertex_attributes(&drawState, texCoords, colors, &colorOffset, &texOffset,
+                          paint.getColor());
 
-    size_t vertexStride = gp->getVertexStride();
+    size_t vertexStride = drawState.getGeometryProcessor()->getVertexStride();
     SkASSERT(vertexStride == sizeof(SkPoint) + (SkToBool(texCoords) ? sizeof(SkPoint) : 0)
                                              + (SkToBool(colors) ? sizeof(GrColor) : 0));
     if (!geo.set(target, vertexCount, vertexStride, indexCount)) {
@@ -887,9 +889,9 @@
         for (int i = 0; i < indexCount; ++i) {
             curIndex[i] = indices[i];
         }
-        target->drawIndexed(&drawState, gp, primitiveType, 0, 0, vertexCount, indexCount);
+        target->drawIndexed(&drawState, primitiveType, 0, 0, vertexCount, indexCount);
     } else {
-        target->drawNonIndexed(&drawState, gp, primitiveType, 0, vertexCount);
+        target->drawNonIndexed(&drawState, primitiveType, 0, vertexCount);
     }
 }
 
diff --git a/src/gpu/GrDefaultGeoProcFactory.cpp b/src/gpu/GrDefaultGeoProcFactory.cpp
index a798ee8..dca6c1c 100644
--- a/src/gpu/GrDefaultGeoProcFactory.cpp
+++ b/src/gpu/GrDefaultGeoProcFactory.cpp
@@ -128,12 +128,11 @@
         return gp.fFlags == this->fFlags;
     }
 
-    virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
+    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE {
         if (fInCoverage) {
-            out->setUnknownSingleComponent();
+            inout->mulByUnknownAlpha();
         } else {
-            // uniform coverage
-            out->setKnownSingleComponent(this->coverage());
+            inout->mulByKnownAlpha(255);
         }
     }
 
diff --git a/src/gpu/GrDefaultPathRenderer.cpp b/src/gpu/GrDefaultPathRenderer.cpp
index 07f9208..24d3c45 100644
--- a/src/gpu/GrDefaultPathRenderer.cpp
+++ b/src/gpu/GrDefaultPathRenderer.cpp
@@ -498,13 +498,12 @@
                 drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
             }
             GrDrawState::AutoRestoreEffects are(drawState);
-            SkAutoTUnref<const GrGeometryProcessor> gp(
+            drawState->setGeometryProcessor(
                     GrDefaultGeoProcFactory::Create(color,
                                                     GrDefaultGeoProcFactory::kPosition_GPType,
-                                                    newCoverage));
+                                                    newCoverage))->unref();
             if (indexCnt) {
                 target->drawIndexed(drawState,
-                                    gp,
                                     primType,
                                     0,
                                     0,
@@ -512,7 +511,7 @@
                                     indexCnt,
                                     &devBounds);
             } else {
-                target->drawNonIndexed(drawState, gp, primType, 0, vertexCnt, &devBounds);
+                target->drawNonIndexed(drawState, primType, 0, vertexCnt, &devBounds);
             }
         }
     }
diff --git a/src/gpu/GrDistanceFieldTextContext.cpp b/src/gpu/GrDistanceFieldTextContext.cpp
index ea72c29..d35ba23 100755
--- a/src/gpu/GrDistanceFieldTextContext.cpp
+++ b/src/gpu/GrDistanceFieldTextContext.cpp
@@ -637,6 +637,9 @@
         }
         this->setupCoverageEffect(filteredColor);
 
+        // Effects could be stored with one of the cache objects (atlas?)
+        drawState.setGeometryProcessor(fCachedGeometryProcessor.get());
+
         // Set draw state
         if (fUseLCDText) {
             // TODO: move supportsRGBCoverage check to setupCoverageEffect and only add LCD
@@ -645,18 +648,17 @@
             if (!drawState.getXPFactory()->supportsRGBCoverage(0, kRGBA_GrColorComponentFlags)) {
                 SkDebugf("LCD Text will not draw correctly.\n");
             }
-            SkASSERT(!fCachedGeometryProcessor->hasVertexColor());
+            SkASSERT(!drawState.hasColorVertexAttribute());
         } else {
             if (0xFF == GrColorUnpackA(fPaint.getColor())) {
                 drawState.setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
             }
             // We're using per-vertex color.
-            SkASSERT(fCachedGeometryProcessor->hasVertexColor());
+            SkASSERT(drawState.hasColorVertexAttribute());
         }
         int nGlyphs = fCurrVertex / kVerticesPerGlyph;
         fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
         fDrawTarget->drawIndexedInstances(&drawState,
-                                          fCachedGeometryProcessor.get(),
                                           kTriangles_GrPrimitiveType,
                                           nGlyphs,
                                           kVerticesPerGlyph,
diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp
index 72ec7a3..465c10c 100644
--- a/src/gpu/GrDrawState.cpp
+++ b/src/gpu/GrDrawState.cpp
@@ -14,7 +14,7 @@
 #include "GrXferProcessor.h"
 #include "effects/GrPorterDuffXferProcessor.h"
 
-bool GrDrawState::isEqual(const GrDrawState& that, bool explicitLocalCoords) const {
+bool GrDrawState::isEqual(const GrDrawState& that) const {
     if (this->getRenderTarget() != that.getRenderTarget() ||
         this->fColorStages.count() != that.fColorStages.count() ||
         this->fCoverageStages.count() != that.fCoverageStages.count() ||
@@ -25,6 +25,17 @@
         return false;
     }
 
+    bool explicitLocalCoords = this->hasLocalCoordAttribute();
+    if (this->hasGeometryProcessor()) {
+        if (!that.hasGeometryProcessor()) {
+            return false;
+        } else if (!this->getGeometryProcessor()->isEqual(*that.getGeometryProcessor())) {
+            return false;
+        }
+    } else if (that.hasGeometryProcessor()) {
+        return false;
+    }
+
     if (!this->getXPFactory()->isEqual(*that.getXPFactory())) {
         return false;
     }
@@ -66,6 +77,7 @@
     fFlagBits = that.fFlagBits;
     fStencilSettings = that.fStencilSettings;
     fDrawFace = that.fDrawFace;
+    fGeometryProcessor.reset(SkSafeRef(that.fGeometryProcessor.get()));
     fXPFactory.reset(SkRef(that.getXPFactory()));
     fColorStages = that.fColorStages;
     fCoverageStages = that.fCoverageStages;
@@ -84,9 +96,10 @@
 }
 
 void GrDrawState::onReset(const SkMatrix* initialViewMatrix) {
-    SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numFragmentStages());
+    SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
     fRenderTarget.reset(NULL);
 
+    fGeometryProcessor.reset(NULL);
     fXPFactory.reset(GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode));
     fColorStages.reset();
     fCoverageStages.reset();
@@ -107,10 +120,6 @@
 
     fColorCache = GrColor_ILLEGAL;
     fCoverageCache = GrColor_ILLEGAL;
-
-    fColorPrimProc = NULL;
-    fCoveragePrimProc = NULL;
-
 }
 
 bool GrDrawState::setIdentityViewMatrix()  {
@@ -132,8 +141,9 @@
 }
 
 void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRenderTarget* rt) {
-    SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numFragmentStages());
+    SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
 
+    fGeometryProcessor.reset(NULL);
     fColorStages.reset();
     fCoverageStages.reset();
 
@@ -187,7 +197,7 @@
                                         this->isCoverageDrawing(), this->isColorWriteDisabled());
 }
 
-bool GrDrawState::hasSolidCoverage(const GrPrimitiveProcessor* pp) const {
+bool GrDrawState::hasSolidCoverage(GrColor coverage) const {
     // If we're drawing coverage directly then coverage is effectively treated as color.
     if (this->isCoverageDrawing()) {
         return true;
@@ -197,15 +207,15 @@
         return false;
     }
 
-    this->calcCoverageInvariantOutput(pp);
+    this->calcCoverageInvariantOutput(coverage);
     return fCoverageProcInfo.isSolidWhite();
 }
 
 //////////////////////////////////////////////////////////////////////////////s
 
-bool GrDrawState::willEffectReadDstColor(const GrPrimitiveProcessor* pp) const {
-    this->calcColorInvariantOutput(pp);
-    this->calcCoverageInvariantOutput(pp);
+bool GrDrawState::willEffectReadDstColor(GrColor color, GrColor coverage) const {
+    this->calcColorInvariantOutput(color);
+    this->calcCoverageInvariantOutput(coverage);
     // TODO: Remove need to create the XP here.
     //       Also once all custom blends are turned into XPs we can remove the need
     //       to check other stages since only xp's will be able to read dst
@@ -225,6 +235,15 @@
 
 void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) {
     if (fDrawState) {
+        // See the big comment on the class definition about GPs.
+        if (SK_InvalidUniqueID == fOriginalGPID) {
+            fDrawState->fGeometryProcessor.reset(NULL);
+        } else {
+            SkASSERT(fDrawState->getGeometryProcessor()->getUniqueID() ==
+                     fOriginalGPID);
+            fOriginalGPID = SK_InvalidUniqueID;
+        }
+
         int m = fDrawState->numColorStages() - fColorEffectCnt;
         SkASSERT(m >= 0);
         fDrawState->fColorStages.pop_back_n(m);
@@ -240,6 +259,10 @@
     }
     fDrawState = ds;
     if (NULL != ds) {
+        SkASSERT(SK_InvalidUniqueID == fOriginalGPID);
+        if (NULL != ds->getGeometryProcessor()) {
+            fOriginalGPID = ds->getGeometryProcessor()->getUniqueID();
+        }
         fColorEffectCnt = ds->numColorStages();
         fCoverageEffectCnt = ds->numCoverageStages();
         SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;)
@@ -349,35 +372,38 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool GrDrawState::willBlendWithDst(const GrPrimitiveProcessor* pp) const {
-    this->calcColorInvariantOutput(pp);
-    this->calcCoverageInvariantOutput(pp);
+bool GrDrawState::srcAlphaWillBeOne(GrColor color, GrColor coverage) const {
+    this->calcColorInvariantOutput(color);
+    if (this->isCoverageDrawing()) {
+        this->calcCoverageInvariantOutput(coverage);
+        return (fColorProcInfo.isOpaque() && fCoverageProcInfo.isOpaque());
+    }
+    return fColorProcInfo.isOpaque();
+}
+
+bool GrDrawState::willBlendWithDst(GrColor color, GrColor coverage) const {
+    this->calcColorInvariantOutput(color);
+    this->calcCoverageInvariantOutput(coverage);
     return fXPFactory->willBlendWithDst(fColorProcInfo, fCoverageProcInfo,
                                         this->isCoverageDrawing(), this->isColorWriteDisabled());
 }
 
-void GrDrawState::calcColorInvariantOutput(const GrPrimitiveProcessor* pp) const {
-    if (!fColorProcInfoValid || fColorPrimProc != pp) {
-        fColorProcInfo.calcColorWithPrimProc(pp, fColorStages.begin(), this->numColorStages());
-        fColorProcInfoValid = true;
-        fColorPrimProc = pp;
-    }
-}
-
-void GrDrawState::calcCoverageInvariantOutput(const GrPrimitiveProcessor* pp) const {
-    if (!fCoverageProcInfoValid ||  fCoveragePrimProc != pp) {
-        fCoverageProcInfo.calcCoverageWithPrimProc(pp, fCoverageStages.begin(),
-                                                   this->numCoverageStages());
-        fCoverageProcInfoValid = true;
-        fCoveragePrimProc = pp;
-    }
-}
-
 void GrDrawState::calcColorInvariantOutput(GrColor color) const {
     if (!fColorProcInfoValid || color != fColorCache) {
-        GrColorComponentFlags flags = kRGBA_GrColorComponentFlags;
-        fColorProcInfo.calcWithInitialValues(fColorStages.begin(), this->numColorStages(), color,
-                                             flags, false);
+        GrColorComponentFlags flags;
+        if (this->hasColorVertexAttribute()) {
+            if (fHints & kVertexColorsAreOpaque_Hint) {
+                flags = kA_GrColorComponentFlag;
+                color = 0xFF << GrColor_SHIFT_A;
+            } else {
+                flags = static_cast<GrColorComponentFlags>(0);
+                color = 0;
+            }
+        } else {
+            flags = kRGBA_GrColorComponentFlags;
+        }
+        fColorProcInfo.calcWithInitialValues(fColorStages.begin(), this->numColorStages(),
+                                             color, flags, false);
         fColorProcInfoValid = true;
         fColorCache = color;
     }
@@ -385,10 +411,16 @@
 
 void GrDrawState::calcCoverageInvariantOutput(GrColor coverage) const {
     if (!fCoverageProcInfoValid || coverage != fCoverageCache) {
-            GrColorComponentFlags flags = kRGBA_GrColorComponentFlags;
-            fCoverageProcInfo.calcWithInitialValues(fCoverageStages.begin(),
-                                                    this->numCoverageStages(), coverage, flags,
-                                                    true);
+        GrColorComponentFlags flags;
+        // Check if per-vertex or constant color may have partial alpha
+        if (this->hasCoverageVertexAttribute()) {
+            flags = static_cast<GrColorComponentFlags>(0);
+            coverage = 0;
+        } else {
+            flags = kRGBA_GrColorComponentFlags;
+        }
+        fCoverageProcInfo.calcWithInitialValues(fCoverageStages.begin(), this->numCoverageStages(),
+                                                coverage, flags, true, fGeometryProcessor.get());
         fCoverageProcInfoValid = true;
         fCoverageCache = coverage;
     }
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index dff3c73..17bd0f4 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -68,6 +68,21 @@
      */
     void setFromPaint(const GrPaint& , const SkMatrix& viewMatrix, GrRenderTarget*);
 
+    ///////////////////////////////////////////////////////////////////////////
+    /// @name Vertex Attributes
+    ////
+
+    // TODO when we move this info off of GrGeometryProcessor, delete these
+    bool hasLocalCoordAttribute() const {
+        return this->hasGeometryProcessor() && this->getGeometryProcessor()->hasLocalCoords();
+    }
+    bool hasColorVertexAttribute() const {
+        return this->hasGeometryProcessor() && this->getGeometryProcessor()->hasVertexColor();
+    }
+    bool hasCoverageVertexAttribute() const {
+        return this->hasGeometryProcessor() && this->getGeometryProcessor()->hasVertexCoverage();
+    }
+
     /// @}
 
     /**
@@ -85,13 +100,29 @@
     /**
      * Determines whether the output coverage is guaranteed to be one for all pixels hit by a draw.
      */
-    bool hasSolidCoverage(const GrPrimitiveProcessor*) const;
+    bool hasSolidCoverage(GrColor coverage) const;
 
     /**
      * This function returns true if the render target destination pixel values will be read for
      * blending during draw.
      */
-    bool willBlendWithDst(const GrPrimitiveProcessor*) const;
+    bool willBlendWithDst(GrColor color, GrColor coverage) const;
+
+    /// @}
+
+    /**
+     * The geometry processor is the sole element of the skia pipeline which can use the vertex,
+     * geometry, and tesselation shaders.  The GP may also compute a coverage in its fragment shader
+     * but is never put in the color processing pipeline.
+     */
+
+    const GrGeometryProcessor* setGeometryProcessor(const GrGeometryProcessor* geometryProcessor) {
+        SkASSERT(geometryProcessor);
+        SkASSERT(!this->hasGeometryProcessor());
+        fGeometryProcessor.reset(SkRef(geometryProcessor));
+        fCoverageProcInfoValid = false;
+        return geometryProcessor;
+    }
 
     ///////////////////////////////////////////////////////////////////////////
     /// @name Effect Stages
@@ -116,6 +147,12 @@
     int numColorStages() const { return fColorStages.count(); }
     int numCoverageStages() const { return fCoverageStages.count(); }
     int numFragmentStages() const { return this->numColorStages() + this->numCoverageStages(); }
+    int numTotalStages() const {
+         return this->numFragmentStages() + (this->hasGeometryProcessor() ? 1 : 0);
+    }
+
+    bool hasGeometryProcessor() const { return SkToBool(fGeometryProcessor.get()); }
+    const GrGeometryProcessor* getGeometryProcessor() const { return fGeometryProcessor.get(); }
 
     const GrXPFactory* getXPFactory() const { return fXPFactory.get(); }
 
@@ -126,7 +163,7 @@
      * Checks whether any of the effects will read the dst pixel color.
      * TODO remove when we have an XP
      */
-    bool willEffectReadDstColor(const GrPrimitiveProcessor*) const;
+    bool willEffectReadDstColor(GrColor color, GrColor coverage) const;
 
     /**
      * The xfer processor factory.
@@ -201,11 +238,13 @@
     public:
         AutoRestoreEffects() 
             : fDrawState(NULL)
+            , fOriginalGPID(SK_InvalidUniqueID)
             , fColorEffectCnt(0)
             , fCoverageEffectCnt(0) {}
 
         AutoRestoreEffects(GrDrawState* ds)
             : fDrawState(NULL)
+            , fOriginalGPID(SK_InvalidUniqueID)
             , fColorEffectCnt(0)
             , fCoverageEffectCnt(0) {
             this->set(ds);
@@ -219,6 +258,7 @@
 
     private:
         GrDrawState*    fDrawState;
+        uint32_t        fOriginalGPID;
         int             fColorEffectCnt;
         int             fCoverageEffectCnt;
     };
@@ -515,29 +555,22 @@
     GrDrawState& operator= (const GrDrawState& that);
 
 private:
-    bool isEqual(const GrDrawState& that, bool explicitLocalCoords) const;
+    bool isEqual(const GrDrawState& that) const;
 
-    const GrProcOptInfo& colorProcInfo(const GrPrimitiveProcessor* pp) const {
-        this->calcColorInvariantOutput(pp);
+    const GrProcOptInfo& colorProcInfo(GrColor color) const { 
+        this->calcColorInvariantOutput(color);
         return fColorProcInfo;
     }
 
-    const GrProcOptInfo& coverageProcInfo(const GrPrimitiveProcessor* pp) const {
-        this->calcCoverageInvariantOutput(pp);
+    const GrProcOptInfo& coverageProcInfo(GrColor coverage) const {
+        this->calcCoverageInvariantOutput(coverage);
         return fCoverageProcInfo;
     }
 
     /**
-     * If fColorProcInfoValid is false, function calculates the invariant output for the color
-     * stages and results are stored in fColorProcInfo.
+     * Determines whether src alpha is guaranteed to be one for all src pixels
      */
-    void calcColorInvariantOutput(const GrPrimitiveProcessor*) const;
-
-    /**
-     * If fCoverageProcInfoValid is false, function calculates the invariant output for the coverage
-     * stages and results are stored in fCoverageProcInfo.
-     */
-    void calcCoverageInvariantOutput(const GrPrimitiveProcessor*) const;
+    bool srcAlphaWillBeOne(GrColor color, GrColor coverage) const;
 
     /**
      * If fColorProcInfoValid is false, function calculates the invariant output for the color
@@ -564,6 +597,7 @@
     uint32_t                                fFlagBits;
     GrStencilSettings                       fStencilSettings;
     DrawFace                                fDrawFace;
+    SkAutoTUnref<const GrGeometryProcessor> fGeometryProcessor;
     SkAutoTUnref<const GrXPFactory>         fXPFactory;
     FragmentStageArray                      fColorStages;
     FragmentStageArray                      fCoverageStages;
@@ -575,8 +609,6 @@
     mutable bool fCoverageProcInfoValid;
     mutable GrColor fColorCache;
     mutable GrColor fCoverageCache;
-    mutable const GrPrimitiveProcessor* fColorPrimProc;
-    mutable const GrPrimitiveProcessor* fCoveragePrimProc;
 
     friend class GrOptDrawState;
 };
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 96594b1..adb7128 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -307,7 +307,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 bool GrDrawTarget::checkDraw(const GrDrawState& drawState,
-                             const GrGeometryProcessor* gp,
                              GrPrimitiveType type,
                              int startVertex,
                              int startIndex,
@@ -350,7 +349,8 @@
 
     SkASSERT(drawState.getRenderTarget());
 
-    if (gp) {
+    if (drawState.hasGeometryProcessor()) {
+        const GrGeometryProcessor* gp = drawState.getGeometryProcessor();
         int numTextures = gp->numTextures();
         for (int t = 0; t < numTextures; ++t) {
             GrTexture* texture = gp->texture(t);
@@ -383,10 +383,12 @@
 }
 
 bool GrDrawTarget::setupDstReadIfNecessary(GrDrawState* ds,
-                                           const GrPrimitiveProcessor* primProc,
+                                           GrColor color,
+                                           uint8_t coverage,
                                            GrDeviceCoordTexture* dstCopy,
                                            const SkRect* drawBounds) {
-    if (this->caps()->dstReadInShaderSupport() || !ds->willEffectReadDstColor(primProc)) {
+    GrColor c = GrColorPackRGBA(coverage, coverage, coverage, coverage);
+    if (this->caps()->dstReadInShaderSupport() || !ds->willEffectReadDstColor(color, c)) {
         return true;
     }
     SkIRect copyRect;
@@ -434,7 +436,6 @@
 }
 
 void GrDrawTarget::drawIndexed(GrDrawState* ds,
-                               const GrGeometryProcessor* gp,
                                GrPrimitiveType type,
                                int startVertex,
                                int startIndex,
@@ -443,7 +444,7 @@
                                const SkRect* devBounds) {
     SkASSERT(ds);
     if (indexCount > 0 &&
-        this->checkDraw(*ds, gp, type, startVertex, startIndex, vertexCount, indexCount)) {
+        this->checkDraw(*ds, type, startVertex, startIndex, vertexCount, indexCount)) {
 
         // Setup clip
         GrClipMaskManager::ScissorState scissorState;
@@ -470,23 +471,24 @@
 
         // TODO: We should continue with incorrect blending.
         GrDeviceCoordTexture dstCopy;
-        if (!this->setupDstReadIfNecessary(ds, gp, &dstCopy, devBounds)) {
+        const GrGeometryProcessor* gp = ds->getGeometryProcessor();
+        if (!this->setupDstReadIfNecessary(ds, gp->getColor(), gp->getCoverage(), &dstCopy,
+                                           devBounds)) {
             return;
         }
         this->setDrawBuffers(&info, gp->getVertexStride());
 
-        this->onDraw(*ds, gp, info, scissorState, dstCopy.texture() ? &dstCopy : NULL);
+        this->onDraw(*ds, info, scissorState, dstCopy.texture() ? &dstCopy : NULL);
     }
 }
 
 void GrDrawTarget::drawNonIndexed(GrDrawState* ds,
-                                  const GrGeometryProcessor* gp,
                                   GrPrimitiveType type,
                                   int startVertex,
                                   int vertexCount,
                                   const SkRect* devBounds) {
     SkASSERT(ds);
-    if (vertexCount > 0 && this->checkDraw(*ds, gp, type, startVertex, -1, vertexCount, -1)) {
+    if (vertexCount > 0 && this->checkDraw(*ds, type, startVertex, -1, vertexCount, -1)) {
 
         // Setup clip
         GrClipMaskManager::ScissorState scissorState;
@@ -513,13 +515,15 @@
 
         // TODO: We should continue with incorrect blending.
         GrDeviceCoordTexture dstCopy;
-        if (!this->setupDstReadIfNecessary(ds, gp, &dstCopy, devBounds)) {
+        const GrGeometryProcessor* gp = ds->getGeometryProcessor();
+        if (!this->setupDstReadIfNecessary(ds, gp->getColor(), gp->getCoverage(), &dstCopy,
+                                           devBounds)) {
             return;
         }
 
         this->setDrawBuffers(&info, gp->getVertexStride());
 
-        this->onDraw(*ds, gp, info, scissorState, dstCopy.texture() ? &dstCopy : NULL);
+        this->onDraw(*ds, info, scissorState, dstCopy.texture() ? &dstCopy : NULL);
     }
 }
 
@@ -559,7 +563,6 @@
 }
 
 void GrDrawTarget::stencilPath(GrDrawState* ds,
-                               const GrPathProcessor* pathProc,
                                const GrPath* path,
                                GrPathRendering::FillType fill) {
     // TODO: extract portions of checkDraw that are relevant to path stenciling.
@@ -581,11 +584,11 @@
                                             ds->getRenderTarget()->getStencilBuffer(),
                                             &stencilSettings);
 
-    this->onStencilPath(*ds, pathProc, path, scissorState, stencilSettings);
+    this->onStencilPath(*ds, path, scissorState, stencilSettings);
 }
 
 void GrDrawTarget::drawPath(GrDrawState* ds,
-                            const GrPathProcessor* pathProc,
+                            GrColor color,
                             const GrPath* path,
                             GrPathRendering::FillType fill) {
     // TODO: extract portions of checkDraw that are relevant to path rendering.
@@ -612,16 +615,16 @@
                                             &stencilSettings);
 
     GrDeviceCoordTexture dstCopy;
-    if (!this->setupDstReadIfNecessary(ds, pathProc, &dstCopy, &devBounds)) {
+    if (!this->setupDstReadIfNecessary(ds, color, 0xff, &dstCopy, &devBounds)) {
         return;
     }
 
-    this->onDrawPath(*ds, pathProc, path, scissorState, stencilSettings, dstCopy.texture() ? &dstCopy :
-                                                                                       NULL);
+    this->onDrawPath(*ds, color, path, scissorState, stencilSettings, dstCopy.texture() ? &dstCopy :
+                                                                                          NULL);
 }
 
 void GrDrawTarget::drawPaths(GrDrawState* ds,
-                             const GrPathProcessor* pathProc,
+                             GrColor color,
                              const GrPathRange* pathRange,
                              const void* indices,
                              PathIndexType indexType,
@@ -656,11 +659,11 @@
     // point, because any context that supports NV_path_rendering will also
     // support NV_blend_equation_advanced.
     GrDeviceCoordTexture dstCopy;
-    if (!this->setupDstReadIfNecessary(ds, pathProc, &dstCopy, NULL)) {
+    if (!this->setupDstReadIfNecessary(ds, color, 0xff, &dstCopy, NULL)) {
         return;
     }
 
-    this->onDrawPaths(*ds, pathProc, pathRange, indices, indexType, transformValues, transformType,
+    this->onDrawPaths(*ds, color, pathRange, indices, indexType, transformValues, transformType,
                       count, scissorState, stencilSettings, dstCopy.texture() ? &dstCopy : NULL);
 }
 
@@ -730,7 +733,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 void GrDrawTarget::drawIndexedInstances(GrDrawState* ds,
-                                        const GrGeometryProcessor* gp,
                                         GrPrimitiveType type,
                                         int instanceCount,
                                         int verticesPerInstance,
@@ -769,7 +771,8 @@
 
     // TODO: We should continue with incorrect blending.
     GrDeviceCoordTexture dstCopy;
-    if (!this->setupDstReadIfNecessary(ds, gp, &dstCopy,devBounds)) {
+    const GrGeometryProcessor* gp = ds->getGeometryProcessor();
+    if (!this->setupDstReadIfNecessary(ds, gp->getColor(), gp->getCoverage(), &dstCopy,devBounds)) {
         return;
     }
 
@@ -779,14 +782,13 @@
         info.fIndexCount = info.fInstanceCount * indicesPerInstance;
 
         if (this->checkDraw(*ds,
-                            gp,
                             type,
                             info.fStartVertex,
                             info.fStartIndex,
                             info.fVertexCount,
                             info.fIndexCount)) {
             this->setDrawBuffers(&info, gp->getVertexStride());
-            this->onDraw(*ds, gp, info, scissorState, dstCopy.texture() ? &dstCopy : NULL);
+            this->onDraw(*ds, info, scissorState, dstCopy.texture() ? &dstCopy : NULL);
         }
         info.fStartVertex += info.fVertexCount;
         instanceCount -= info.fInstanceCount;
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index 770e885..fc2ee76 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -233,7 +233,6 @@
      *                     not a request for clipping.
      */
     void drawIndexed(GrDrawState*,
-                     const GrGeometryProcessor*,
                      GrPrimitiveType type,
                      int startVertex,
                      int startIndex,
@@ -253,7 +252,6 @@
      *                     not a request for clipping.
      */
     void drawNonIndexed(GrDrawState*,
-                        const GrGeometryProcessor*,
                         GrPrimitiveType type,
                         int startVertex,
                         int vertexCount,
@@ -265,13 +263,13 @@
      * on the draw state (if possible in the 3D API).  Note, we will never have an inverse fill
      * with stencil path
      */
-    void stencilPath(GrDrawState*, const GrPathProcessor*, const GrPath*,GrPathRendering::FillType);
+    void stencilPath(GrDrawState*, const GrPath*, GrPathRendering::FillType fill);
 
     /**
      * Draws a path. Fill must not be a hairline. It will respect the HW
      * antialias flag on the draw state (if possible in the 3D API).
      */
-    void drawPath(GrDrawState*, const GrPathProcessor*, const GrPath*, GrPathRendering::FillType);
+    void drawPath(GrDrawState*, GrColor, const GrPath*, GrPathRendering::FillType fill);
 
     /**
      * Draws the aggregate path from combining multiple. Note that this will not
@@ -287,7 +285,7 @@
      * @param fill            Fill type for drawing all the paths
      */
     void drawPaths(GrDrawState*,
-                   const GrPathProcessor*,
+                   GrColor,
                    const GrPathRange* pathRange,
                    const void* indices,
                    PathIndexType indexType,
@@ -359,7 +357,6 @@
      *                     not a request for clipping.
      */
     void drawIndexedInstances(GrDrawState*,
-                              const GrGeometryProcessor*,
                               GrPrimitiveType type,
                               int instanceCount,
                               int verticesPerInstance,
@@ -659,7 +656,8 @@
     // but couldn't be made. Otherwise, returns true.  This method needs to be protected because it
     // needs to be accessed by GLPrograms to setup a correct drawstate
     bool setupDstReadIfNecessary(GrDrawState*,
-                                 const GrPrimitiveProcessor*,
+                                 GrColor,
+                                 uint8_t,
                                  GrDeviceCoordTexture* dstCopy,
                                  const SkRect* drawBounds);
 
@@ -700,7 +698,6 @@
     virtual void geometrySourceWillPop(const GeometrySrcState& restoredState) = 0;
     // subclass called to perform drawing
     virtual void onDraw(const GrDrawState&,
-                        const GrGeometryProcessor*,
                         const DrawInfo&,
                         const GrClipMaskManager::ScissorState&,
                         const GrDeviceCoordTexture* dstCopy) = 0;
@@ -712,18 +709,17 @@
                             const SkMatrix* localMatrix) = 0;
 
     virtual void onStencilPath(const GrDrawState&,
-                               const GrPathProcessor*,
                                const GrPath*,
                                const GrClipMaskManager::ScissorState&,
                                const GrStencilSettings&) = 0;
     virtual void onDrawPath(const GrDrawState&,
-                            const GrPathProcessor*,
+                            GrColor,
                             const GrPath*,
                             const GrClipMaskManager::ScissorState&,
                             const GrStencilSettings&,
                             const GrDeviceCoordTexture* dstCopy) = 0;
     virtual void onDrawPaths(const GrDrawState&,
-                             const GrPathProcessor*,
+                             GrColor,
                              const GrPathRange*,
                              const void* indices,
                              PathIndexType,
@@ -770,7 +766,6 @@
     // called by drawIndexed and drawNonIndexed. Use a negative indexCount to
     // indicate non-indexed drawing.
     bool checkDraw(const GrDrawState&,
-                   const GrGeometryProcessor*,
                    GrPrimitiveType type,
                    int startVertex,
                    int startIndex,
diff --git a/src/gpu/GrGeometryProcessor.h b/src/gpu/GrGeometryProcessor.h
index 4411049..a0cfc09 100644
--- a/src/gpu/GrGeometryProcessor.h
+++ b/src/gpu/GrGeometryProcessor.h
@@ -39,23 +39,6 @@
 class GrGLGeometryProcessor;
 class GrOptDrawState;
 
-struct GrInitInvariantOutput;
-
-/*
- * GrGeometryProcessors and GrPathProcessors may effect invariantColor
- */
-class GrPrimitiveProcessor : public GrProcessor {
-public:
-    // TODO GPs and PPs have to provide an initial coverage because the coverage invariant code is
-    // broken right now
-    virtual uint8_t coverage() const = 0;
-    virtual void getInvariantOutputColor(GrInitInvariantOutput* out) const = 0;
-    virtual void getInvariantOutputCoverage(GrInitInvariantOutput* out) const = 0;
-
-private:
-    typedef GrProcessor INHERITED;
-};
-
 /**
  * A GrGeometryProcessor is used to perform computation in the vertex shader and
  * add support for custom vertex attributes. A GrGemeotryProcessor is typically
@@ -66,7 +49,7 @@
  * added to the vertex attribute array specified on the GrDrawState.
  * GrGeometryProcessor subclasses should be immutable after construction.
  */
-class GrGeometryProcessor : public GrPrimitiveProcessor {
+class GrGeometryProcessor : public GrProcessor {
 public:
     GrGeometryProcessor(GrColor color, uint8_t coverage = 0xff)
         : fVertexStride(0)
@@ -131,13 +114,11 @@
             return false;
         }
 
-        if (!fHasVertexColor && this->color() != that.color()) {
+        if (!fHasVertexColor && this->getColor() != that.getColor()) {
             return false;
         }
 
-        // TODO this is fragile, most gps set their coverage to 0xff so this is okay.  In the long
-        // term this should move to subclasses which set explicit coverage
-        if (!fHasVertexCoverage && this->coverage() != that.coverage()) {
+        if (!fHasVertexCoverage && this->getCoverage() != that.getCoverage()) {
             return false;
         }
         return this->onIsEqual(that);
@@ -152,8 +133,8 @@
 
     virtual void initBatchTracker(GrBatchTracker*, const InitBT&) const {}
 
-    GrColor color() const { return fColor; }
-    uint8_t coverage() const { return fCoverage; }
+    GrColor getColor() const { return fColor; }
+    uint8_t getCoverage() const { return fCoverage; }
 
     // TODO this is a total hack until the gp can own whether or not it uses uniform
     // color / coverage
@@ -161,8 +142,7 @@
     bool hasVertexCoverage() const { return fHasVertexCoverage; }
     bool hasLocalCoords() const { return fHasLocalCoords; }
 
-    void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE;
-    void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE;
+    void computeInvariantColor(GrInvariantOutput* inout) const;
 
 protected:
     /**
@@ -183,9 +163,6 @@
     void setHasVertexCoverage() { fHasVertexCoverage = true; }
     void setHasLocalCoords() { fHasLocalCoords = true; }
 
-    virtual void onGetInvariantOutputColor(GrInitInvariantOutput*) const {}
-    virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput*) const = 0;
-
 private:
     virtual bool onIsEqual(const GrGeometryProcessor&) const = 0;
 
@@ -200,26 +177,4 @@
 
     typedef GrProcessor 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) {
-        return SkNEW_ARGS(GrPathProcessor, (color));
-    }
-
-    const char* name() const SK_OVERRIDE { return "PathProcessor"; }
-    uint8_t coverage() const SK_OVERRIDE { return 0xff; }
-    void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE;
-    void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE;
-
-private:
-    GrPathProcessor(GrColor color) : fColor(color) {}
-    GrColor fColor;
-
-    typedef GrProcessor INHERITED;
-};
 #endif
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index 0b5c968..493420d 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -62,17 +62,14 @@
 
     The vertex attrib order is always pos, color, [local coords].
  */
-static const GrGeometryProcessor* create_rect_gp(GrDrawState* drawState,
-                                                 bool hasLocalCoords,
-                                                 GrColor color) {
+static void set_vertex_attributes(GrDrawState* drawState, bool hasLocalCoords, GrColor color) {
     uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType |
                      GrDefaultGeoProcFactory::kColor_GPType;
     flags |= hasLocalCoords ? GrDefaultGeoProcFactory::kLocalCoord_GPType : 0;
-    const GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Create(color, flags);
+    drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(color, flags))->unref();
     if (0xFF == GrColorUnpackA(color)) {
         drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
     }
-    return gp;
 }
 
 static bool path_fill_type_is_winding(const GrStencilSettings& pathStencilSettings) {
@@ -119,10 +116,9 @@
                                      const SkMatrix* localMatrix) {
     GrDrawState::AutoRestoreEffects are(ds);
 
-    SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(ds, SkToBool(localRect),
-                                                                     color));
+    set_vertex_attributes(ds, SkToBool(localRect),  color);
 
-    size_t vstride = gp->getVertexStride();
+    size_t vstride = ds->getGeometryProcessor()->getVertexStride();
     SkASSERT(vstride == sizeof(SkPoint) + sizeof(GrColor) + (SkToBool(localRect) ? sizeof(SkPoint) :
                                                                                    0));
     AutoReleaseGeometry geo(this, 4, vstride, 0);
@@ -169,7 +165,7 @@
     }
 
     this->setIndexSourceToBuffer(this->getContext()->getQuadIndexBuffer());
-    this->drawIndexedInstances(ds, gp, kTriangles_GrPrimitiveType, 1, 4, 6, &devBounds);
+    this->drawIndexedInstances(ds, kTriangles_GrPrimitiveType, 1, 4, 6, &devBounds);
 }
 
 int GrInOrderDrawBuffer::concatInstancedDraw(const GrDrawState& ds, const DrawInfo& info) {
@@ -225,13 +221,13 @@
 }
 
 void GrInOrderDrawBuffer::onDraw(const GrDrawState& ds,
-                                 const GrGeometryProcessor* gp,
                                  const DrawInfo& info,
                                  const ScissorState& scissorState,
                                  const GrDeviceCoordTexture* dstCopy) {
     SkASSERT(info.vertexBuffer() && (!info.isIndexed() || info.indexBuffer()));
 
-    if (!this->recordStateAndShouldDraw(ds, gp, NULL,
+    const GrGeometryProcessor* gp = ds.getGeometryProcessor();
+    if (!this->recordStateAndShouldDraw(ds, gp->getColor(), gp->getCoverage(),
                                         GrGpu::PrimTypeToDrawType(info.primitiveType()),
                                         scissorState, dstCopy)) {
         return;
@@ -253,12 +249,11 @@
 }
 
 void GrInOrderDrawBuffer::onStencilPath(const GrDrawState& ds,
-                                        const GrPathProcessor* pathProc,
                                         const GrPath* path,
                                         const GrClipMaskManager::ScissorState& scissorState,
                                         const GrStencilSettings& stencilSettings) {
     // Only compare the subset of GrDrawState relevant to path stenciling?
-    if (!this->recordStateAndShouldDraw(ds, NULL, pathProc, GrGpu::kStencilPath_DrawType,
+    if (!this->recordStateAndShouldDraw(ds, GrColor_WHITE, 0xff, GrGpu::kStencilPath_DrawType,
                                         scissorState, NULL)) {
         return;
     }
@@ -268,14 +263,14 @@
 }
 
 void GrInOrderDrawBuffer::onDrawPath(const GrDrawState& ds,
-                                     const GrPathProcessor* pathProc,
+                                     GrColor color,
                                      const GrPath* path,
                                      const GrClipMaskManager::ScissorState& scissorState,
                                      const GrStencilSettings& stencilSettings,
                                      const GrDeviceCoordTexture* dstCopy) {
     // TODO: Only compare the subset of GrDrawState relevant to path covering?
-    if (!this->recordStateAndShouldDraw(ds, NULL, pathProc, GrGpu::kDrawPath_DrawType,
-                                        scissorState, dstCopy)) {
+    if (!this->recordStateAndShouldDraw(ds, color, 0xff, GrGpu::kDrawPath_DrawType, scissorState,
+                                        dstCopy)) {
         return;
     }
     DrawPath* dp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawPath, (path));
@@ -284,7 +279,7 @@
 }
 
 void GrInOrderDrawBuffer::onDrawPaths(const GrDrawState& ds,
-                                      const GrPathProcessor* pathProc,
+                                      GrColor color,
                                       const GrPathRange* pathRange,
                                       const void* indices,
                                       PathIndexType indexType,
@@ -298,7 +293,7 @@
     SkASSERT(indices);
     SkASSERT(transformValues);
 
-    if (!this->recordStateAndShouldDraw(ds, NULL, pathProc, GrGpu::kDrawPath_DrawType, scissorState,
+    if (!this->recordStateAndShouldDraw(ds, color, 0xff, GrGpu::kDrawPath_DrawType, scissorState,
                                         dstCopy)) {
         return;
     }
@@ -329,7 +324,7 @@
             transformType == previous->fTransformType &&
             stencilSettings == previous->fStencilSettings &&
             path_fill_type_is_winding(stencilSettings) &&
-            !ds.willBlendWithDst(pathProc)) {
+            !ds.willBlendWithDst(color, GrColor_WHITE)) {
             // Fold this DrawPaths call into the one previous.
             previous->fCount += count;
             return;
@@ -495,13 +490,13 @@
 }
 
 bool GrInOrderDrawBuffer::recordStateAndShouldDraw(const GrDrawState& ds,
-                                                   const GrGeometryProcessor* gp,
-                                                   const GrPathProcessor* pathProc,
+                                                   GrColor color,
+                                                   uint8_t coverage,
                                                    GrGpu::DrawType drawType,
                                                    const GrClipMaskManager::ScissorState& scissor,
                                                    const GrDeviceCoordTexture* dstCopy) {
     SetState* ss = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, SetState,
-                                            (ds, gp, pathProc, *this->getGpu()->caps(), scissor,
+                                            (ds, color, coverage, *this->getGpu()->caps(), scissor,
                                              dstCopy, drawType));
     if (ss->fState.mustSkip()) {
         fCmdBuffer.pop_back();
diff --git a/src/gpu/GrInOrderDrawBuffer.h b/src/gpu/GrInOrderDrawBuffer.h
index 9b850a7..6771fcc 100644
--- a/src/gpu/GrInOrderDrawBuffer.h
+++ b/src/gpu/GrInOrderDrawBuffer.h
@@ -171,12 +171,11 @@
     };
 
     struct SetState : public Cmd {
-        SetState(const GrDrawState& drawState, const GrGeometryProcessor* gp,
-                 const GrPathProcessor* pp, const GrDrawTargetCaps& caps,
-                 const ScissorState& scissor, const GrDeviceCoordTexture* dstCopy,
-                 GrGpu::DrawType drawType)
+        SetState(const GrDrawState& drawState, GrColor color, uint8_t coverage,
+                 const GrDrawTargetCaps& caps, const ScissorState& scissor,
+                 const GrDeviceCoordTexture* dstCopy, GrGpu::DrawType drawType)
         : Cmd(kSetState_Cmd)
-        , fState(drawState, gp, pp, caps, scissor, dstCopy, drawType) {}
+        , fState(drawState, color, coverage, caps, scissor, dstCopy, drawType) {}
 
         void execute(GrInOrderDrawBuffer*, const GrOptDrawState*) SK_OVERRIDE;
 
@@ -191,7 +190,6 @@
 
     // overrides from GrDrawTarget
     void onDraw(const GrDrawState&,
-                const GrGeometryProcessor*,
                 const DrawInfo&,
                 const ScissorState&,
                 const GrDeviceCoordTexture* dstCopy) SK_OVERRIDE;
@@ -202,18 +200,17 @@
                     const SkMatrix* localMatrix) SK_OVERRIDE;
 
     void onStencilPath(const GrDrawState&,
-                       const GrPathProcessor*,
                        const GrPath*,
                        const ScissorState&,
                        const GrStencilSettings&) SK_OVERRIDE;
     void onDrawPath(const GrDrawState&,
-                    const GrPathProcessor*,
+                    GrColor,
                     const GrPath*,
                     const ScissorState&,
                     const GrStencilSettings&,
                     const GrDeviceCoordTexture* dstCopy) SK_OVERRIDE;
     void onDrawPaths(const GrDrawState&,
-                     const GrPathProcessor*,
+                     GrColor,
                      const GrPathRange*,
                      const void* indices,
                      PathIndexType,
@@ -240,8 +237,8 @@
     // records it. If the draw can be skipped false is returned and no new GrOptDrawState is
     // recorded.
     bool SK_WARN_UNUSED_RESULT recordStateAndShouldDraw(const GrDrawState&,
-                                                        const GrGeometryProcessor*,
-                                                        const GrPathProcessor*,
+                                                        GrColor,
+                                                        uint8_t coverage,
                                                         GrGpu::DrawType,
                                                         const GrClipMaskManager::ScissorState&,
                                                         const GrDeviceCoordTexture*);
diff --git a/src/gpu/GrOptDrawState.cpp b/src/gpu/GrOptDrawState.cpp
index 010fe4b..9ebe551 100644
--- a/src/gpu/GrOptDrawState.cpp
+++ b/src/gpu/GrOptDrawState.cpp
@@ -14,36 +14,21 @@
 #include "GrXferProcessor.h"
 
 GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
-                               const GrGeometryProcessor* gp,
-                               const GrPathProcessor* pathProc,
+                               GrColor color,
+                               uint8_t coverage,
                                const GrDrawTargetCaps& caps,
                                const ScissorState& scissorState,
                                const GrDeviceCoordTexture* dstCopy,
                                GrGpu::DrawType drawType)
     : fFinalized(false) {
+    GrColor coverageColor = GrColorPackRGBA(coverage, coverage, coverage, coverage);
     fDrawType = drawType;
 
-    // Copy GeometryProcesssor from DS or ODS
-    if (gp) {
-        SkASSERT(!pathProc);
-        SkASSERT(!(GrGpu::IsPathRenderingDrawType(drawType) ||
-                   GrGpu::kStencilPath_DrawType == drawType));
-        fGeometryProcessor.reset(gp);
-        fPrimitiveProcessor.reset(gp);
-    } else {
-        SkASSERT(!gp && pathProc && (GrGpu::IsPathRenderingDrawType(drawType) ||
-                               GrGpu::kStencilPath_DrawType == drawType));
-        fPrimitiveProcessor.reset(pathProc);
-    }
-
-
-    const GrProcOptInfo& colorPOI = drawState.colorProcInfo(fPrimitiveProcessor);
-    const GrProcOptInfo& coveragePOI = drawState.coverageProcInfo(fPrimitiveProcessor);
+    const GrProcOptInfo& colorPOI = drawState.colorProcInfo(color);
+    const GrProcOptInfo& coveragePOI = drawState.coverageProcInfo(coverageColor);
     
     fColor = colorPOI.inputColorToEffectiveStage();
-    // TODO fix this when coverage stages work correctly
-    // fCoverage = coveragePOI.inputColorToEffectiveStage();
-    fCoverage = fPrimitiveProcessor->coverage();
+    fCoverage = coverage;
 
     // Create XferProcessor from DS's XPFactory
     SkAutoTUnref<GrXferProcessor> xferProcessor(
@@ -101,11 +86,14 @@
         fFlags |= kDither_Flag;
     }
 
-    fDescInfo.fHasVertexColor = gp && gp->hasVertexColor();
+    fDescInfo.fHasVertexColor = drawState.hasGeometryProcessor() &&
+                                drawState.getGeometryProcessor()->hasVertexColor();
 
-    fDescInfo.fHasVertexCoverage = gp && gp->hasVertexCoverage();
+    fDescInfo.fHasVertexCoverage = drawState.hasGeometryProcessor() &&
+                                   drawState.getGeometryProcessor()->hasVertexCoverage();
 
-    bool hasLocalCoords = gp && gp->hasLocalCoords();
+    bool hasLocalCoords = drawState.hasGeometryProcessor() &&
+                          drawState.getGeometryProcessor()->hasLocalCoords();
 
     int firstColorStageIdx = colorPOI.firstEffectiveStageIndex();
     fDescInfo.fInputColorIsUsed = colorPOI.inputColorIsUsed();
@@ -118,6 +106,7 @@
     int firstCoverageStageIdx = 0;
     fDescInfo.fInputCoverageIsUsed = true;
 
+
     GrXferProcessor::BlendInfo blendInfo;
     fXferProcessor->getBlendInfo(&blendInfo);
     fSrcBlend = blendInfo.fSrcBlend;
@@ -129,6 +118,12 @@
 
     fDescInfo.fRequiresLocalCoordAttrib = hasLocalCoords;
 
+    // Copy GeometryProcesssor from DS or ODS
+    SkASSERT(GrGpu::IsPathRenderingDrawType(drawType) ||
+             GrGpu::kStencilPath_DrawType ||
+             drawState.hasGeometryProcessor());
+    fGeometryProcessor.reset(drawState.getGeometryProcessor());
+
     // Copy Stages from DS to ODS
     for (int i = firstColorStageIdx; i < drawState.numColorStages(); ++i) {
         SkNEW_APPEND_TO_TARRAY(&fFragmentStages,
@@ -144,7 +139,7 @@
     }
 
     // let the GP init the batch tracker
-    if (gp) {
+    if (drawState.hasGeometryProcessor()) {
         GrGeometryProcessor::InitBT init;
         init.fOutputColor = fDescInfo.fInputColorIsUsed;
         init.fOutputCoverage = fDescInfo.fInputCoverageIsUsed;
diff --git a/src/gpu/GrOptDrawState.h b/src/gpu/GrOptDrawState.h
index 1e7b5e5..55a5071 100644
--- a/src/gpu/GrOptDrawState.h
+++ b/src/gpu/GrOptDrawState.h
@@ -19,7 +19,6 @@
 
 class GrDeviceCoordTexture;
 class GrDrawState;
-class GrPathProcessor;
 
 /**
  * Class that holds an optimized version of a GrDrawState. It is meant to be an immutable class,
@@ -31,9 +30,8 @@
 
     typedef GrClipMaskManager::ScissorState ScissorState;
 
-    GrOptDrawState(const GrDrawState& drawState, const GrGeometryProcessor*, const GrPathProcessor*,
-                   const GrDrawTargetCaps&, const ScissorState&,
-                   const GrDeviceCoordTexture* dstCopy, GrGpu::DrawType);
+    GrOptDrawState(const GrDrawState& drawState, GrColor, uint8_t coverage, const GrDrawTargetCaps&,
+                   const ScissorState&, const GrDeviceCoordTexture* dstCopy, GrGpu::DrawType);
 
     bool operator== (const GrOptDrawState& that) const;
     bool operator!= (const GrOptDrawState& that) const { return !(*this == that); }
@@ -209,7 +207,7 @@
      * the function may adjust the blend coefficients. After this function is called the src and dst
      * blend coeffs will represent those used by backend API.
      */
-    void setOutputStateInfo(const GrDrawState& ds, GrXferProcessor::OptFlags,
+    void setOutputStateInfo(const GrDrawState& ds, GrColor coverage, GrXferProcessor::OptFlags,
                             const GrDrawTargetCaps&);
 
     enum Flags {
@@ -221,7 +219,6 @@
     typedef GrPendingIOResource<GrRenderTarget, kWrite_GrIOType> RenderTarget;
     typedef SkSTArray<8, GrPendingFragmentStage> FragmentStageArray;
     typedef GrPendingProgramElement<const GrGeometryProcessor> ProgramGeometryProcessor;
-    typedef GrPendingProgramElement<const GrPrimitiveProcessor> ProgramPrimitiveProcessor;
     typedef GrPendingProgramElement<const GrXferProcessor> ProgramXferProcessor;
     RenderTarget                        fRenderTarget;
     ScissorState                        fScissorState;
@@ -236,7 +233,6 @@
     GrBlendCoeff                        fDstBlend;
     uint32_t                            fFlags;
     ProgramGeometryProcessor            fGeometryProcessor;
-    ProgramPrimitiveProcessor           fPrimitiveProcessor;
     GrBatchTracker                      fBatchTracker;
     ProgramXferProcessor                fXferProcessor;
     FragmentStageArray                  fFragmentStages;
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index 22a18d2..eac6fb4 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -144,8 +144,8 @@
         return cee.fStroke == fStroke;
     }
 
-    virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
-        out->setUnknownSingleComponent();
+    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE {
+        inout->mulByUnknownAlpha();
     }
 
     const GrAttribute* fInPosition;
@@ -290,8 +290,8 @@
         return eee.fStroke == fStroke;
     }
 
-    virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
-        out->setUnknownSingleComponent();
+    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE {
+        inout->mulByUnknownAlpha();
     }
 
     const GrAttribute* fInPosition;
@@ -455,8 +455,8 @@
         return eee.fMode == fMode;
     }
 
-    virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
-        out->setUnknownSingleComponent();
+    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE {
+        inout->mulByUnknownAlpha();
     }
 
     const GrAttribute* fInPosition;
@@ -562,8 +562,8 @@
         }
     }
 
-    SkAutoTUnref<GrGeometryProcessor> gp(
-            CircleEdgeEffect::Create(color, isStrokeOnly && innerRadius > 0));
+    GrGeometryProcessor* gp = CircleEdgeEffect::Create(color, isStrokeOnly && innerRadius > 0);
+    drawState->setGeometryProcessor(gp)->unref();
 
     GrDrawTarget::AutoReleaseGeometry geo(target, 4, gp->getVertexStride(),  0);
     SkASSERT(gp->getVertexStride() == sizeof(CircleVertex));
@@ -609,7 +609,7 @@
     verts[3].fInnerRadius = innerRadius;
 
     target->setIndexSourceToBuffer(context->getGpu()->getQuadIndexBuffer());
-    target->drawIndexedInstances(drawState, gp, kTriangles_GrPrimitiveType, 1, 4, 6, &bounds);
+    target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 4, 6, &bounds);
     target->resetIndexSource();
 }
 
@@ -689,8 +689,11 @@
         return false;
     }
 
-    SkAutoTUnref<GrGeometryProcessor> gp(
-            EllipseEdgeEffect::Create(color, isStrokeOnly && innerXRadius > 0 && innerYRadius > 0));
+    GrGeometryProcessor* gp = EllipseEdgeEffect::Create(color,
+                                                        isStrokeOnly &&
+                                                        innerXRadius > 0 && innerYRadius > 0);
+
+    drawState->setGeometryProcessor(gp)->unref();
 
     GrDrawTarget::AutoReleaseGeometry geo(target, 4, gp->getVertexStride(),  0);
     SkASSERT(gp->getVertexStride() == sizeof(EllipseVertex));
@@ -741,7 +744,7 @@
     verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
 
     target->setIndexSourceToBuffer(context->getGpu()->getQuadIndexBuffer());
-    target->drawIndexedInstances(drawState, gp, kTriangles_GrPrimitiveType, 1, 4, 6, &bounds);
+    target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 4, 6, &bounds);
     target->resetIndexSource();
 
     return true;
@@ -806,7 +809,9 @@
     SkScalar innerRatioX = SkScalarDiv(xRadius, innerXRadius);
     SkScalar innerRatioY = SkScalarDiv(yRadius, innerYRadius);
 
-    SkAutoTUnref<GrGeometryProcessor> gp(DIEllipseEdgeEffect::Create(color, mode));
+    GrGeometryProcessor* gp = DIEllipseEdgeEffect::Create(color, mode);
+
+    drawState->setGeometryProcessor(gp)->unref();
 
     GrDrawTarget::AutoReleaseGeometry geo(target, 4, gp->getVertexStride(),  0);
     SkASSERT(gp->getVertexStride() == sizeof(DIEllipseVertex));
@@ -852,7 +857,7 @@
     verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -innerRatioY - offsetDy);
 
     target->setIndexSourceToBuffer(context->getGpu()->getQuadIndexBuffer());
-    target->drawIndexedInstances(drawState, gp, kTriangles_GrPrimitiveType, 1, 4, 6, &bounds);
+    target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 4, 6, &bounds);
     target->resetIndexSource();
 
     return true;
@@ -1072,7 +1077,8 @@
 
         isStrokeOnly = (isStrokeOnly && innerRadius >= 0);
 
-        SkAutoTUnref<GrGeometryProcessor> effect(CircleEdgeEffect::Create(color, isStrokeOnly));
+        GrGeometryProcessor* effect = CircleEdgeEffect::Create(color, isStrokeOnly);
+        drawState->setGeometryProcessor(effect)->unref();
 
         GrDrawTarget::AutoReleaseGeometry geo(target, 16, effect->getVertexStride(),  0);
         SkASSERT(effect->getVertexStride() == sizeof(CircleVertex));
@@ -1134,7 +1140,7 @@
         int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
                                       SK_ARRAY_COUNT(gRRectIndices);
         target->setIndexSourceToBuffer(indexBuffer);
-        target->drawIndexedInstances(drawState, effect, kTriangles_GrPrimitiveType, 1, 16, indexCnt,
+        target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 16, indexCnt,
                                      &bounds);
 
     // otherwise we use the ellipse renderer
@@ -1173,7 +1179,8 @@
 
         isStrokeOnly = (isStrokeOnly && innerXRadius >= 0 && innerYRadius >= 0);
 
-        SkAutoTUnref<GrGeometryProcessor> effect(EllipseEdgeEffect::Create(color, isStrokeOnly));
+        GrGeometryProcessor* effect = EllipseEdgeEffect::Create(color, isStrokeOnly);
+        drawState->setGeometryProcessor(effect)->unref();
 
         GrDrawTarget::AutoReleaseGeometry geo(target, 16, effect->getVertexStride(),  0);
         SkASSERT(effect->getVertexStride() == sizeof(EllipseVertex));
@@ -1240,7 +1247,7 @@
         int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
                                       SK_ARRAY_COUNT(gRRectIndices);
         target->setIndexSourceToBuffer(indexBuffer);
-        target->drawIndexedInstances(drawState, effect, kTriangles_GrPrimitiveType, 1, 16, indexCnt,
+        target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 16, indexCnt,
                                      &bounds);
     }
 
diff --git a/src/gpu/GrProcOptInfo.cpp b/src/gpu/GrProcOptInfo.cpp
index ebcf016..a84ac2e 100644
--- a/src/gpu/GrProcOptInfo.cpp
+++ b/src/gpu/GrProcOptInfo.cpp
@@ -11,57 +11,37 @@
 #include "GrFragmentStage.h"
 #include "GrGeometryProcessor.h"
 
-void GrProcOptInfo::calcColorWithPrimProc(const GrPrimitiveProcessor* primProc,
-                                          const GrFragmentStage* stages,
-                                          int stageCount) {
-    GrInitInvariantOutput out;
-    primProc->getInvariantOutputColor(&out);
-    fInOut.reset(out);
-    this->internalCalc(stages, stageCount, primProc->willReadFragmentPosition());
-}
-
-void GrProcOptInfo::calcCoverageWithPrimProc(const GrPrimitiveProcessor* primProc,
-                                             const GrFragmentStage* stages,
-                                             int stageCount) {
-    GrInitInvariantOutput out;
-    primProc->getInvariantOutputCoverage(&out);
-    fInOut.reset(out);
-    this->internalCalc(stages, stageCount, primProc->willReadFragmentPosition());
-}
-
 void GrProcOptInfo::calcWithInitialValues(const GrFragmentStage* stages,
                                           int stageCount,
                                           GrColor startColor,
                                           GrColorComponentFlags flags,
-                                          bool areCoverageStages) {
-    GrInitInvariantOutput out;
-    out.fIsSingleComponent = areCoverageStages;
-    out.fColor = startColor;
-    out.fValidFlags = flags;
-    this->internalCalc(stages, stageCount, false);
-}
-
-void GrProcOptInfo::internalCalc(const GrFragmentStage* stages,
-                                 int stageCount,
-                                 bool initWillReadFragmentPosition) {
+                                          bool areCoverageStages,
+                                          const GrGeometryProcessor* gp) {
+    fInOut.reset(startColor, flags, areCoverageStages);
     fFirstEffectStageIndex = 0;
     fInputColorIsUsed = true;
-    fInputColor = fInOut.color();
+    fInputColor = startColor;
     fRemoveVertexAttrib = false;
     fReadsDst = false;
-    fReadsFragPosition = initWillReadFragmentPosition;
+    fReadsFragPosition = false;
+
+    if (areCoverageStages && gp) {
+        gp->computeInvariantOutput(&fInOut);
+    }
 
     for (int i = 0; i < stageCount; ++i) {
         const GrFragmentProcessor* processor = stages[i].getProcessor();
         fInOut.resetWillUseInputColor();
         processor->computeInvariantOutput(&fInOut);
-        SkDEBUGCODE(fInOut.validate());
+#ifdef SK_DEBUG
+        fInOut.validate();
+#endif
         if (!fInOut.willUseInputColor()) {
             fFirstEffectStageIndex = i;
             fInputColorIsUsed = false;
             // Reset these since we don't care if previous stages read these values
             fReadsDst = false;
-            fReadsFragPosition = initWillReadFragmentPosition;
+            fReadsFragPosition = false;
         }
         if (processor->willReadDstColor()) {
             fReadsDst = true;
@@ -79,7 +59,8 @@
             fInOut.resetNonMulStageFound();
             // Reset these since we don't care if previous stages read these values
             fReadsDst = false;
-            fReadsFragPosition = initWillReadFragmentPosition;
+            fReadsFragPosition = false;
         }
     }
 }
+
diff --git a/src/gpu/GrProcOptInfo.h b/src/gpu/GrProcOptInfo.h
index 30b286f..91ff5f9 100644
--- a/src/gpu/GrProcOptInfo.h
+++ b/src/gpu/GrProcOptInfo.h
@@ -13,7 +13,7 @@
 
 class GrFragmentStage;
 class GrFragmentProcessor;
-class GrPrimitiveProcessor;
+class GrGeometryProcessor;
 class GrProcessor;
 
 /**
@@ -33,11 +33,8 @@
         , fReadsFragPosition(false) {}
 
     void calcWithInitialValues(const GrFragmentStage*, int stageCount, GrColor startColor,
-                               GrColorComponentFlags flags, bool areCoverageStages);
-
-    void calcColorWithPrimProc(const GrPrimitiveProcessor*, const GrFragmentStage*, int stagecount);
-    void calcCoverageWithPrimProc(const GrPrimitiveProcessor*, const GrFragmentStage*,
-                                  int stagecount);
+                               GrColorComponentFlags flags, bool areCoverageStages,
+                               const GrGeometryProcessor* gp = NULL);
 
     bool isSolidWhite() const { return fInOut.isSolidWhite(); }
     bool isOpaque() const { return fInOut.isOpaque(); }
@@ -92,8 +89,6 @@
     bool readsFragPosition() const { return fReadsFragPosition; }
 
 private:
-    void internalCalc(const GrFragmentStage*, int stagecount, bool initWillReadFragPosition);
-
     GrInvariantOutput fInOut;
     int fFirstEffectStageIndex;
     bool fInputColorIsUsed;
diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp
index c937c2e..2bcd9b4 100644
--- a/src/gpu/GrProcessor.cpp
+++ b/src/gpu/GrProcessor.cpp
@@ -145,6 +145,10 @@
     return true;
 }
 
+void GrProcessor::computeInvariantOutput(GrInvariantOutput* inout) const {
+    this->onComputeInvariantOutput(inout);
+}
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 void GrFragmentProcessor::addCoordTransform(const GrCoordTransform* transform) {
@@ -165,33 +169,10 @@
     return true;
 }
 
-void GrFragmentProcessor::computeInvariantOutput(GrInvariantOutput* inout) const {
-    this->onComputeInvariantOutput(inout);
-}
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-void GrGeometryProcessor::getInvariantOutputColor(GrInitInvariantOutput* out) const {
-    if (fHasVertexColor) {
-        out->setUnknownFourComponents();
-    } else {
-        out->setKnownFourComponents(fColor);
-    }
-    this->onGetInvariantOutputColor(out);
-}
+void GrGeometryProcessor::computeInvariantColor(GrInvariantOutput* intout) const {
 
-void GrGeometryProcessor::getInvariantOutputCoverage(GrInitInvariantOutput* out) const {
-    this->onGetInvariantOutputCoverage(out);
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-void GrPathProcessor::getInvariantOutputColor(GrInitInvariantOutput* out) const {
-    out->setKnownFourComponents(fColor);
-}
-
-void GrPathProcessor::getInvariantOutputCoverage(GrInitInvariantOutput* out) const {
-    out->setKnownSingleComponent(0xff);
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -212,3 +193,4 @@
 // Initial static variable from GrXPFactory
 int32_t GrXPFactory::gCurrXPFClassID =
         GrXPFactory::kIllegalXPFClassID;
+
diff --git a/src/gpu/GrStencilAndCoverPathRenderer.cpp b/src/gpu/GrStencilAndCoverPathRenderer.cpp
index d8470f3..e7c4fc8 100644
--- a/src/gpu/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/GrStencilAndCoverPathRenderer.cpp
@@ -85,9 +85,8 @@
                                                   const SkPath& path,
                                                   const SkStrokeRec& stroke) {
     SkASSERT(!path.isInverseFillType());
-    SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(GrColor_WHITE));
     SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke));
-    target->stencilPath(drawState, pp, p, convert_skpath_filltype(path.getFillType()));
+    target->stencilPath(drawState, p, convert_skpath_filltype(path.getFillType()));
 }
 
 bool GrStencilAndCoverPathRenderer::onDrawPath(GrDrawTarget* target,
@@ -118,8 +117,7 @@
         drawState->setStencil(kInvertedStencilPass);
 
         // fake inverse with a stencil and cover
-        SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(GrColor_WHITE));
-        target->stencilPath(drawState, pp, p, convert_skpath_filltype(path.getFillType()));
+        target->stencilPath(drawState, p, convert_skpath_filltype(path.getFillType()));
 
         GrDrawState::AutoViewMatrixRestore avmr;
         SkRect bounds = SkRect::MakeLTRB(0, 0,
@@ -147,8 +145,7 @@
             0xffff);
 
         drawState->setStencil(kStencilPass);
-        SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(color));
-        target->drawPath(drawState, pp, p, convert_skpath_filltype(path.getFillType()));
+        target->drawPath(drawState, color, p, convert_skpath_filltype(path.getFillType()));
     }
 
     drawState->stencil()->setDisabled();
diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp
index 42f74ea..bf1e58d 100644
--- a/src/gpu/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/GrStencilAndCoverTextContext.cpp
@@ -399,8 +399,7 @@
 
 void GrStencilAndCoverTextContext::flush() {
     if (fQueuedGlyphCount > 0) {
-        SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(fPaint.getColor()));
-        fDrawTarget->drawPaths(&fDrawState, pp, fGlyphs,
+        fDrawTarget->drawPaths(&fDrawState, fPaint.getColor(), fGlyphs,
                                fGlyphIndices, GrPathRange::kU16_PathIndexType,
                                get_xy_scalar_array(fGlyphPositions),
                                GrPathRendering::kTranslate_PathTransformType,
diff --git a/src/gpu/effects/GrBezierEffect.h b/src/gpu/effects/GrBezierEffect.h
index 53b1053..a9cbeb0 100644
--- a/src/gpu/effects/GrBezierEffect.h
+++ b/src/gpu/effects/GrBezierEffect.h
@@ -102,8 +102,8 @@
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
-    virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
-        out->setUnknownSingleComponent();
+    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE {
+        inout->mulByUnknownAlpha();
     }
 
     GrPrimitiveEdgeType   fEdgeType;
@@ -171,8 +171,8 @@
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
-    virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
-        out->setUnknownSingleComponent();
+    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE {
+        inout->mulByUnknownAlpha();
     }
 
     GrPrimitiveEdgeType   fEdgeType;
@@ -241,8 +241,8 @@
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
-    virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
-        out->setUnknownSingleComponent();
+    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE {
+        inout->mulByUnknownAlpha();
     }
 
     GrPrimitiveEdgeType   fEdgeType;
diff --git a/src/gpu/effects/GrBicubicEffect.cpp b/src/gpu/effects/GrBicubicEffect.cpp
index 76edff0..8ada70e 100644
--- a/src/gpu/effects/GrBicubicEffect.cpp
+++ b/src/gpu/effects/GrBicubicEffect.cpp
@@ -175,7 +175,7 @@
 
 void GrBicubicEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
     // FIXME: Perhaps we can do better.
-    inout->mulByUnknownSingleComponent();
+    inout->mulByUnknownAlpha();
 }
 
 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrBicubicEffect);
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.cpp b/src/gpu/effects/GrBitmapTextGeoProc.cpp
index 9c5e82e..1578fd8 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.cpp
+++ b/src/gpu/effects/GrBitmapTextGeoProc.cpp
@@ -84,15 +84,15 @@
     return SkToBool(this->inColor()) == SkToBool(gp.inColor());
 }
 
-void GrBitmapTextGeoProc::onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const {
+void GrBitmapTextGeoProc::onComputeInvariantOutput(GrInvariantOutput* inout) const {
     if (GrPixelConfigIsAlphaOnly(this->texture(0)->config())) {
-        out->setUnknownSingleComponent();
+        inout->mulByUnknownAlpha();
     } else if (GrPixelConfigIsOpaque(this->texture(0)->config())) {
-        out->setUnknownOpaqueFourComponents();
-        out->setUsingLCDCoverage();
+        inout->mulByUnknownOpaqueColor();
+        inout->setUsingLCDCoverage();
     } else {
-        out->setUnknownFourComponents();
-        out->setUsingLCDCoverage();
+        inout->mulByUnknownColor();
+        inout->setUsingLCDCoverage();
     }
 }
 
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.h b/src/gpu/effects/GrBitmapTextGeoProc.h
index ef86704..ce235ae 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.h
+++ b/src/gpu/effects/GrBitmapTextGeoProc.h
@@ -45,7 +45,7 @@
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
-    virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput*) const SK_OVERRIDE;
+    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE;
 
     GrTextureAccess    fTextureAccess;
     const GrAttribute* fInPosition;
diff --git a/src/gpu/effects/GrConvexPolyEffect.cpp b/src/gpu/effects/GrConvexPolyEffect.cpp
index 1430716..248cd17 100644
--- a/src/gpu/effects/GrConvexPolyEffect.cpp
+++ b/src/gpu/effects/GrConvexPolyEffect.cpp
@@ -44,9 +44,9 @@
     virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE {
         if (fRect.isEmpty()) {
             // An empty rect will have no coverage anywhere.
-            inout->mulByKnownSingleComponent(0);
+            inout->mulByKnownAlpha(0);
         } else {
-            inout->mulByUnknownSingleComponent();
+            inout->mulByUnknownAlpha();
         }
     }
 
@@ -323,7 +323,7 @@
 GrConvexPolyEffect::~GrConvexPolyEffect() {}
 
 void GrConvexPolyEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
-    inout->mulByUnknownSingleComponent();
+    inout->mulByUnknownAlpha();
 }
 
 void GrConvexPolyEffect::getGLProcessorKey(const GrGLCaps& caps,
diff --git a/src/gpu/effects/GrConvolutionEffect.h b/src/gpu/effects/GrConvolutionEffect.h
index 1d0950b..7fda369 100644
--- a/src/gpu/effects/GrConvolutionEffect.h
+++ b/src/gpu/effects/GrConvolutionEffect.h
@@ -99,7 +99,7 @@
     virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const {
         // If the texture was opaque we could know that the output color if we knew the sum of the
         // kernel values.
-        inout->mulByUnknownFourComponents();
+        inout->mulByUnknownColor();
     }
 
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp
index 1641d27..b59b2a6 100644
--- a/src/gpu/effects/GrDashingEffect.cpp
+++ b/src/gpu/effects/GrDashingEffect.cpp
@@ -335,7 +335,7 @@
         devIntervals[0] = lineLength;
     }
 
-    SkAutoTUnref<const GrGeometryProcessor> gp;
+    const GrGeometryProcessor* gp;
     bool fullDash = devIntervals[1] > 0.f || useAA;
     if (fullDash) {
         SkPathEffect::DashInfo devInfo;
@@ -347,12 +347,14 @@
         bool isRoundCap = SkPaint::kRound_Cap == cap;
         GrDashingEffect::DashCap capType = isRoundCap ? GrDashingEffect::kRound_DashCap :
                                                         GrDashingEffect::kNonRound_DashCap;
-        gp.reset(GrDashingEffect::Create(color, edgeType, devInfo, strokeWidth, capType));
+        gp = GrDashingEffect::Create(color, edgeType, devInfo, strokeWidth, capType);
     } else {
         // Set up the vertex data for the line and start/end dashes
-        gp.reset(GrDefaultGeoProcFactory::Create(color, GrDefaultGeoProcFactory::kPosition_GPType));
+        gp = GrDefaultGeoProcFactory::Create(color, GrDefaultGeoProcFactory::kPosition_GPType);
     }
 
+    drawState->setGeometryProcessor(gp)->unref();
+
     int totalRectCnt = 0;
 
     totalRectCnt += !lineDone ? 1 : 0;
@@ -433,7 +435,7 @@
     }
 
     target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
-    target->drawIndexedInstances(drawState, gp, kTriangles_GrPrimitiveType, totalRectCnt, 4, 6);
+    target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, totalRectCnt, 4, 6);
     target->resetIndexSource();
     return true;
 }
@@ -487,7 +489,7 @@
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
-    virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput*) const SK_OVERRIDE;
+    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE;
 
     GrPrimitiveEdgeType fEdgeType;
     const GrAttribute*  fInPosition;
@@ -612,8 +614,8 @@
 
 DashingCircleEffect::~DashingCircleEffect() {}
 
-void DashingCircleEffect::onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const {
-    out->setUnknownSingleComponent();
+void DashingCircleEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
+    inout->mulByUnknownAlpha();
 }
 
 void DashingCircleEffect::getGLProcessorKey(const GrBatchTracker& bt,
@@ -717,7 +719,7 @@
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
-    virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput*) const SK_OVERRIDE;
+    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE;
 
     GrPrimitiveEdgeType fEdgeType;
     const GrAttribute*  fInPosition;
@@ -855,8 +857,8 @@
 
 DashingLineEffect::~DashingLineEffect() {}
 
-void DashingLineEffect::onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const {
-    out->setUnknownSingleComponent();
+void DashingLineEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
+    inout->mulByUnknownAlpha();
 }
 
 void DashingLineEffect::getGLProcessorKey(const GrBatchTracker& bt,
diff --git a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
index be06c1d..f408d2d 100755
--- a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
+++ b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
@@ -206,8 +206,8 @@
            fFlags == cte.fFlags;
 }
 
-void GrDistanceFieldTextureEffect::onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const {
-    out->setUnknownSingleComponent();
+void GrDistanceFieldTextureEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
+    inout->mulByUnknownAlpha();
 }
 
 void GrDistanceFieldTextureEffect::getGLProcessorKey(const GrBatchTracker& bt,
@@ -407,8 +407,8 @@
     return fFlags == cte.fFlags;
 }
 
-void GrDistanceFieldNoGammaTextureEffect::onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const{
-    out->setUnknownSingleComponent();
+void GrDistanceFieldNoGammaTextureEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
+    inout->mulByUnknownAlpha();
 }
 
 void GrDistanceFieldNoGammaTextureEffect::getGLProcessorKey(const GrBatchTracker& bt,
@@ -665,9 +665,9 @@
             fFlags == cte.fFlags);
 }
 
-void GrDistanceFieldLCDTextureEffect::onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const {
-    out->setUnknownFourComponents();
-    out->setUsingLCDCoverage();
+void GrDistanceFieldLCDTextureEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
+    inout->mulByUnknownColor();
+    inout->setUsingLCDCoverage();
 }
 
 void GrDistanceFieldLCDTextureEffect::getGLProcessorKey(const GrBatchTracker& bt,
diff --git a/src/gpu/effects/GrDistanceFieldTextureEffect.h b/src/gpu/effects/GrDistanceFieldTextureEffect.h
index a290d57..f0f7e3b 100644
--- a/src/gpu/effects/GrDistanceFieldTextureEffect.h
+++ b/src/gpu/effects/GrDistanceFieldTextureEffect.h
@@ -87,7 +87,7 @@
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
-    virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput*) const SK_OVERRIDE;
+    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE;
 
     GrTextureAccess    fTextureAccess;
 #ifdef SK_GAMMA_APPLY_TO_A8
@@ -139,7 +139,7 @@
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
-    virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput*) const SK_OVERRIDE;
+    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE;
 
     GrTextureAccess    fTextureAccess;
     uint32_t           fFlags;
@@ -190,7 +190,7 @@
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
-    virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput*) const SK_OVERRIDE;
+    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE;
 
     GrTextureAccess    fTextureAccess;
     GrTextureAccess    fGammaTextureAccess;
diff --git a/src/gpu/effects/GrMatrixConvolutionEffect.h b/src/gpu/effects/GrMatrixConvolutionEffect.h
index 8d6bb7c..6d60609 100644
--- a/src/gpu/effects/GrMatrixConvolutionEffect.h
+++ b/src/gpu/effects/GrMatrixConvolutionEffect.h
@@ -81,7 +81,7 @@
 
     virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE {
         // TODO: Try to do better?
-        inout->mulByUnknownFourComponents();
+        inout->mulByUnknownColor();
     }
 
     SkIRect         fBounds;
diff --git a/src/gpu/effects/GrOvalEffect.cpp b/src/gpu/effects/GrOvalEffect.cpp
index f1d1e68..b750599 100644
--- a/src/gpu/effects/GrOvalEffect.cpp
+++ b/src/gpu/effects/GrOvalEffect.cpp
@@ -56,7 +56,7 @@
 }
 
 void CircleEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
-    inout->mulByUnknownSingleComponent();
+    inout->mulByUnknownAlpha();
 }
 
 CircleEffect::CircleEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar r)
@@ -233,7 +233,7 @@
 }
 
 void EllipseEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
-    inout->mulByUnknownSingleComponent();
+    inout->mulByUnknownAlpha();
 }
 
 EllipseEffect::EllipseEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar rx, SkScalar ry)
diff --git a/src/gpu/effects/GrRRectEffect.cpp b/src/gpu/effects/GrRRectEffect.cpp
index 1c1bd18..64a9d41 100644
--- a/src/gpu/effects/GrRRectEffect.cpp
+++ b/src/gpu/effects/GrRRectEffect.cpp
@@ -86,7 +86,7 @@
 }
 
 void CircularRRectEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
-    inout->mulByUnknownSingleComponent();
+    inout->mulByUnknownAlpha();
 }
 
 CircularRRectEffect::CircularRRectEffect(GrPrimitiveEdgeType edgeType, uint32_t circularCornerFlags,
@@ -426,7 +426,7 @@
 }
 
 void EllipticalRRectEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
-    inout->mulByUnknownSingleComponent();
+    inout->mulByUnknownAlpha();
 }
 
 EllipticalRRectEffect::EllipticalRRectEffect(GrPrimitiveEdgeType edgeType, const SkRRect& rrect)
diff --git a/src/gpu/effects/GrSingleTextureEffect.h b/src/gpu/effects/GrSingleTextureEffect.h
index 9df0cff..6fd6819 100644
--- a/src/gpu/effects/GrSingleTextureEffect.h
+++ b/src/gpu/effects/GrSingleTextureEffect.h
@@ -41,11 +41,11 @@
      */
     void updateInvariantOutputForModulation(GrInvariantOutput* inout) const {
         if (GrPixelConfigIsAlphaOnly(this->texture(0)->config())) {
-            inout->mulByUnknownSingleComponent();
+            inout->mulByUnknownAlpha();
         } else if (GrPixelConfigIsOpaque(this->texture(0)->config())) {
-            inout->mulByUnknownOpaqueFourComponents();
+            inout->mulByUnknownOpaqueColor();
         } else {
-            inout->mulByUnknownFourComponents();
+            inout->mulByUnknownColor();
         }
     }
 
diff --git a/src/gpu/effects/GrTextureDomain.cpp b/src/gpu/effects/GrTextureDomain.cpp
index f1ef618..b5b9ae4 100644
--- a/src/gpu/effects/GrTextureDomain.cpp
+++ b/src/gpu/effects/GrTextureDomain.cpp
@@ -273,9 +273,9 @@
 void GrTextureDomainEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
     if (GrTextureDomain::kDecal_Mode == fTextureDomain.mode()) { // TODO: helper
         if (GrPixelConfigIsAlphaOnly(this->texture(0)->config())) {
-            inout->mulByUnknownSingleComponent();
+            inout->mulByUnknownAlpha();
         } else {
-            inout->mulByUnknownFourComponents();
+            inout->mulByUnknownColor();
         }
     } else {
         this->updateInvariantOutputForModulation(inout);
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index c0de2a5..953b5e0 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -129,14 +129,19 @@
     ds->setXPFactory(xpf.get());
 }
 
-static const GrGeometryProcessor* get_random_gp(GrContext* context,
-                                                const GrDrawTargetCaps& caps,
-                                                SkRandom* random,
-                                                GrTexture* dummyTextures[]) {
-    return GrProcessorTestFactory<GrGeometryProcessor>::CreateStage(random,
-                                                                    context,
-                                                                    caps,
-                                                                    dummyTextures);
+static void set_random_gp(GrContext* context,
+                          const GrDrawTargetCaps& caps,
+                          GrDrawState* ds,
+                          SkRandom* random,
+                          GrTexture* dummyTextures[]) {
+    SkAutoTUnref<const GrGeometryProcessor> gp(
+            GrProcessorTestFactory<GrGeometryProcessor>::CreateStage(random,
+                                                                     context,
+                                                                     caps,
+                                                                     dummyTextures));
+    SkASSERT(gp);
+
+    ds->setGeometryProcessor(gp);
 }
 
 static void set_random_color_coverage_stages(GrGpuGL* gpu,
@@ -288,12 +293,8 @@
 
         // twiddle drawstate knobs randomly
         bool hasGeometryProcessor = !usePathRendering;
-        const GrGeometryProcessor* gp = NULL;
-        const GrPathProcessor* pathProc = NULL;
         if (hasGeometryProcessor) {
-            gp = get_random_gp(fContext, gpu->glCaps(), &random, dummyTextures);
-        } else {
-            pathProc = GrPathProcessor::Create(GrColor_WHITE);
+            set_random_gp(fContext, gpu->glCaps(), &ds, &random, dummyTextures);
         }
         set_random_color_coverage_stages(gpu,
                                          &ds,
@@ -311,20 +312,19 @@
 
         GrDeviceCoordTexture dstCopy;
 
-        const GrPrimitiveProcessor* primProc;
-        if (hasGeometryProcessor) {
-            primProc = gp;
-        } else {
-            primProc = pathProc;
-        }
-        if (!this->setupDstReadIfNecessary(&ds, primProc, &dstCopy, NULL)) {
+        // TODO take color off the PP when its installed
+        GrColor color = ds.hasGeometryProcessor() ? ds.getGeometryProcessor()->getColor() :
+                                                    GrColor_WHITE;
+        uint8_t coverage = ds.hasGeometryProcessor() ? ds.getGeometryProcessor()->getCoverage() :
+                                                       0xff;
+        if (!this->setupDstReadIfNecessary(&ds, color, coverage, &dstCopy, NULL)) {
             SkDebugf("Couldn't setup dst read texture");
             return false;
         }
 
         // create optimized draw state, setup readDst texture if required, and build a descriptor
         // and program.  ODS creation can fail, so we have to check
-        GrOptDrawState ods(ds, gp, pathProc, *gpu->caps(), scissor, &dstCopy, drawType);
+        GrOptDrawState ods(ds, color, coverage, *gpu->caps(), scissor, &dstCopy, drawType);
         if (ods.mustSkip()) {
             continue;
         }