Drawstate on stack

BUG=skia:

Review URL: https://codereview.chromium.org/732693002
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index c180cc6..b0504b7 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -133,34 +133,33 @@
 
 static inline bool cmd_has_trace_marker(uint8_t cmd) { return SkToBool(cmd & kTraceCmdBit); }
 
-void GrInOrderDrawBuffer::onDrawRect(const SkRect& rect,
+void GrInOrderDrawBuffer::onDrawRect(GrDrawState* ds,
+                                     const SkRect& rect,
                                      const SkRect* localRect,
                                      const SkMatrix* localMatrix) {
-    GrDrawState* drawState = this->drawState();
-    GrDrawState::AutoRestoreEffects are(drawState);
+    GrDrawState::AutoRestoreEffects are(ds);
 
-    GrColor color = drawState->getColor();
+    GrColor color = ds->getColor();
+    set_vertex_attributes(ds, SkToBool(localRect),  color);
 
-    set_vertex_attributes(drawState, SkToBool(localRect),  color);
-
-    AutoReleaseGeometry geo(this, 4, 0);
+    AutoReleaseGeometry geo(this, 4, ds->getVertexStride(), 0);
     if (!geo.succeeded()) {
         SkDebugf("Failed to get space for vertices!\n");
         return;
     }
 
     // Go to device coords to allow batching across matrix changes
-    SkMatrix matrix = drawState->getViewMatrix();
+    SkMatrix matrix = ds->getViewMatrix();
 
     // When the caller has provided an explicit source rect for a stage then we don't want to
     // modify that stage's matrix. Otherwise if the effect is generating its source rect from
     // the vertex positions then we have to account for the view matrix change.
     GrDrawState::AutoViewMatrixRestore avmr;
-    if (!avmr.setIdentity(drawState)) {
+    if (!avmr.setIdentity(ds)) {
         return;
     }
 
-    size_t vstride = drawState->getVertexStride();
+    size_t vstride = ds->getVertexStride();
 
     geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vstride);
     matrix.mapPointsWithStride(geo.positions(), vstride, 4);
@@ -189,19 +188,16 @@
     }
 
     this->setIndexSourceToBuffer(this->getContext()->getQuadIndexBuffer());
-    this->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6, &devBounds);
-
-    // to ensure that stashing the drawState ptr is valid
-    SkASSERT(this->drawState() == drawState);
+    this->drawIndexedInstances(ds, kTriangles_GrPrimitiveType, 1, 4, 6, &devBounds);
 }
 
