BUG=skia:

Review URL: https://codereview.chromium.org/815643005
diff --git a/src/gpu/GrGeometryProcessor.cpp b/src/gpu/GrGeometryProcessor.cpp
index 662f28f..7214220 100644
--- a/src/gpu/GrGeometryProcessor.cpp
+++ b/src/gpu/GrGeometryProcessor.cpp
@@ -241,7 +241,7 @@
 
 
 void
-GrGLGeometryProcessor::setTransformData(const GrPrimitiveProcessor* primProc,
+GrGLGeometryProcessor::setTransformData(const GrPrimitiveProcessor& primProc,
                                         const GrGLProgramDataManager& pdman,
                                         int index,
                                         const SkTArray<const GrCoordTransform*, true>& transforms) {
@@ -249,7 +249,7 @@
     int numTransforms = transforms.count();
     for (int t = 0; t < numTransforms; ++t) {
         SkASSERT(procTransforms[t].fHandle.isValid());
-        const SkMatrix& transform = GetTransformMatrix(primProc->localMatrix(), *transforms[t]);
+        const SkMatrix& transform = GetTransformMatrix(primProc.localMatrix(), *transforms[t]);
         if (!procTransforms[t].fCurrentValue.cheapEqualTo(transform)) {
             pdman.setSkMatrix(procTransforms[t].fHandle.convertToUniformHandle(), transform);
             procTransforms[t].fCurrentValue = transform;
@@ -377,7 +377,7 @@
         }
     }
 
-    void setTransformData(const GrPrimitiveProcessor* primProc,
+    void setTransformData(const GrPrimitiveProcessor& primProc,
                           int index,
                           const SkTArray<const GrCoordTransform*, true>& transforms,
                           GrGLPathRendering* glpr,
@@ -386,7 +386,7 @@
         // effect
         int texCoordIndex = fInstalledTransforms[index][0].fHandle.handle();
         for (int t = 0; t < transforms.count(); ++t) {
-            const SkMatrix& transform = GetTransformMatrix(primProc->localMatrix(), *transforms[t]);
+            const SkMatrix& transform = GetTransformMatrix(primProc.localMatrix(), *transforms[t]);
             GrGLPathRendering::PathTexGenComponents components =
                     GrGLPathRendering::kST_PathTexGenComponents;
             if (transform.hasPerspective()) {
@@ -455,7 +455,7 @@
         }
     }
 
-    void setTransformData(const GrPrimitiveProcessor* primProc,
+    void setTransformData(const GrPrimitiveProcessor& primProc,
                           int index,
                           const SkTArray<const GrCoordTransform*, true>& coordTransforms,
                           GrGLPathRendering* glpr,
@@ -464,7 +464,7 @@
         int numTransforms = transforms.count();
         for (int t = 0; t < numTransforms; ++t) {
             SkASSERT(transforms[t].fHandle.isValid());
-            const SkMatrix& transform = GetTransformMatrix(primProc->localMatrix(),
+            const SkMatrix& transform = GetTransformMatrix(primProc.localMatrix(),
                                                            *coordTransforms[t]);
             if (transforms[t].fCurrentValue.cheapEqualTo(transform)) {
                 continue;
diff --git a/src/gpu/GrGeometryProcessor.h b/src/gpu/GrGeometryProcessor.h
index 736c515..97271b9 100644
--- a/src/gpu/GrGeometryProcessor.h
+++ b/src/gpu/GrGeometryProcessor.h
@@ -111,13 +111,6 @@
                               const GrPrimitiveProcessor& that,
                               const GrBatchTracker& theirs) const = 0;
 
-    /*
-     * We always call canMakeEqual before makeEqual so there is no need to do any kind of equality
-     * testing here
-     * TODO make this pure virtual when primProcs can actually use it
-     */
-    virtual void makeEqual(GrBatchTracker*, const GrBatchTracker&) const {}
-
     virtual void getInvariantOutputColor(GrInitInvariantOutput* out) const = 0;
     virtual void getInvariantOutputCoverage(GrInitInvariantOutput* out) const = 0;
 
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 0c60a02..f523632 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -276,9 +276,9 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-void GrGpu::draw(const GrOptDrawState& ds, const GrDrawTarget::DrawInfo& info) {
+void GrGpu::draw(const DrawArgs& args, const GrDrawTarget::DrawInfo& info) {
     this->handleDirtyContext();
-    this->onDraw(ds, info);
+    this->onDraw(args, info);
 }
 
 void GrGpu::stencilPath(const GrPath* path, const StencilPathState& state) {
@@ -286,14 +286,14 @@
     this->onStencilPath(path, state);
 }
 
-void GrGpu::drawPath(const GrOptDrawState& ds,
+void GrGpu::drawPath(const DrawArgs& args,
                      const GrPath* path,
                      const GrStencilSettings& stencilSettings) {
     this->handleDirtyContext();
-    this->onDrawPath(ds, path, stencilSettings);
+    this->onDrawPath(args, path, stencilSettings);
 }
 
-void GrGpu::drawPaths(const GrOptDrawState& ds,
+void GrGpu::drawPaths(const DrawArgs& args,
                       const GrPathRange* pathRange,
                       const void* indices,
                       GrDrawTarget::PathIndexType indexType,
@@ -303,6 +303,6 @@
                       const GrStencilSettings& stencilSettings) {
     this->handleDirtyContext();
     pathRange->willDrawPaths(indices, indexType, count);
-    this->onDrawPaths(ds, pathRange, indices, indexType, transformValues,
+    this->onDrawPaths(args, pathRange, indices, indexType, transformValues,
                       transformType, count, stencilSettings);
 }
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 429c9c8..cbae83f 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -20,6 +20,7 @@
 class GrPathRange;
 class GrPathRenderer;
 class GrPathRendererChain;
+class GrPrimitiveProcessor;
 class GrStencilBuffer;
 class GrVertexBufferAllocPool;
 
@@ -315,10 +316,12 @@
 
     GrContext::GPUStats* gpuStats() { return &fGPUStats; }
 
-    virtual void buildProgramDesc(const GrOptDrawState&,
+    virtual void buildProgramDesc(GrProgramDesc*,
+                                  const GrPrimitiveProcessor&,
+                                  const GrOptDrawState&,
                                   const GrProgramDesc::DescInfo&,
                                   GrGpu::DrawType,
-                                  GrProgramDesc*) = 0;
+                                  const GrBatchTracker&) const = 0;
 
     /**
      * Called at start and end of gpu trace marking
@@ -358,7 +361,25 @@
                              const SkIRect& srcRect,
                              const SkIPoint& dstPoint) = 0;
 
-    void draw(const GrOptDrawState&, const GrDrawTarget::DrawInfo&);
+    struct DrawArgs {
+        typedef GrDrawTarget::DrawInfo DrawInfo;
+        DrawArgs(const GrPrimitiveProcessor* primProc,
+                 const GrOptDrawState* optState,
+                 const GrProgramDesc* desc,
+                 const GrBatchTracker* batchTracker)
+            : fPrimitiveProcessor(primProc)
+            , fOptState(optState)
+            , fDesc(desc)
+            , fBatchTracker(batchTracker) {
+            SkASSERT(primProc && optState && desc && batchTracker);
+        }
+        const GrPrimitiveProcessor* fPrimitiveProcessor;
+        const GrOptDrawState* fOptState;
+        const GrProgramDesc* fDesc;
+        const GrBatchTracker* fBatchTracker;
+    };
+
+    void draw(const DrawArgs&, const GrDrawTarget::DrawInfo&);
 
     /** None of these params are optional, pointers used just to avoid making copies. */
     struct StencilPathState {
@@ -371,8 +392,8 @@
 
     void stencilPath(const GrPath*, const StencilPathState&);
 
-    void drawPath(const GrOptDrawState&, const GrPath*, const GrStencilSettings&);
-    void drawPaths(const GrOptDrawState&,
+    void drawPath(const DrawArgs&, const GrPath*, const GrStencilSettings&);
+    void drawPaths(const DrawArgs&,
                    const GrPathRange*,
                    const void* indices,
                    GrDrawTarget::PathIndexType,
@@ -446,11 +467,11 @@
                                     bool insideClip) = 0;
 
     // overridden by backend-specific derived class to perform the draw call.
-    virtual void onDraw(const GrOptDrawState&, const GrDrawTarget::DrawInfo&) = 0;
+    virtual void onDraw(const DrawArgs&, const GrDrawTarget::DrawInfo&) = 0;
     virtual void onStencilPath(const GrPath*, const StencilPathState&) = 0;
 
-    virtual void onDrawPath(const GrOptDrawState&, const GrPath*, const GrStencilSettings&) = 0;
-    virtual void onDrawPaths(const GrOptDrawState&,
+    virtual void onDrawPath(const DrawArgs&, const GrPath*, const GrStencilSettings&) = 0;
+    virtual void onDrawPaths(const DrawArgs&,
                              const GrPathRange*,
                              const void* indices,
                              GrDrawTarget::PathIndexType,
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index 468045c..f504f09 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -419,7 +419,7 @@
 
     // Updated every time we find a set state cmd to reflect the current state in the playback
     // stream.
-    GrOptDrawState* currentOptState = NULL;
+    SetState* currentState = NULL;
 
     while (iter.next()) {
         GrGpuTraceMarker newMarker("", -1);
@@ -433,10 +433,14 @@
 
         if (kSetState_Cmd == strip_trace_bit(iter->fType)) {
             SetState* ss = reinterpret_cast<SetState*>(iter.get());
-            currentOptState = &ss->fState;
-            currentOptState->finalize(this->getGpu());
+
+            this->getGpu()->buildProgramDesc(&ss->fDesc, *ss->fPrimitiveProcessor, ss->fState,
+                                             ss->fState.descInfo(), ss->fState.drawType(),
+                                             ss->fBatchTracker);
+            currentState = ss;
+
         } else {
-            iter->execute(this, currentOptState);
+            iter->execute(this, currentState);
         }
 
         if (cmd_has_trace_marker(iter->fType)) {
@@ -448,12 +452,14 @@
     ++fDrawID;
 }
 
-void GrInOrderDrawBuffer::Draw::execute(GrInOrderDrawBuffer* buf, const GrOptDrawState* optState) {
-    SkASSERT(optState);
-    buf->getGpu()->draw(*optState, fInfo);
+void GrInOrderDrawBuffer::Draw::execute(GrInOrderDrawBuffer* buf, const SetState* state) {
+    SkASSERT(state);
+    DrawArgs args(state->fPrimitiveProcessor.get(), &state->fState, &state->fDesc,
+                  &state->fBatchTracker);
+    buf->getGpu()->draw(args, fInfo);
 }
 
-void GrInOrderDrawBuffer::StencilPath::execute(GrInOrderDrawBuffer* buf, const GrOptDrawState*) {
+void GrInOrderDrawBuffer::StencilPath::execute(GrInOrderDrawBuffer* buf, const SetState*) {
     GrGpu::StencilPathState state;
     state.fRenderTarget = fRenderTarget.get();
     state.fScissor = &fScissor;
@@ -464,24 +470,26 @@
     buf->getGpu()->stencilPath(this->path(), state);
 }
 
-void GrInOrderDrawBuffer::DrawPath::execute(GrInOrderDrawBuffer* buf,
-                                            const GrOptDrawState* optState) {
-    SkASSERT(optState);
-    buf->getGpu()->drawPath(*optState, this->path(), fStencilSettings);
+void GrInOrderDrawBuffer::DrawPath::execute(GrInOrderDrawBuffer* buf, const SetState* state) {
+    SkASSERT(state);
+    DrawArgs args(state->fPrimitiveProcessor.get(), &state->fState, &state->fDesc,
+                  &state->fBatchTracker);
+    buf->getGpu()->drawPath(args, this->path(), fStencilSettings);
 }
 
-void GrInOrderDrawBuffer::DrawPaths::execute(GrInOrderDrawBuffer* buf,
-                                             const GrOptDrawState* optState) {
-    SkASSERT(optState);
-    buf->getGpu()->drawPaths(*optState, this->pathRange(),
+void GrInOrderDrawBuffer::DrawPaths::execute(GrInOrderDrawBuffer* buf, const SetState* state) {
+    SkASSERT(state);
+    DrawArgs args(state->fPrimitiveProcessor.get(), &state->fState, &state->fDesc,
+                  &state->fBatchTracker);
+    buf->getGpu()->drawPaths(args, this->pathRange(),
                             &buf->fPathIndexBuffer[fIndicesLocation], fIndexType,
                             &buf->fPathTransformBuffer[fTransformsLocation], fTransformType,
                             fCount, fStencilSettings);
 }
 
-void GrInOrderDrawBuffer::SetState::execute(GrInOrderDrawBuffer*, const GrOptDrawState*) {}
+void GrInOrderDrawBuffer::SetState::execute(GrInOrderDrawBuffer*, const SetState*) {}
 
-void GrInOrderDrawBuffer::Clear::execute(GrInOrderDrawBuffer* buf, const GrOptDrawState*) {
+void GrInOrderDrawBuffer::Clear::execute(GrInOrderDrawBuffer* buf, const SetState*) {
     if (GrColor_ILLEGAL == fColor) {
         buf->getGpu()->discard(this->renderTarget());
     } else {
@@ -489,12 +497,11 @@
     }
 }
 
-void GrInOrderDrawBuffer::ClearStencilClip::execute(GrInOrderDrawBuffer* buf,
-                                                    const GrOptDrawState*) {
+void GrInOrderDrawBuffer::ClearStencilClip::execute(GrInOrderDrawBuffer* buf, const SetState*) {
     buf->getGpu()->clearStencilClip(fRect, fInsideClip, this->renderTarget());
 }
 
-void GrInOrderDrawBuffer::CopySurface::execute(GrInOrderDrawBuffer* buf, const GrOptDrawState*) {
+void GrInOrderDrawBuffer::CopySurface::execute(GrInOrderDrawBuffer* buf, const SetState*) {
     buf->getGpu()->copySurface(this->dst(), this->src(), fSrcRect, fDstPoint);
 }
 
@@ -524,10 +531,18 @@
         fCmdBuffer.pop_back();
         return false;
     }
-    if (fPrevState && fPrevState->combineIfPossible(ss->fState)) {
+
+    ss->fPrimitiveProcessor->initBatchTracker(&ss->fBatchTracker,
+                                              ss->fState.getInitBatchTracker());
+
+    if (fPrevState &&
+        fPrevState->fPrimitiveProcessor->canMakeEqual(fPrevState->fBatchTracker,
+                                                      *ss->fPrimitiveProcessor,
+                                                      ss->fBatchTracker) &&
+        fPrevState->fState.isEqual(ss->fState)) {
         fCmdBuffer.pop_back();
     } else {
-        fPrevState = &ss->fState;
+        fPrevState = ss;
         this->recordTraceMarkersIfNecessary();
     }
     return true;
diff --git a/src/gpu/GrInOrderDrawBuffer.h b/src/gpu/GrInOrderDrawBuffer.h
index d733546..6a6cd88 100644
--- a/src/gpu/GrInOrderDrawBuffer.h
+++ b/src/gpu/GrInOrderDrawBuffer.h
@@ -51,6 +51,7 @@
     void discard(GrRenderTarget*) SK_OVERRIDE;
 
 private:
+    typedef GrGpu::DrawArgs DrawArgs;
     enum {
         kDraw_Cmd           = 1,
         kStencilPath_Cmd    = 2,
@@ -61,11 +62,13 @@
         kDrawPaths_Cmd      = 7,
     };
 
+    struct SetState;
+
     struct Cmd : ::SkNoncopyable {
         Cmd(uint8_t type) : fType(type) {}
         virtual ~Cmd() {}
 
-        virtual void execute(GrInOrderDrawBuffer*, const GrOptDrawState*) = 0;
+        virtual void execute(GrInOrderDrawBuffer*, const SetState*) = 0;
 
         uint8_t fType;
     };
@@ -73,7 +76,7 @@
     struct Draw : public Cmd {
         Draw(const DrawInfo& info) : Cmd(kDraw_Cmd), fInfo(info) {}
 
-        void execute(GrInOrderDrawBuffer*, const GrOptDrawState*) SK_OVERRIDE;
+        void execute(GrInOrderDrawBuffer*, const SetState*) SK_OVERRIDE;
 
         DrawInfo     fInfo;
     };
@@ -86,7 +89,7 @@
 
         const GrPath* path() const { return fPath.get(); }
 
-        void execute(GrInOrderDrawBuffer*, const GrOptDrawState*) SK_OVERRIDE;
+        void execute(GrInOrderDrawBuffer*, const SetState*) SK_OVERRIDE;
 
         SkMatrix                                                fViewMatrix;
         bool                                                    fUseHWAA;
@@ -102,7 +105,7 @@
 
         const GrPath* path() const { return fPath.get(); }
 
-        void execute(GrInOrderDrawBuffer*, const GrOptDrawState*) SK_OVERRIDE;
+        void execute(GrInOrderDrawBuffer*, const SetState*) SK_OVERRIDE;
 
         GrStencilSettings       fStencilSettings;
 
@@ -115,7 +118,7 @@
 
         const GrPathRange* pathRange() const { return fPathRange.get();  }
 
-        void execute(GrInOrderDrawBuffer*, const GrOptDrawState*) SK_OVERRIDE;
+        void execute(GrInOrderDrawBuffer*, const SetState*) SK_OVERRIDE;
 
         int                     fIndicesLocation;
         PathIndexType           fIndexType;
@@ -134,7 +137,7 @@
 
         GrRenderTarget* renderTarget() const { return fRenderTarget.get(); }
 
-        void execute(GrInOrderDrawBuffer*, const GrOptDrawState*) SK_OVERRIDE;
+        void execute(GrInOrderDrawBuffer*, const SetState*) SK_OVERRIDE;
 
         SkIRect fRect;
         GrColor fColor;
@@ -150,7 +153,7 @@
 
         GrRenderTarget* renderTarget() const { return fRenderTarget.get(); }
 
-        void execute(GrInOrderDrawBuffer*, const GrOptDrawState*) SK_OVERRIDE;
+        void execute(GrInOrderDrawBuffer*, const SetState*) SK_OVERRIDE;
 
         SkIRect fRect;
         bool    fInsideClip;
@@ -165,7 +168,7 @@
         GrSurface* dst() const { return fDst.get(); }
         GrSurface* src() const { return fSrc.get(); }
 
-        void execute(GrInOrderDrawBuffer*, const GrOptDrawState*) SK_OVERRIDE;
+        void execute(GrInOrderDrawBuffer*, const SetState*) SK_OVERRIDE;
 
         SkIPoint    fDstPoint;
         SkIRect     fSrcRect;
@@ -181,11 +184,16 @@
                  const GrScissorState& scissor, const GrDeviceCoordTexture* dstCopy,
                  GrGpu::DrawType drawType)
         : Cmd(kSetState_Cmd)
+        , fPrimitiveProcessor(primProc)
         , fState(drawState, primProc, caps, scissor, dstCopy, drawType) {}
 
-        void execute(GrInOrderDrawBuffer*, const GrOptDrawState*) SK_OVERRIDE;
+        void execute(GrInOrderDrawBuffer*, const SetState*) SK_OVERRIDE;
 
-        GrOptDrawState          fState;
+        typedef GrPendingProgramElement<const GrPrimitiveProcessor> ProgramPrimitiveProcessor;
+        ProgramPrimitiveProcessor   fPrimitiveProcessor;
+        const GrOptDrawState        fState;
+        GrProgramDesc               fDesc;
+        GrBatchTracker              fBatchTracker;
     };
 
     typedef void* TCmdAlign; // This wouldn't be enough align if a command used long double.
@@ -265,7 +273,7 @@
     };
 
     CmdBuffer                           fCmdBuffer;
-    GrOptDrawState*                     fPrevState;
+    SetState*                           fPrevState;
     SkTArray<GrTraceMarkerSet, false>   fGpuCmdMarkers;
     SkTDArray<char>                     fPathIndexBuffer;
     SkTDArray<float>                    fPathTransformBuffer;
diff --git a/src/gpu/GrOptDrawState.cpp b/src/gpu/GrOptDrawState.cpp
index bc1ce7d..8d28f44 100644
--- a/src/gpu/GrOptDrawState.cpp
+++ b/src/gpu/GrOptDrawState.cpp
@@ -18,15 +18,11 @@
                                const GrDrawTargetCaps& caps,
                                const GrScissorState& scissorState,
                                const GrDeviceCoordTexture* dstCopy,
-                               GrGpu::DrawType drawType)
-    : fFinalized(false) {
+                               GrGpu::DrawType drawType) {
     fDrawType = drawType;
 
-    fPrimitiveProcessor.reset(primProc);
-
-
-    const GrProcOptInfo& colorPOI = drawState.colorProcInfo(fPrimitiveProcessor);
-    const GrProcOptInfo& coveragePOI = drawState.coverageProcInfo(fPrimitiveProcessor);
+    const GrProcOptInfo& colorPOI = drawState.colorProcInfo(primProc);
+    const GrProcOptInfo& coveragePOI = drawState.coverageProcInfo(primProc);
 
     // Create XferProcessor from DS's XPFactory
     SkAutoTUnref<GrXferProcessor> xferProcessor(
@@ -112,12 +108,10 @@
     }
 
     // let the GP init the batch tracker
-    GrGeometryProcessor::InitBT init;
-    init.fColorIgnored = SkToBool(optFlags & GrXferProcessor::kIgnoreColor_OptFlag);
-    init.fOverrideColor = init.fColorIgnored ? GrColor_ILLEGAL : overrideColor;
-    init.fCoverageIgnored = SkToBool(optFlags & GrXferProcessor::kIgnoreCoverage_OptFlag);
-    init.fUsesLocalCoords = usesLocalCoords;
-    fPrimitiveProcessor->initBatchTracker(&fBatchTracker, init);
+    fInitBT.fColorIgnored = SkToBool(optFlags & GrXferProcessor::kIgnoreColor_OptFlag);
+    fInitBT.fOverrideColor = fInitBT.fColorIgnored ? GrColor_ILLEGAL : overrideColor;
+    fInitBT.fCoverageIgnored = SkToBool(optFlags & GrXferProcessor::kIgnoreCoverage_OptFlag);
+    fInitBT.fUsesLocalCoords = usesLocalCoords;
 }
 
 void GrOptDrawState::adjustProgramFromOptimizations(const GrDrawState& ds,
@@ -144,18 +138,9 @@
     }
 }
 
-void GrOptDrawState::finalize(GrGpu* gpu) {
-    gpu->buildProgramDesc(*this, fDescInfo, fDrawType, &fDesc);
-    fFinalized = true;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 
-bool GrOptDrawState::combineIfPossible(const GrOptDrawState& that) {
-    if (fDescInfo != that.fDescInfo) {
-        return false;
-    }
-
+bool GrOptDrawState::isEqual(const GrOptDrawState& that) const {
     if (this->getRenderTarget() != that.getRenderTarget() ||
         this->fFragmentStages.count() != that.fFragmentStages.count() ||
         this->fNumColorStages != that.fNumColorStages ||
@@ -168,12 +153,6 @@
         return false;
     }
 
-    if (!this->getPrimitiveProcessor()->canMakeEqual(fBatchTracker,
-                                                     *that.getPrimitiveProcessor(),
-                                                     that.getBatchTracker())) {
-        return false;
-    }
-
     if (!this->getXferProcessor()->isEqual(*that.getXferProcessor())) {
         return false;
     }
@@ -186,9 +165,6 @@
             return false;
         }
     }
-
-    // Now update the GrPrimitiveProcessor's batch tracker
-    fPrimitiveProcessor->makeEqual(&fBatchTracker, that.getBatchTracker());
     return true;
 }
 
diff --git a/src/gpu/GrOptDrawState.h b/src/gpu/GrOptDrawState.h
index 00e368c..6beeea2 100644
--- a/src/gpu/GrOptDrawState.h
+++ b/src/gpu/GrOptDrawState.h
@@ -37,7 +37,7 @@
      * Returns true if it is possible to combine the two GrOptDrawStates and it will update 'this'
      * to subsume 'that''s draw.
      */
-    bool combineIfPossible(const GrOptDrawState& that);
+    bool isEqual(const GrOptDrawState& that) const;
 
     /// @}
 
@@ -62,9 +62,6 @@
     int numCoverageStages() const { return fFragmentStages.count() - fNumColorStages; }
     int numFragmentStages() const { return fFragmentStages.count(); }
 
-    const GrPrimitiveProcessor* getPrimitiveProcessor() const { return fPrimitiveProcessor.get(); }
-    const GrBatchTracker& getBatchTracker() const { return fBatchTracker; }
-
     const GrXferProcessor* getXferProcessor() const { return fXferProcessor.get(); }
 
     const GrPendingFragmentStage& getColorStage(int idx) const {
@@ -135,10 +132,9 @@
 
     const GrDeviceCoordTexture* getDstCopy() const { return fDstCopy.texture() ? &fDstCopy : NULL; }
 
-    // Finalize *MUST* be called before programDesc()
-    void finalize(GrGpu*);
+    const GrProgramDesc::DescInfo& descInfo() const { return fDescInfo; }
 
-    const GrProgramDesc& programDesc() const { SkASSERT(fFinalized); return fDesc; }
+    const GrGeometryProcessor::InitBT& getInitBatchTracker() const { return fInitBT; }
 
 private:
     /**
@@ -166,8 +162,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;
     GrScissorState                      fScissorState;
@@ -175,13 +169,11 @@
     GrDrawState::DrawFace               fDrawFace;
     GrDeviceCoordTexture                fDstCopy;
     uint32_t                            fFlags;
-    ProgramPrimitiveProcessor           fPrimitiveProcessor;
-    GrBatchTracker                      fBatchTracker;
     ProgramXferProcessor                fXferProcessor;
     FragmentStageArray                  fFragmentStages;
     GrGpu::DrawType                     fDrawType;
     GrProgramDesc::DescInfo             fDescInfo;
-    bool                                fFinalized;
+    GrGeometryProcessor::InitBT         fInitBT;
 
     // This function is equivalent to the offset into fFragmentStages where coverage stages begin.
     int                                 fNumColorStages;
diff --git a/src/gpu/GrTest.cpp b/src/gpu/GrTest.cpp
index d709853..3acf27e 100644
--- a/src/gpu/GrTest.cpp
+++ b/src/gpu/GrTest.cpp
@@ -63,10 +63,11 @@
                                    int width, int height,
                                    GrPixelConfig config,
                                    size_t rowBytes) const SK_OVERRIDE { return false; }
-    void buildProgramDesc(const GrOptDrawState&,
+    void buildProgramDesc(GrProgramDesc*,const GrPrimitiveProcessor&,
+                          const GrOptDrawState&,
                           const GrProgramDesc::DescInfo&,
                           GrGpu::DrawType,
-                          GrProgramDesc* desc) SK_OVERRIDE {}
+                          const GrBatchTracker&) const SK_OVERRIDE {}
 
     void discard(GrRenderTarget*) SK_OVERRIDE {}
 
@@ -112,13 +113,13 @@
 
     void onClearStencilClip(GrRenderTarget*, const SkIRect& rect, bool insideClip) SK_OVERRIDE {}
 
-    void onDraw(const GrOptDrawState&, const GrDrawTarget::DrawInfo&) SK_OVERRIDE {}
+    void onDraw(const DrawArgs&, const GrDrawTarget::DrawInfo&) SK_OVERRIDE {}
 
     void onStencilPath(const GrPath* path, const StencilPathState& state) SK_OVERRIDE {}
 
-    void onDrawPath(const GrOptDrawState&, const GrPath*, const GrStencilSettings&) SK_OVERRIDE {}
+    void onDrawPath(const DrawArgs&, const GrPath*, const GrStencilSettings&) SK_OVERRIDE {}
 
-    void onDrawPaths(const GrOptDrawState&,
+    void onDrawPaths(const DrawArgs&,
                      const GrPathRange*,
                      const void* indices,
                      GrDrawTarget::PathIndexType,
diff --git a/src/gpu/gl/GrGLGeometryProcessor.h b/src/gpu/gl/GrGLGeometryProcessor.h
index 88b69a6..da6c347 100644
--- a/src/gpu/gl/GrGLGeometryProcessor.h
+++ b/src/gpu/gl/GrGLGeometryProcessor.h
@@ -138,7 +138,7 @@
     /* Any general emit code goes in the base class emitCode.  Subclasses override onEmitCode */
     void emitCode(EmitArgs&) SK_OVERRIDE;
 
-    void setTransformData(const GrPrimitiveProcessor*,
+    void setTransformData(const GrPrimitiveProcessor&,
                           const GrGLProgramDataManager&,
                           int index,
                           const SkTArray<const GrCoordTransform*, true>& transforms);
@@ -210,7 +210,7 @@
                  const GrPrimitiveProcessor&,
                  const GrBatchTracker&) SK_OVERRIDE;
 
-    virtual void setTransformData(const GrPrimitiveProcessor*,
+    virtual void setTransformData(const GrPrimitiveProcessor&,
                                   int index,
                                   const SkTArray<const GrCoordTransform*, true>& transforms,
                                   GrGLPathRendering*,
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 182d258..aa9a3e6 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -1336,15 +1336,16 @@
     this->disableScissor();
 }
 
-bool GrGLGpu::flushGLState(const GrOptDrawState& optState) {
+bool GrGLGpu::flushGLState(const DrawArgs& args) {
     GrXferProcessor::BlendInfo blendInfo;
-    optState.getXferProcessor()->getBlendInfo(&blendInfo);
+    const GrOptDrawState& optState = *args.fOptState;
+    args.fOptState->getXferProcessor()->getBlendInfo(&blendInfo);
 
     this->flushDither(optState.isDitherState());
     this->flushColorWrite(blendInfo.fWriteColor);
     this->flushDrawFace(optState.getDrawFace());
 
-    fCurrentProgram.reset(fProgramCache->getProgram(optState));
+    fCurrentProgram.reset(fProgramCache->getProgram(args));
     if (NULL == fCurrentProgram.get()) {
         SkDEBUGFAIL("Failed to create program!");
         return false;
@@ -1362,7 +1363,7 @@
         this->flushBlend(blendInfo);
     }
 
-    fCurrentProgram->setData(optState);
+    fCurrentProgram->setData(*args.fPrimitiveProcessor, optState, *args.fBatchTracker);
 
     GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(optState.getRenderTarget());
     this->flushStencil(optState.getStencil());
@@ -1377,7 +1378,7 @@
     return true;
 }
 
-void GrGLGpu::setupGeometry(const GrOptDrawState& optState,
+void GrGLGpu::setupGeometry(const GrPrimitiveProcessor& primProc,
                             const GrDrawTarget::DrawInfo& info,
                             size_t* indexOffsetInBytes) {
     GrGLVertexBuffer* vbuf;
@@ -1400,11 +1401,10 @@
     GrGLAttribArrayState* attribState =
         fHWGeometryState.bindArrayAndBuffersToDraw(this, vbuf, ibuf);
 
-    const GrPrimitiveProcessor* primProc = optState.getPrimitiveProcessor();
-    int vaCount = primProc->numAttribs();
+    int vaCount = primProc.numAttribs();
     if (vaCount > 0) {
 
-        GrGLsizei stride = static_cast<GrGLsizei>(primProc->getVertexStride());
+        GrGLsizei stride = static_cast<GrGLsizei>(primProc.getVertexStride());
 
         size_t vertexOffsetInBytes = stride * info.startVertex();
 
@@ -1414,7 +1414,7 @@
         size_t offset = 0;
 
         for (int attribIndex = 0; attribIndex < vaCount; attribIndex++) {
-            const GrGeometryProcessor::Attribute& attrib = primProc->getAttrib(attribIndex);
+            const GrGeometryProcessor::Attribute& attrib = primProc.getAttrib(attribIndex);
             usedAttribArraysMask |= (1 << attribIndex);
             GrVertexAttribType attribType = attrib.fType;
             attribState->set(this,
@@ -1431,11 +1431,14 @@
     }
 }
 
-void GrGLGpu::buildProgramDesc(const GrOptDrawState& optState,
+void GrGLGpu::buildProgramDesc(GrProgramDesc* desc,
+                               const GrPrimitiveProcessor& primProc,
+                               const GrOptDrawState& optState,
                                const GrProgramDesc::DescInfo& descInfo,
                                GrGpu::DrawType drawType,
-                               GrProgramDesc* desc) {
-    if (!GrGLProgramDescBuilder::Build(optState, descInfo, drawType, this, desc)) {
+                               const GrBatchTracker& batchTracker) const {
+    if (!GrGLProgramDescBuilder::Build(desc, primProc, optState, descInfo, drawType, this,
+                                       batchTracker)) {
         SkDEBUGFAIL("Failed to generate GL program descriptor");
     }
 }
@@ -1823,13 +1826,13 @@
     #endif
 #endif
 
-void GrGLGpu::onDraw(const GrOptDrawState& ds, const GrDrawTarget::DrawInfo& info) {
-    if (!this->flushGLState(ds)) {
+void GrGLGpu::onDraw(const DrawArgs& args, const GrDrawTarget::DrawInfo& info) {
+    if (!this->flushGLState(args)) {
         return;
     }
 
-    size_t indexOffsetInBytes;
-    this->setupGeometry(ds, info, &indexOffsetInBytes);
+    size_t indexOffsetInBytes = 0;
+    this->setupGeometry(*args.fPrimitiveProcessor, info, &indexOffsetInBytes);
 
     SkASSERT((size_t)info.primitiveType() < SK_ARRAY_COUNT(gPrimitiveType2GLMode));
 
@@ -1875,15 +1878,15 @@
     fPathRendering->stencilPath(path, *state.fStencil);
 }
 
-void GrGLGpu::onDrawPath(const GrOptDrawState& ds, const GrPath* path,
+void GrGLGpu::onDrawPath(const DrawArgs& args, const GrPath* path,
                          const GrStencilSettings& stencil) {
-    if (!this->flushGLState(ds)) {
+    if (!this->flushGLState(args)) {
         return;
     }
     fPathRendering->drawPath(path, stencil);
 }
 
-void GrGLGpu::onDrawPaths(const GrOptDrawState& ds,
+void GrGLGpu::onDrawPaths(const DrawArgs& args,
                           const GrPathRange* pathRange,
                           const void* indices,
                           GrDrawTarget::PathIndexType indexType,
@@ -1891,7 +1894,7 @@
                           GrDrawTarget::PathTransformType transformType,
                            int count,
                            const GrStencilSettings& stencil) {
-    if (!this->flushGLState(ds)) {
+    if (!this->flushGLState(args)) {
         return;
     }
     fPathRendering->drawPaths(pathRange, indices, indexType, transformValues,
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 88cf6f6..d63c105 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -104,11 +104,12 @@
                         const SkIRect& srcRect,
                         const SkIPoint& dstPoint) SK_OVERRIDE;
 
-protected:
-    void buildProgramDesc(const GrOptDrawState&,
+    void buildProgramDesc(GrProgramDesc*,
+                          const GrPrimitiveProcessor&,
+                          const GrOptDrawState&,
                           const GrProgramDesc::DescInfo&,
                           GrGpu::DrawType,
-                          GrProgramDesc*) SK_OVERRIDE;
+                          const GrBatchTracker&) const SK_OVERRIDE;
 
 private:
     // GrGpu overrides
@@ -145,10 +146,10 @@
 
     void onResolveRenderTarget(GrRenderTarget* target) SK_OVERRIDE;
 
-    void onDraw(const GrOptDrawState&, const GrDrawTarget::DrawInfo&) SK_OVERRIDE;
+    void onDraw(const DrawArgs&, const GrDrawTarget::DrawInfo&) SK_OVERRIDE;
     void onStencilPath(const GrPath*, const StencilPathState&) SK_OVERRIDE;
-    void onDrawPath(const GrOptDrawState&, const GrPath*, const GrStencilSettings&) SK_OVERRIDE;
-    void onDrawPaths(const GrOptDrawState&,
+    void onDrawPath(const DrawArgs&, const GrPath*, const GrStencilSettings&) SK_OVERRIDE;
+    void onDrawPaths(const DrawArgs&,
                      const GrPathRange*,
                      const void* indices,
                      GrDrawTarget::PathIndexType,
@@ -167,12 +168,12 @@
     void setTextureUnit(int unitIdx);
 
     // Flushes state from GrOptDrawState to GL. Returns false if the state couldn't be set.
-    bool flushGLState(const GrOptDrawState&);
+    bool flushGLState(const DrawArgs&);
 
     // Sets up vertex attribute pointers and strides. On return indexOffsetInBytes gives the offset
     // an into the index buffer. It does not account for drawInfo.startIndex() but rather the start
     // index is relative to the returned offset.
-    void setupGeometry(const GrOptDrawState&,
+    void setupGeometry(const GrPrimitiveProcessor&,
                        const GrDrawTarget::DrawInfo& info,
                        size_t* indexOffsetInBytes);
 
@@ -189,7 +190,7 @@
         ~ProgramCache();
 
         void abandon();
-        GrGLProgram* getProgram(const GrOptDrawState&);
+        GrGLProgram* getProgram(const DrawArgs&);
 
     private:
         enum {
diff --git a/src/gpu/gl/GrGLGpuProgramCache.cpp b/src/gpu/gl/GrGLGpuProgramCache.cpp
index a920221..3e20047 100644
--- a/src/gpu/gl/GrGLGpuProgramCache.cpp
+++ b/src/gpu/gl/GrGLGpuProgramCache.cpp
@@ -91,28 +91,28 @@
     return SkTSearch(fEntries, fCount, desc, sizeof(Entry*), less);
 }
 
-GrGLProgram* GrGLGpu::ProgramCache::getProgram(const GrOptDrawState& optState) {
+GrGLProgram* GrGLGpu::ProgramCache::getProgram(const DrawArgs& args) {
 #ifdef PROGRAM_CACHE_STATS
     ++fTotalRequests;
 #endif
 
     Entry* entry = NULL;
 
-    uint32_t hashIdx = optState.programDesc().getChecksum();
+    uint32_t hashIdx = args.fDesc->getChecksum();
     hashIdx ^= hashIdx >> 16;
     if (kHashBits <= 8) {
         hashIdx ^= hashIdx >> 8;
     }
     hashIdx &=((1 << kHashBits) - 1);
     Entry* hashedEntry = fHashTable[hashIdx];
-    if (hashedEntry && hashedEntry->fProgram->getDesc() == optState.programDesc()) {
+    if (hashedEntry && hashedEntry->fProgram->getDesc() == *args.fDesc) {
         SkASSERT(hashedEntry->fProgram);
         entry = hashedEntry;
     }
 
     int entryIdx;
     if (NULL == entry) {
-        entryIdx = this->search(optState.programDesc());
+        entryIdx = this->search(*args.fDesc);
         if (entryIdx >= 0) {
             entry = fEntries[entryIdx];
 #ifdef PROGRAM_CACHE_STATS
@@ -126,7 +126,7 @@
 #ifdef PROGRAM_CACHE_STATS
         ++fCacheMisses;
 #endif
-        GrGLProgram* program = GrGLProgramBuilder::CreateProgram(optState, fGpu);
+        GrGLProgram* program = GrGLProgramBuilder::CreateProgram(args, fGpu);
         if (NULL == program) {
             return NULL;
         }
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index e1f0310..bd36e59 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -103,8 +103,9 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void GrGLProgram::setData(const GrOptDrawState& optState) {
-    this->setRenderTargetState(optState);
+void GrGLProgram::setData(const GrPrimitiveProcessor& primProc, const GrOptDrawState& optState,
+                          const GrBatchTracker& batchTracker) {
+    this->setRenderTargetState(primProc, optState);
 
     const GrDeviceCoordTexture* dstCopy = optState.getDstCopy();
     if (dstCopy) {
@@ -130,9 +131,7 @@
 
     // we set the textures, and uniforms for installed processors in a generic way, but subclasses
     // of GLProgram determine how to set coord transforms
-    const GrPrimitiveProcessor& primProc = *optState.getPrimitiveProcessor();
-    const GrBatchTracker& bt = optState.getBatchTracker();
-    fGeometryProcessor->fGLProc->setData(fProgramDataManager, primProc, bt);
+    fGeometryProcessor->fGLProc->setData(fProgramDataManager, primProc, batchTracker);
     this->bindTextures(fGeometryProcessor.get(), primProc);
 
     if (fXferProcessor.get()) {
@@ -140,26 +139,27 @@
         fXferProcessor->fGLProc->setData(fProgramDataManager, xp);
         this->bindTextures(fXferProcessor.get(), xp);
     }
-    this->setFragmentData(optState);
+    this->setFragmentData(primProc, optState);
 
     // Some of GrGLProgram subclasses need to update state here
     this->didSetData(optState.drawType());
 }
 
-void GrGLProgram::setFragmentData(const GrOptDrawState& optState) {
+void GrGLProgram::setFragmentData(const GrPrimitiveProcessor& primProc,
+                                  const GrOptDrawState& optState) {
     int numProcessors = fFragmentProcessors->fProcs.count();
     for (int e = 0; e < numProcessors; ++e) {
         const GrPendingFragmentStage& stage = optState.getFragmentStage(e);
         const GrProcessor& processor = *stage.processor();
         fFragmentProcessors->fProcs[e]->fGLProc->setData(fProgramDataManager, processor);
-        this->setTransformData(optState.getPrimitiveProcessor(),
+        this->setTransformData(primProc,
                                stage,
                                e,
                                fFragmentProcessors->fProcs[e]);
         this->bindTextures(fFragmentProcessors->fProcs[e], processor);
     }
 }
-void GrGLProgram::setTransformData(const GrPrimitiveProcessor* primProc,
+void GrGLProgram::setTransformData(const GrPrimitiveProcessor& primProc,
                                    const GrPendingFragmentStage& processor,
                                    int index,
                                    GrGLInstalledFragProc* ip) {
@@ -173,7 +173,8 @@
     SkASSERT(!GrGpu::IsPathRenderingDrawType(drawType));
 }
 
-void GrGLProgram::setRenderTargetState(const GrOptDrawState& optState) {
+void GrGLProgram::setRenderTargetState(const GrPrimitiveProcessor& primProc,
+                                       const GrOptDrawState& optState) {
     // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
     if (fBuiltinUniformHandles.fRTHeightUni.isValid() &&
         fRenderTargetState.fRenderTargetSize.fHeight != optState.getRenderTarget()->height()) {
@@ -182,10 +183,11 @@
     }
 
     // call subclasses to set the actual view matrix
-    this->onSetRenderTargetState(optState);
+    this->onSetRenderTargetState(primProc, optState);
 }
 
-void GrGLProgram::onSetRenderTargetState(const GrOptDrawState& optState) {
+void GrGLProgram::onSetRenderTargetState(const GrPrimitiveProcessor&,
+                                         const GrOptDrawState& optState) {
     const GrRenderTarget* rt = optState.getRenderTarget();
     SkISize size;
     size.set(rt->width(), rt->height());
@@ -220,7 +222,7 @@
     pathProc->didSetData(fGpu->glPathRendering());
 }
 
-void GrGLNvprProgram::setTransformData(const GrPrimitiveProcessor* primProc,
+void GrGLNvprProgram::setTransformData(const GrPrimitiveProcessor& primProc,
                                        const GrPendingFragmentStage& proc,
                                        int index,
                                        GrGLInstalledFragProc* ip) {
@@ -230,13 +232,13 @@
                                fGpu->glPathRendering(), fProgramID);
 }
 
-void GrGLNvprProgram::onSetRenderTargetState(const GrOptDrawState& optState) {
+void GrGLNvprProgram::onSetRenderTargetState(const GrPrimitiveProcessor& primProc,
+                                             const GrOptDrawState& optState) {
     SkASSERT(GrGpu::IsPathRenderingDrawType(optState.drawType()) &&
-             !optState.getPrimitiveProcessor()->willUseGeoShader() &&
-             optState.getPrimitiveProcessor()->numAttribs() == 0);
+             !primProc.willUseGeoShader() && primProc.numAttribs() == 0);
     const GrRenderTarget* rt = optState.getRenderTarget();
     SkISize size;
     size.set(rt->width(), rt->height());
-    fGpu->glPathRendering()->setProjectionMatrix(optState.getPrimitiveProcessor()->viewMatrix(),
+    fGpu->glPathRendering()->setProjectionMatrix(primProc.viewMatrix(),
                                                  size, rt->origin());
 }
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index cd4aa96..bd4d6a3 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -95,7 +95,7 @@
      * GrGLGpu object to bind the textures required by the GrGLProcessors. The color and coverage
      * stages come from GrGLProgramDesc::Build().
      */
-    void setData(const GrOptDrawState&);
+    void setData(const GrPrimitiveProcessor&, const GrOptDrawState&, const GrBatchTracker&);
 
 protected:
     typedef GrGLProgramDataManager::UniformHandle UniformHandle;
@@ -116,8 +116,8 @@
     void initSamplers(Proc*, int* texUnitIdx);
 
     // A templated helper to loop over effects, set the transforms(via subclass) and bind textures
-    void setFragmentData(const GrOptDrawState&);
-    virtual void setTransformData(const GrPrimitiveProcessor*,
+    void setFragmentData(const GrPrimitiveProcessor&, const GrOptDrawState&);
+    virtual void setTransformData(const GrPrimitiveProcessor&,
                                   const GrPendingFragmentStage&,
                                   int index,
                                   GrGLInstalledFragProc*);
@@ -131,8 +131,8 @@
     virtual void didSetData(GrGpu::DrawType);
 
     // Helper for setData() that sets the view matrix and loads the render target height uniform
-    void setRenderTargetState(const GrOptDrawState&);
-    virtual void onSetRenderTargetState(const GrOptDrawState&);
+    void setRenderTargetState(const GrPrimitiveProcessor&, const GrOptDrawState&);
+    virtual void onSetRenderTargetState(const GrPrimitiveProcessor&, const GrOptDrawState&);
 
     // these reflect the current values of uniforms (GL uniform values travel with program)
     RenderTargetState fRenderTargetState;
@@ -176,11 +176,11 @@
 
 private:
     void didSetData(GrGpu::DrawType) SK_OVERRIDE;
-    virtual void setTransformData(const GrPrimitiveProcessor*,
+    virtual void setTransformData(const GrPrimitiveProcessor&,
                                   const GrPendingFragmentStage&,
                                   int index,
                                   GrGLInstalledFragProc*) SK_OVERRIDE;
-    virtual void onSetRenderTargetState(const GrOptDrawState&);
+    virtual void onSetRenderTargetState(const GrPrimitiveProcessor&, const GrOptDrawState&);
 
     friend class GrGLNvprProgramBuilder;
 
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index 299e047..243be01 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -86,11 +86,13 @@
     return true;
 }
 
-bool GrGLProgramDescBuilder::Build(const GrOptDrawState& optState,
+bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
+                                   const GrPrimitiveProcessor& primProc,
+                                   const GrOptDrawState& optState,
                                    const GrProgramDesc::DescInfo& descInfo,
                                    GrGpu::DrawType drawType,
-                                   GrGLGpu* gpu,
-                                   GrProgramDesc* desc) {
+                                   const GrGLGpu* gpu,
+                                   const GrBatchTracker& batchTracker) {
     // The descriptor is used as a cache key. Thus when a field of the
     // descriptor will not affect program generation (because of the attribute
     // bindings in use or other descriptor field settings) it should be set
@@ -103,8 +105,7 @@
 
     GrProcessorKeyBuilder b(&desc->fKey);
 
-    const GrPrimitiveProcessor& primProc = *optState.getPrimitiveProcessor();
-    primProc.getGLProcessorKey(optState.getBatchTracker(), gpu->glCaps(), &b);
+    primProc.getGLProcessorKey(batchTracker, gpu->glCaps(), &b);
     if (!get_meta_key(primProc, gpu->glCaps(), 0, &b)) {
         desc->fKey.reset();
         return false;
diff --git a/src/gpu/gl/GrGLProgramDesc.h b/src/gpu/gl/GrGLProgramDesc.h
index edf139e..3b8093d 100644
--- a/src/gpu/gl/GrGLProgramDesc.h
+++ b/src/gpu/gl/GrGLProgramDesc.h
@@ -41,6 +41,7 @@
     /**
      * Builds a GL specific program descriptor
      *
+     * @param GrPrimitiveProcessor The geometry
      * @param GrOptDrawState  The optimized drawstate.  The descriptor will represent a program
      *                        which this optstate can use to draw with.  The optstate contains
      *                        general draw information, as well as the specific color, geometry,
@@ -55,11 +56,13 @@
      *                              supported
      * @param GrProgramDesc  The built and finalized descriptor
      **/
-    static bool Build(const GrOptDrawState&,
+    static bool Build(GrProgramDesc*,
+                      const GrPrimitiveProcessor&,
+                      const GrOptDrawState&,
                       const GrProgramDesc::DescInfo&,
                       GrGpu::DrawType,
-                      GrGLGpu*,
-                      GrProgramDesc*);
+                      const GrGLGpu*,
+                      const GrBatchTracker&);
 };
 
 #endif
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index c88efac..e81c079 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -24,8 +24,8 @@
 
 class GrGLNvprProgramBuilder : public GrGLProgramBuilder {
 public:
-    GrGLNvprProgramBuilder(GrGLGpu* gpu, const GrOptDrawState& optState)
-        : INHERITED(gpu, optState) {}
+    GrGLNvprProgramBuilder(GrGLGpu* gpu, const DrawArgs& args)
+        : INHERITED(gpu, args) {}
 
     GrGLProgram* createProgram(GrGLuint programID) SK_OVERRIDE {
         // this is just for nvpr es, which has separable varyings that are plugged in after
@@ -33,7 +33,8 @@
         GrGLPathProcessor* pathProc =
                 static_cast<GrGLPathProcessor*>(fGeometryProcessor->fGLProc.get());
         pathProc->resolveSeparableVaryings(fGpu, programID);
-        return SkNEW_ARGS(GrGLNvprProgram, (fGpu, fDesc, fUniformHandles, programID, fUniforms,
+        return SkNEW_ARGS(GrGLNvprProgram, (fGpu, this->desc(), fUniformHandles, programID,
+                                            fUniforms,
                                             fGeometryProcessor,
                                             fXferProcessor, fFragmentProcessors.get()));
     }
@@ -48,10 +49,10 @@
 
 const int GrGLProgramBuilder::kVarsPerBlock = 8;
 
-GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrOptDrawState& optState, GrGLGpu* gpu) {
+GrGLProgram* GrGLProgramBuilder::CreateProgram(const DrawArgs& args, GrGLGpu* gpu) {
     // create a builder.  This will be handed off to effects so they can use it to add
     // uniforms, varyings, textures, etc
-    SkAutoTDelete<GrGLProgramBuilder> builder(CreateProgramBuilder(optState, gpu));
+    SkAutoTDelete<GrGLProgramBuilder> builder(CreateProgramBuilder(args, gpu));
 
     GrGLProgramBuilder* pb = builder.get();
 
@@ -71,30 +72,29 @@
     return pb->finalize();
 }
 
-GrGLProgramBuilder* GrGLProgramBuilder::CreateProgramBuilder(const GrOptDrawState& optState,
+GrGLProgramBuilder* GrGLProgramBuilder::CreateProgramBuilder(const DrawArgs& args,
                                                              GrGLGpu* gpu) {
-    if (GrGpu::IsPathRenderingDrawType(optState.drawType())) {
+    if (GrGpu::IsPathRenderingDrawType(args.fOptState->drawType())) {
         SkASSERT(gpu->glCaps().pathRenderingSupport() &&
-                 !optState.getPrimitiveProcessor()->willUseGeoShader() &&
-                 optState.getPrimitiveProcessor()->numAttribs() == 0);
-        return SkNEW_ARGS(GrGLNvprProgramBuilder, (gpu, optState));
+                 !args.fPrimitiveProcessor->willUseGeoShader() &&
+                 args.fPrimitiveProcessor->numAttribs() == 0);
+        return SkNEW_ARGS(GrGLNvprProgramBuilder, (gpu, args));
     } else {
-        return SkNEW_ARGS(GrGLProgramBuilder, (gpu, optState));
+        return SkNEW_ARGS(GrGLProgramBuilder, (gpu, args));
     }
 }
 
 /////////////////////////////////////////////////////////////////////////////
 
-GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const GrOptDrawState& optState)
+GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const DrawArgs& args)
     : fVS(this)
     , fGS(this)
-    , fFS(this, optState.programDesc().header().fFragPosKey)
+    , fFS(this, args.fDesc->header().fFragPosKey)
     , fOutOfStage(true)
     , fStageIndex(-1)
     , fGeometryProcessor(NULL)
     , fXferProcessor(NULL)
-    , fOptState(optState)
-    , fDesc(optState.programDesc())
+    , fArgs(args)
     , fGpu(gpu)
     , fUniforms(kVarsPerBlock) {
 }
@@ -106,7 +106,7 @@
     if (varying->vsVarying()) {
         fVS.addVarying(name, varying);
     }
-    if (fOptState.getPrimitiveProcessor()->willUseGeoShader()) {
+    if (this->primitiveProcessor().willUseGeoShader()) {
         fGS.addVarying(name, varying);
     }
     if (varying->fsVarying()) {
@@ -193,22 +193,22 @@
     // First we loop over all of the installed processors and collect coord transforms.  These will
     // be sent to the GrGLPrimitiveProcessor in its emitCode function
     SkSTArray<8, GrGLProcessor::TransformedCoordsArray> outCoords;
-    for (int i = 0; i < fOptState.numFragmentStages(); i++) {
-        const GrFragmentProcessor* processor = fOptState.getFragmentStage(i).processor();
+    for (int i = 0; i < this->optState().numFragmentStages(); i++) {
+        const GrFragmentProcessor* processor = this->optState().getFragmentStage(i).processor();
         SkSTArray<2, const GrCoordTransform*, true>& procCoords = fCoordTransforms.push_back();
         for (int t = 0; t < processor->numTransforms(); t++) {
             procCoords.push_back(&processor->coordTransform(t));
         }
     }
 
-    const GrPrimitiveProcessor& primProc = *fOptState.getPrimitiveProcessor();
+    const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
     this->emitAndInstallProc(primProc, inputColor, inputCoverage);
 
     fFragmentProcessors.reset(SkNEW(GrGLInstalledFragProcs));
-    int numProcs = fOptState.numFragmentStages();
-    this->emitAndInstallFragProcs(0, fOptState.numColorStages(), inputColor);
-    this->emitAndInstallFragProcs(fOptState.numColorStages(), numProcs,  inputCoverage);
-    this->emitAndInstallXferProc(*fOptState.getXferProcessor(), *inputColor, *inputCoverage);
+    int numProcs = this->optState().numFragmentStages();
+    this->emitAndInstallFragProcs(0, this->optState().numColorStages(), inputColor);
+    this->emitAndInstallFragProcs(this->optState().numColorStages(), numProcs,  inputCoverage);
+    this->emitAndInstallXferProc(*this->optState().getXferProcessor(), *inputColor, *inputCoverage);
 }
 
 void GrGLProgramBuilder::emitAndInstallFragProcs(int procOffset,
@@ -216,7 +216,7 @@
                                                  GrGLSLExpr4* inOut) {
     for (int e = procOffset; e < numProcs; ++e) {
         GrGLSLExpr4 output;
-        const GrPendingFragmentStage& stage = fOptState.getFragmentStage(e);
+        const GrPendingFragmentStage& stage = this->optState().getFragmentStage(e);
         this->emitAndInstallProc(stage, e, *inOut, &output);
         *inOut = output;
     }
@@ -300,7 +300,7 @@
     SkASSERT(!fGeometryProcessor);
     fGeometryProcessor = SkNEW(GrGLInstalledGeoProc);
 
-    const GrBatchTracker& bt = fOptState.getBatchTracker();
+    const GrBatchTracker& bt = this->batchTracker();
     fGeometryProcessor->fGLProc.reset(gp.createGLInstance(bt, fGpu->glCaps()));
 
     SkSTArray<4, GrGLProcessor::TextureSampler> samplers(gp.numTextures());
@@ -396,7 +396,7 @@
 
     // Legacy nvpr will not compile with a vertex shader, but newer nvpr requires a dummy vertex
     // shader
-    bool useNvpr = GrGpu::IsPathRenderingDrawType(fOptState.drawType());
+    bool useNvpr = GrGpu::IsPathRenderingDrawType(this->optState().drawType());
     if (!(useNvpr && fGpu->glCaps().nvprSupport() == GrGLCaps::kLegacy_NvprSupport)) {
         if (!fVS.compileAndAttachShaders(programID, &shadersToDelete)) {
             this->cleanupProgram(programID, shadersToDelete);
@@ -490,7 +490,7 @@
 }
 
 GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
-    return SkNEW_ARGS(GrGLProgram, (fGpu, fDesc, fUniformHandles, programID, fUniforms,
+    return SkNEW_ARGS(GrGLProgram, (fGpu, this->desc(), fUniformHandles, programID, fUniforms,
                                     fGeometryProcessor, fXferProcessor, fFragmentProcessors.get()));
 }
 
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h
index ddca6e6..612791e 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.h
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.h
@@ -219,6 +219,7 @@
                            public GrGLFPBuilder,
                            public GrGLXPBuilder {
 public:
+    typedef GrGpu::DrawArgs DrawArgs;
     /** Generates a shader program.
      *
      * The program implements what is specified in the stages given as input.
@@ -226,7 +227,7 @@
      * to be used.
      * @return true if generation was successful.
      */
-    static GrGLProgram* CreateProgram(const GrOptDrawState&, GrGLGpu*);
+    static GrGLProgram* CreateProgram(const DrawArgs&, GrGLGpu*);
 
     UniformHandle addUniformArray(uint32_t visibility,
                                   GrSLType type,
@@ -277,13 +278,15 @@
     typedef GrGLProgramDataManager::UniformInfo UniformInfo;
     typedef GrGLProgramDataManager::UniformInfoArray UniformInfoArray;
 
-    static GrGLProgramBuilder* CreateProgramBuilder(const GrOptDrawState&, GrGLGpu*);
+    static GrGLProgramBuilder* CreateProgramBuilder(const DrawArgs&, GrGLGpu*);
 
-    GrGLProgramBuilder(GrGLGpu*, const GrOptDrawState&);
+    GrGLProgramBuilder(GrGLGpu*, const DrawArgs&);
 
-    const GrOptDrawState& optState() const { return fOptState; }
-    const GrProgramDesc& desc() const { return fDesc; }
-    const GrProgramDesc::KeyHeader& header() const { return fDesc.header(); }
+    const GrPrimitiveProcessor& primitiveProcessor() const { return *fArgs.fPrimitiveProcessor; }
+    const GrOptDrawState& optState() const { return *fArgs.fOptState; }
+    const GrProgramDesc& desc() const { return *fArgs.fDesc; }
+    const GrBatchTracker& batchTracker() const { return *fArgs.fBatchTracker; }
+    const GrProgramDesc::KeyHeader& header() const { return fArgs.fDesc->header(); }
 
     // Generates a name for a variable. The generated string will be name prefixed by the prefix
     // char (unless the prefix is '\0'). It also mangles the name to be stage-specific if we're
@@ -383,8 +386,7 @@
     GrGLInstalledXferProc* fXferProcessor;
     SkAutoTUnref<GrGLInstalledFragProcs> fFragmentProcessors;
 
-    const GrOptDrawState& fOptState;
-    const GrProgramDesc& fDesc;
+    const DrawArgs& fArgs;
     GrGLGpu* fGpu;
     UniformInfoArray fUniforms;
     GrGLPrimitiveProcessor::TransformsIn fCoordTransforms;
diff --git a/src/gpu/gl/builders/GrGLVertexShaderBuilder.cpp b/src/gpu/gl/builders/GrGLVertexShaderBuilder.cpp
index a8d0865..f17e741 100644
--- a/src/gpu/gl/builders/GrGLVertexShaderBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLVertexShaderBuilder.cpp
@@ -64,11 +64,11 @@
 }
 
 void GrGLVertexBuilder::bindVertexAttributes(GrGLuint programID) {
-    const GrPrimitiveProcessor* primProc = fProgramBuilder->fOptState.getPrimitiveProcessor();
+    const GrPrimitiveProcessor& primProc = fProgramBuilder->primitiveProcessor();
 
-    int vaCount = primProc->numAttribs();
+    int vaCount = primProc.numAttribs();
     for (int i = 0; i < vaCount; i++) {
-        GL_CALL(BindAttribLocation(programID, i, primProc->getAttrib(i).fName));
+        GL_CALL(BindAttribLocation(programID, i, primProc.getAttrib(i).fName));
     }
     return;
 }