Move state management to GrInOrderDrawBuffer

BUG=skia:

Review URL: https://codereview.chromium.org/1120143002
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index e298be6..76e085d 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -17,6 +17,7 @@
     , fCommands(context->getGpu(), vertexPool, indexPool)
     , fPathIndexBuffer(kPathIdxBufferMinReserve * sizeof(char)/4)
     , fPathTransformBuffer(kPathXformBufferMinReserve * sizeof(float)/4)
+    , fPipelineBuffer(kPipelineBufferMinReserve)
     , fDrawID(0) {
 
     SkASSERT(vertexPool);
@@ -300,7 +301,12 @@
 
 void GrInOrderDrawBuffer::onDrawBatch(GrBatch* batch,
                                       const PipelineInfo& pipelineInfo) {
-    GrTargetCommands::Cmd* cmd = fCommands.recordDrawBatch(this, batch, pipelineInfo);
+    State* state = this->setupPipelineAndShouldDraw(batch, pipelineInfo);
+    if (!state) {
+        return;
+    }
+
+    GrTargetCommands::Cmd* cmd = fCommands.recordDrawBatch(state, batch);
     this->recordTraceMarkersIfNecessary(cmd);
 }
 
@@ -309,7 +315,7 @@
                                         const GrPath* path,
                                         const GrScissorState& scissorState,
                                         const GrStencilSettings& stencilSettings) {
-    GrTargetCommands::Cmd* cmd = fCommands.recordStencilPath(this, pipelineBuilder, 
+    GrTargetCommands::Cmd* cmd = fCommands.recordStencilPath(pipelineBuilder,
                                                              pathProc, path, scissorState,
                                                              stencilSettings);
     this->recordTraceMarkersIfNecessary(cmd);
@@ -319,9 +325,11 @@
                                      const GrPath* path,
                                      const GrStencilSettings& stencilSettings,
                                      const PipelineInfo& pipelineInfo) {
-    GrTargetCommands::Cmd* cmd = fCommands.recordDrawPath(this, pathProc,
-                                                          path, stencilSettings,
-                                                          pipelineInfo);
+    State* state = this->setupPipelineAndShouldDraw(pathProc, pipelineInfo);
+    if (!state) {
+        return;
+    }
+    GrTargetCommands::Cmd* cmd = fCommands.recordDrawPath(state, pathProc, path, stencilSettings);
     this->recordTraceMarkersIfNecessary(cmd);
 }
 
@@ -334,7 +342,11 @@
                                       int count,
                                       const GrStencilSettings& stencilSettings,
                                       const PipelineInfo& pipelineInfo) {
-    GrTargetCommands::Cmd* cmd = fCommands.recordDrawPaths(this, pathProc, pathRange,
+    State* state = this->setupPipelineAndShouldDraw(pathProc, pipelineInfo);
+    if (!state) {
+        return;
+    }
+    GrTargetCommands::Cmd* cmd = fCommands.recordDrawPaths(state, this, pathProc, pathRange,
                                                            indices, indexType, transformValues,
                                                            transformType, count,
                                                            stencilSettings, pipelineInfo);
@@ -343,16 +355,14 @@
 
 void GrInOrderDrawBuffer::onClear(const SkIRect* rect, GrColor color,
                                   bool canIgnoreRect, GrRenderTarget* renderTarget) {
-    GrTargetCommands::Cmd* cmd = fCommands.recordClear(this, rect, color,
-                                                       canIgnoreRect, renderTarget);
+    GrTargetCommands::Cmd* cmd = fCommands.recordClear(rect, color, canIgnoreRect, renderTarget);
     this->recordTraceMarkersIfNecessary(cmd);
 }
 
 void GrInOrderDrawBuffer::clearStencilClip(const SkIRect& rect,
                                            bool insideClip,
                                            GrRenderTarget* renderTarget) {
-    GrTargetCommands::Cmd* cmd = fCommands.recordClearStencilClip(this, rect,
-                                                                  insideClip, renderTarget);
+    GrTargetCommands::Cmd* cmd = fCommands.recordClearStencilClip(rect, insideClip, renderTarget);
     this->recordTraceMarkersIfNecessary(cmd);
 }
 
@@ -361,7 +371,7 @@
         return;
     }
 
-    GrTargetCommands::Cmd* cmd = fCommands.recordDiscard(this, renderTarget);
+    GrTargetCommands::Cmd* cmd = fCommands.recordDiscard(renderTarget);
     this->recordTraceMarkersIfNecessary(cmd);
 }
 
@@ -370,6 +380,15 @@
     fPathIndexBuffer.rewind();
     fPathTransformBuffer.rewind();
     fGpuCmdMarkers.reset();
+
+    fPrevState.reset(NULL);
+    // Note, fPrevState points into fPipelineBuffer's allocation, so we have to reset first.
+    // Furthermore, we have to reset fCommands before fPipelineBuffer too.
+    if (fDrawID % kPipelineBufferHighWaterMark) {
+        fPipelineBuffer.rewind();
+    } else {
+        fPipelineBuffer.reset();
+    }
 }
 
 void GrInOrderDrawBuffer::onFlush() {
@@ -400,3 +419,55 @@
         }
     }
 }
+
+GrTargetCommands::State*
+GrInOrderDrawBuffer::setupPipelineAndShouldDraw(const GrPrimitiveProcessor* primProc,
+                                                const GrDrawTarget::PipelineInfo& pipelineInfo) {
+    State* state = this->allocState();
+    this->setupPipeline(pipelineInfo, state->pipelineLocation());
+
+    if (state->getPipeline()->mustSkip()) {
+        this->unallocState(state);
+        return NULL;
+    }
+
+    state->fPrimitiveProcessor->initBatchTracker(&state->fBatchTracker,
+                                                 state->getPipeline()->getInitBatchTracker());
+
+    if (fPrevState && fPrevState->fPrimitiveProcessor.get() &&
+        fPrevState->fPrimitiveProcessor->canMakeEqual(fPrevState->fBatchTracker,
+                                                      *state->fPrimitiveProcessor,
+                                                      state->fBatchTracker) &&
+        fPrevState->getPipeline()->isEqual(*state->getPipeline())) {
+        this->unallocState(state);
+    } else {
+        fPrevState.reset(state);
+    }
+
+    fCommands.recordXferBarrierIfNecessary(*fPrevState->getPipeline(), this);
+    return fPrevState;
+}
+
+GrTargetCommands::State*
+GrInOrderDrawBuffer::setupPipelineAndShouldDraw(GrBatch* batch,
+                                                const GrDrawTarget::PipelineInfo& pipelineInfo) {
+    State* state = this->allocState();
+    this->setupPipeline(pipelineInfo, state->pipelineLocation());
+
+    if (state->getPipeline()->mustSkip()) {
+        this->unallocState(state);
+        return NULL;
+    }
+
+    batch->initBatchTracker(state->getPipeline()->getInitBatchTracker());
+
+    if (fPrevState && !fPrevState->fPrimitiveProcessor.get() &&
+        fPrevState->getPipeline()->isEqual(*state->getPipeline())) {
+        this->unallocState(state);
+    } else {
+        fPrevState.reset(state);
+    }
+
+    fCommands.recordXferBarrierIfNecessary(*fPrevState->getPipeline(), this);
+    return fPrevState;
+}