-int GrInOrderDrawBuffer::concatInstancedDraw(const DrawInfo& info,
+int GrInOrderDrawBuffer::concatInstancedDraw(const GrDrawState& ds,
+                                             const DrawInfo& info,
                                              const GrClipMaskManager::ScissorState& scissorState) {
     SkASSERT(!fCmdBuffer.empty());
     SkASSERT(info.isInstanced());
 
     const GeometrySrcState& geomSrc = this->getGeomSrc();
-    const GrDrawState& drawState = this->getDrawState();
 
     // we only attempt to concat the case when reserved verts are used with a client-specified index
     // buffer. To make this work with client-specified VBs we'd need to know if the VB was updated
@@ -243,8 +239,7 @@
     instancesToConcat = SkTMin(instancesToConcat, info.instanceCount());
 
     // update the amount of reserved vertex data actually referenced in draws
-    size_t vertexBytes = instancesToConcat * info.verticesPerInstance() *
-                         drawState.getVertexStride();
+    size_t vertexBytes = instancesToConcat * info.verticesPerInstance() * ds.getVertexStride();
     poolState.fUsedPoolVertexBytes = SkTMax(poolState.fUsedPoolVertexBytes, vertexBytes);
 
     draw->fInfo.adjustInstanceCount(instancesToConcat);
@@ -262,12 +257,13 @@
     return instancesToConcat;
 }
 
-void GrInOrderDrawBuffer::onDraw(const DrawInfo& info,
+void GrInOrderDrawBuffer::onDraw(const GrDrawState& ds,
+                                 const DrawInfo& info,
                                  const GrClipMaskManager::ScissorState& scissorState) {
     GeometryPoolState& poolState = fGeoPoolStateStack.back();
-    const GrDrawState& drawState = this->getDrawState();
 
-    this->recordStateIfNecessary(GrGpu::PrimTypeToDrawType(info.primitiveType()),
+    this->recordStateIfNecessary(ds,
+                                 GrGpu::PrimTypeToDrawType(info.primitiveType()),
                                  info.getDstCopy());
 
     const GrVertexBuffer* vb;
@@ -288,7 +284,7 @@
 
     Draw* draw;
     if (info.isInstanced()) {
-        int instancesConcated = this->concatInstancedDraw(info, scissorState);
+        int instancesConcated = this->concatInstancedDraw(ds, info, scissorState);
         if (info.instanceCount() > instancesConcated) {
             draw = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, Draw, (info, scissorState, vb, ib));
             draw->fInfo.adjustInstanceCount(-instancesConcated);
@@ -303,7 +299,7 @@
     // Adjust the starting vertex and index when we are using reserved or array sources to
     // compensate for the fact that the data was inserted into a larger vb/ib owned by the pool.
     if (kBuffer_GeometrySrcType != this->getGeomSrc().fVertexSrc) {
-        size_t bytes = (info.vertexCount() + info.startVertex()) * drawState.getVertexStride();
+        size_t bytes = (info.vertexCount() + info.startVertex()) * ds.getVertexStride();
         poolState.fUsedPoolVertexBytes = SkTMax(poolState.fUsedPoolVertexBytes, bytes);
         draw->fInfo.adjustStartVertex(poolState.fPoolStartVertex);
     }
@@ -315,23 +311,25 @@
     }
 }
 
-void GrInOrderDrawBuffer::onStencilPath(const GrPath* path,
+void GrInOrderDrawBuffer::onStencilPath(const GrDrawState& ds,
+                                        const GrPath* path,
                                         const GrClipMaskManager::ScissorState& scissorState,
                                         const GrStencilSettings& stencilSettings) {
     // Only compare the subset of GrDrawState relevant to path stenciling?
-    this->recordStateIfNecessary(GrGpu::kStencilPath_DrawType, NULL);
+    this->recordStateIfNecessary(ds, GrGpu::kStencilPath_DrawType, NULL);
     StencilPath* sp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, StencilPath, (path));
     sp->fScissorState = scissorState;
     sp->fStencilSettings = stencilSettings;
     this->recordTraceMarkersIfNecessary();
 }
 
-void GrInOrderDrawBuffer::onDrawPath(const GrPath* path,
+void GrInOrderDrawBuffer::onDrawPath(const GrDrawState& ds,
+                                     const GrPath* path,
                                      const GrClipMaskManager::ScissorState& scissorState,
                                      const GrStencilSettings& stencilSettings,
                                      const GrDeviceCoordTexture* dstCopy) {
     // TODO: Only compare the subset of GrDrawState relevant to path covering?
-    this->recordStateIfNecessary(GrGpu::kDrawPath_DrawType, dstCopy);
+    this->recordStateIfNecessary(ds, GrGpu::kDrawPath_DrawType, dstCopy);
     DrawPath* dp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawPath, (path));
     if (dstCopy) {
         dp->fDstCopy = *dstCopy;
@@ -341,7 +339,8 @@
     this->recordTraceMarkersIfNecessary();
 }
 
-void GrInOrderDrawBuffer::onDrawPaths(const GrPathRange* pathRange,
+void GrInOrderDrawBuffer::onDrawPaths(const GrDrawState& ds,
+                                      const GrPathRange* pathRange,
                                       const uint32_t indices[],
                                       int count,
                                       const float transforms[],
@@ -353,7 +352,7 @@
     SkASSERT(indices);
     SkASSERT(transforms);
 
-    this->recordStateIfNecessary(GrGpu::kDrawPaths_DrawType, dstCopy);
+    this->recordStateIfNecessary(ds, GrGpu::kDrawPaths_DrawType, dstCopy);
 
     uint32_t* savedIndices = fPathIndexBuffer.append(count, indices);
     float* savedTransforms = fPathTransformBuffer.append(count *
@@ -373,7 +372,7 @@
             scissorState == previous->fScissorState &&
             stencilSettings == previous->fStencilSettings &&
             path_fill_type_is_winding(stencilSettings) &&
-            !this->getDrawState().willBlendWithDst()) {
+            !ds.willBlendWithDst()) {
             // Fold this DrawPaths call into the one previous.
             previous->fCount += count;
             return;
@@ -396,11 +395,8 @@
 
 void GrInOrderDrawBuffer::onClear(const SkIRect* rect, GrColor color,
                                   bool canIgnoreRect, GrRenderTarget* renderTarget) {
+    SkASSERT(renderTarget);
     SkIRect r;
-    if (NULL == renderTarget) {
-        renderTarget = this->drawState()->getRenderTarget();
-        SkASSERT(renderTarget);
-    }
     if (NULL == rect) {
         // We could do something smart and remove previous draws and clears to
         // the current render target. If we get that smart we have to make sure
@@ -419,10 +415,7 @@
 void GrInOrderDrawBuffer::clearStencilClip(const SkIRect& rect,
                                            bool insideClip,
                                            GrRenderTarget* renderTarget) {
-    if (NULL == renderTarget) {
-        renderTarget = this->drawState()->getRenderTarget();
-        SkASSERT(renderTarget);
-    }
+    SkASSERT(renderTarget);
     ClearStencilClip* clr = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, ClearStencilClip, (renderTarget));
     clr->fRect = rect;
     clr->fInsideClip = insideClip;
@@ -493,7 +486,7 @@
         }
 
         if (kSetState_Cmd == strip_trace_bit(iter->fType)) {
-            const SetState* ss = reinterpret_cast<const SetState*>(iter.get());
+            SetState* ss = reinterpret_cast<SetState*>(iter.get());
             currentOptState.reset(GrOptDrawState::Create(ss->fState,
                                                          fDstGpu,
                                                          &ss->fDstCopy,
@@ -592,8 +585,8 @@
     }
 }
 
-bool GrInOrderDrawBuffer::canCopySurface(GrSurface* dst,
-                                         GrSurface* src,
+bool GrInOrderDrawBuffer::canCopySurface(const GrSurface* dst,
+                                         const GrSurface* src,
                                          const SkIRect& srcRect,
                                          const SkIPoint& dstPoint) {
     return fDstGpu->canCopySurface(dst, src, srcRect, dstPoint) ||
@@ -605,6 +598,7 @@
 }
 
 void GrInOrderDrawBuffer::willReserveVertexAndIndexSpace(int vertexCount,
+                                                         size_t vertexStride,
                                                          int indexCount) {
     // We use geometryHints() to know whether to flush the draw buffer. We
     // can't flush if we are inside an unbalanced pushGeometrySource.
@@ -628,12 +622,13 @@
     if (!insideGeoPush &&
         !unreleasedVertexSpace &&
         !unreleasedIndexSpace &&
-        this->geometryHints(&vcount, &icount)) {
+        this->geometryHints(vertexStride, &vcount, &icount)) {
         this->flush();
     }
 }
 
-bool GrInOrderDrawBuffer::geometryHints(int* vertexCount,
+bool GrInOrderDrawBuffer::geometryHints(size_t vertexStride,
+                                        int* vertexCount,
                                         int* indexCount) const {
     // we will recommend a flush if the data could fit in a single
     // preallocated buffer but none are left and it can't fit
@@ -650,7 +645,6 @@
         *indexCount = currIndices;
     }
     if (vertexCount) {
-        size_t vertexStride = this->getDrawState().getVertexStride();
         int32_t currVertices = fVertexPool.currentBufferVertices(vertexStride);
         if (*vertexCount > currVertices &&
             (!fVertexPool.preallocatedBuffersRemaining() &&
@@ -753,10 +747,11 @@
     }
 }
 
-void GrInOrderDrawBuffer::recordStateIfNecessary(GrGpu::DrawType drawType,
+void GrInOrderDrawBuffer::recordStateIfNecessary(const GrDrawState& ds,
+                                                 GrGpu::DrawType drawType,
                                                  const GrDeviceCoordTexture* dstCopy) {
     if (!fLastState) {
-        SetState* ss = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, SetState, (this->getDrawState()));
+        SetState* ss = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, SetState, (ds));
         fLastState = &ss->fState;
         if (dstCopy) {
             ss->fDstCopy = *dstCopy;
@@ -766,10 +761,9 @@
         this->recordTraceMarkersIfNecessary();
         return;
     }
-    const GrDrawState& curr = this->getDrawState();
-    switch (GrDrawState::CombineIfPossible(*fLastState, curr, *this->caps())) {
+    switch (GrDrawState::CombineIfPossible(*fLastState, ds, *this->caps())) {
         case GrDrawState::kIncompatible_CombinedState: {
-            SetState* ss = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, SetState, (curr));
+            SetState* ss = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, SetState, (ds));
             fLastState = &ss->fState;
             if (dstCopy) {
                 ss->fDstCopy = *dstCopy;
@@ -788,7 +782,7 @@
             // Note that this goes away when we move GrIODB over to taking optimized snapshots
             // of draw states.
             fLastState->~GrDrawState();
-            SkNEW_PLACEMENT_ARGS(fLastState, GrDrawState, (curr));
+            SkNEW_PLACEMENT_ARGS(fLastState, GrDrawState, (ds));
             this->convertDrawStateToPendingExec(fLastState);
             break;
     }