Move bounds to GrBatch

BUG=skia:

Review URL: https://codereview.chromium.org/1121463002
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index f031f7f..3a548aa 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -847,6 +847,10 @@
     AAConvexPathBatch(const Geometry& geometry) {
         this->initClassID<AAConvexPathBatch>();
         fGeoData.push_back(geometry);
+
+        // compute bounds
+        fBounds = geometry.fPath.getBounds();
+        geometry.fViewMatrix.mapRect(&fBounds);
     }
 
     bool onCombineIfPossible(GrBatch* t) override {
@@ -862,6 +866,7 @@
         }
 
         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
+        this->joinBounds(that->bounds());
         return true;
     }
 
@@ -891,19 +896,13 @@
         return true;
     }
 
-    // We outset our vertices one pixel and add one more pixel for precision.
-    // TODO create tighter bounds when we start reordering.
-    SkRect devRect = path.getBounds();
-    vm.mapRect(&devRect);
-    devRect.outset(2, 2);
-
     AAConvexPathBatch::Geometry geometry;
     geometry.fColor = color;
     geometry.fViewMatrix = vm;
     geometry.fPath = path;
 
     SkAutoTUnref<GrBatch> batch(AAConvexPathBatch::Create(geometry));
-    target->drawBatch(pipelineBuilder, batch, &devRect);
+    target->drawBatch(pipelineBuilder, batch);
 
     return true;
 
diff --git a/src/gpu/GrAADistanceFieldPathRenderer.cpp b/src/gpu/GrAADistanceFieldPathRenderer.cpp
index f0b6c77..669ec09 100755
--- a/src/gpu/GrAADistanceFieldPathRenderer.cpp
+++ b/src/gpu/GrAADistanceFieldPathRenderer.cpp
@@ -312,6 +312,10 @@
         fAtlas = atlas;
         fPathCache = pathCache;
         fPathList = pathList;
+
+        // Compute bounds
+        fBounds = geometry.fPath.getBounds();
+        viewMatrix.mapRect(&fBounds);
     }
 
     bool addPathToAtlas(GrBatchTarget* batchTarget,
@@ -548,6 +552,7 @@
         }
 
         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
+        this->joinBounds(that->bounds());
         return true;
     }
 
@@ -607,10 +612,7 @@
 
     SkAutoTUnref<GrBatch> batch(AADistanceFieldPathBatch::Create(geometry, color, viewMatrix,
                                                                  fAtlas, &fPathCache, &fPathList));
-
-    SkRect bounds = path.getBounds();
-    viewMatrix.mapRect(&bounds);
-    target->drawBatch(pipelineBuilder, batch, &bounds);
+    target->drawBatch(pipelineBuilder, batch);
 
     return true;
 }
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
index 9ab5c8e..96e0677 100644
--- a/src/gpu/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp
@@ -699,7 +699,6 @@
         uint8_t fCoverage;
         SkMatrix fViewMatrix;
         SkPath fPath;
-        SkDEBUGCODE(SkRect fDevBounds;)
         SkIRect fDevClipBounds;
     };
 
@@ -734,7 +733,6 @@
         fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
         fBatch.fCoverageIgnored = init.fCoverageIgnored;
         fBatch.fCoverage = fGeoData[0].fCoverage;
-        SkDEBUGCODE(fBatch.fDevBounds = fGeoData[0].fDevBounds;)
     }
 
     void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override;
@@ -753,6 +751,10 @@
         SkASSERT(linesIndexBuffer && quadsIndexBuffer);
         this->initClassID<AAHairlineBatch>();
         fGeoData.push_back(geometry);
+
+        // compute bounds
+        fBounds = geometry.fPath.getBounds();
+        geometry.fViewMatrix.mapRect(&fBounds);
     }
 
     bool onCombineIfPossible(GrBatch* t) override {
@@ -785,6 +787,7 @@
         }
 
         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
+        this->joinBounds(that->bounds());
         return true;
     }
 
@@ -1047,23 +1050,16 @@
     pipelineBuilder->clip().getConservativeBounds(pipelineBuilder->getRenderTarget(),
                                                   &devClipBounds);
 
-    // This outset was determined experimentally by running skps and gms.  It probably could be a
-    // bit tighter
-    SkRect devRect = path.getBounds();
-    viewMatrix.mapRect(&devRect);
-    devRect.outset(2, 2);
-
     AAHairlineBatch::Geometry geometry;
     geometry.fColor = color;
     geometry.fCoverage = newCoverage;
     geometry.fViewMatrix = viewMatrix;
     geometry.fPath = path;
-    SkDEBUGCODE(geometry.fDevBounds = devRect;)
     geometry.fDevClipBounds = devClipBounds;
 
     SkAutoTUnref<GrBatch> batch(AAHairlineBatch::Create(geometry, fLinesIndexBuffer,
                                                         fQuadsIndexBuffer));
-    target->drawBatch(pipelineBuilder, batch, &devRect);
+    target->drawBatch(pipelineBuilder, batch);
 
     return true;
 }
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp
index 569466f..5cd112d 100644
--- a/src/gpu/GrAARectRenderer.cpp
+++ b/src/gpu/GrAARectRenderer.cpp
@@ -186,6 +186,8 @@
         : fIndexBuffer(indexBuffer) {
         this->initClassID<AAFillRectBatch>();
         fGeoData.push_back(geometry);
+
+        this->setBounds(geometry.fDevRect);
     }
 
     GrColor color() const { return fBatch.fColor; }
@@ -216,6 +218,7 @@
         }
 
         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
+        this->joinBounds(that->bounds());
         return true;
     }
 
@@ -476,7 +479,7 @@
     geometry.fColor = color;
 
     SkAutoTUnref<GrBatch> batch(AAFillRectBatch::Create(geometry, fAAFillRectIndexBuffer));
-    target->drawBatch(pipelineBuilder, batch, &devRect);
+    target->drawBatch(pipelineBuilder, batch);
 }
 
 void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
@@ -501,14 +504,6 @@
     const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
     const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
 
-    // Temporarily #if'ed out. We don't want to pass in the devRect but
-    // right now it is computed in GrContext::apply_aa_to_rect and we don't
-    // want to throw away the work
-#if 0
-    SkRect devRect;
-    combinedMatrix.mapRect(&devRect, rect);
-#endif
-
     SkScalar spare;
     {
         SkScalar w = devRect.width() - dx;
@@ -693,6 +688,11 @@
         this->initClassID<AAStrokeRectBatch>();
         fBatch.fViewMatrix = viewMatrix;
         fGeoData.push_back(geometry);
+
+        // If we have miterstroke then we inset devOutside and outset devOutsideAssist, so we need
+        // the join for proper bounds
+        fBounds = geometry.fDevOutside;
+        fBounds.join(geometry.fDevOutsideAssist);
     }
 
     GrColor color() const { return fBatch.fColor; }
@@ -727,6 +727,7 @@
             fBatch.fColor = GrColor_ILLEGAL;
         }
         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
+        this->joinBounds(that->bounds());
         return true;
     }
 
diff --git a/src/gpu/GrAtlasTextContext.cpp b/src/gpu/GrAtlasTextContext.cpp
index f1906c3..14930fa 100644
--- a/src/gpu/GrAtlasTextContext.cpp
+++ b/src/gpu/GrAtlasTextContext.cpp
@@ -1721,6 +1721,7 @@
     void init() {
         fBatch.fColor = fGeoData[0].fColor;
         fBatch.fViewMatrix = fGeoData[0].fBlob->fViewMatrix;
+        this->setBounds(fGeoData[0].fBlob->fRuns[fGeoData[0].fRun].fVertexBounds);
     }
 
 private:
@@ -1924,6 +1925,8 @@
             fGeoData[i].fBlob->ref();
         }
         fInstanceCount = total;
+
+        this->joinBounds(that->bounds());
         return true;
     }
 
@@ -2092,7 +2095,7 @@
         geometry.fTransY = transY;
         batch->init();
 
-        target->drawBatch(pipelineBuilder, batch, &cacheBlob->fRuns[run].fVertexBounds);
+        target->drawBatch(pipelineBuilder, batch);
     }
 }
 
diff --git a/src/gpu/GrBatch.h b/src/gpu/GrBatch.h
index 92a9c08..7b5c888 100644
--- a/src/gpu/GrBatch.h
+++ b/src/gpu/GrBatch.h
@@ -38,7 +38,6 @@
  * If there are any possible optimizations which might require knowing more about the full state of
  * the draw, ie whether or not the GrBatch is allowed to tweak alpha for coverage, then this
  * information will be communicated to the GrBatch prior to geometry generation.
- * TODO Batch should own the draw bounds
  */
 
 class GrBatch : public SkRefCnt {
@@ -62,13 +61,15 @@
             return false;
         }
 
-        return onCombineIfPossible(that);
+        return this->onCombineIfPossible(that);
     }
 
     virtual bool onCombineIfPossible(GrBatch*) = 0;
 
     virtual void generateGeometry(GrBatchTarget*, const GrPipeline*) = 0;
 
+    const SkRect& bounds() const { return fBounds; }
+
     // TODO this goes away when batches are everywhere
     void setNumberOfDraws(int numberOfDraws) { fNumberOfDraws = numberOfDraws; }
     int numberOfDraws() const { return fNumberOfDraws; }
@@ -104,6 +105,16 @@
 
     uint32_t fClassID;
 
+    // NOTE, compute some bounds, even if extremely conservative.  Do *NOT* setLargest on the bounds
+    // rect because we outset it for dst copy textures
+    void setBounds(const SkRect& newBounds) { fBounds = newBounds; }
+
+    void joinBounds(const SkRect& otherBounds) {
+        return fBounds.joinPossiblyEmptyRect(otherBounds);
+    }
+
+    SkRect fBounds;
+
 private:
     static uint32_t GenClassID() {
         // fCurrProcessorClassID has been initialized to kIllegalProcessorClassID. The
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 301c676..4709513 100755
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -529,6 +529,12 @@
         fBatch.fHairline = geometry.fStrokeWidth == 0;
 
         fGeoData.push_back(geometry);
+
+        // setup bounds
+        fBounds = geometry.fRect;
+        SkScalar rad = SkScalarHalf(geometry.fStrokeWidth);
+        fBounds.outset(rad, rad);
+        geometry.fViewMatrix.mapRect(&fBounds);
     }
 
     /*  create a triangle strip that strokes the specified rect. There are 8
@@ -679,16 +685,12 @@
 
         SkAutoTUnref<GrBatch> batch(StrokeRectBatch::Create(geometry));
 
-        SkRect bounds = rect;
-        SkScalar rad = SkScalarHalf(width);
-        bounds.outset(rad, rad);
-        viewMatrix.mapRect(&bounds);
         // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
         // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
         // is enabled because it can cause ugly artifacts.
         pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
                                  0 == width && !rt->isMultisampled());
-        target->drawBatch(&pipelineBuilder, batch, &bounds);
+        target->drawBatch(&pipelineBuilder, batch);
     } else {
         // filled BW rect
         target->drawSimpleRect(&pipelineBuilder, color, viewMatrix, rect);
@@ -758,10 +760,11 @@
                            const SkMatrix& viewMatrix,
                            const SkPoint* positions, int vertexCount,
                            const uint16_t* indices, int indexCount,
-                           const GrColor* colors, const SkPoint* localCoords) {
+                           const GrColor* colors, const SkPoint* localCoords,
+                           const SkRect& bounds) {
         return SkNEW_ARGS(DrawVerticesBatch, (geometry, primitiveType, viewMatrix, positions,
                                               vertexCount, indices, indexCount, colors,
-                                              localCoords));
+                                              localCoords, bounds));
     }
 
     const char* name() const override { return "DrawVerticesBatch"; }
@@ -895,7 +898,7 @@
                       const SkMatrix& viewMatrix,
                       const SkPoint* positions, int vertexCount,
                       const uint16_t* indices, int indexCount,
-                      const GrColor* colors, const SkPoint* localCoords) {
+                      const GrColor* colors, const SkPoint* localCoords, const SkRect& bounds) {
         this->initClassID<DrawVerticesBatch>();
         SkASSERT(positions);
 
@@ -926,6 +929,8 @@
         fBatch.fVertexCount = vertexCount;
         fBatch.fIndexCount = indexCount;
         fBatch.fPrimitiveType = primitiveType;
+
+        this->setBounds(bounds);
     }
 
     GrPrimitiveType primitiveType() const { return fBatch.fPrimitiveType; }
@@ -980,6 +985,8 @@
         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
         fBatch.fVertexCount += that->vertexCount();
         fBatch.fIndexCount += that->indexCount();
+
+        this->joinBounds(that->bounds());
         return true;
     }
 
@@ -1032,13 +1039,12 @@
 
     DrawVerticesBatch::Geometry geometry;
     geometry.fColor = paint.getColor();
-
     SkAutoTUnref<GrBatch> batch(DrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
                                                           positions, vertexCount, indices,
-                                                          indexCount,colors, texCoords));
+                                                          indexCount, colors, texCoords,
+                                                          bounds));
 
-    // TODO figure out bounds
-    target->drawBatch(&pipelineBuilder, batch, &bounds);
+    target->drawBatch(&pipelineBuilder, batch);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrDefaultPathRenderer.cpp b/src/gpu/GrDefaultPathRenderer.cpp
index acc1871..93d64ab 100644
--- a/src/gpu/GrDefaultPathRenderer.cpp
+++ b/src/gpu/GrDefaultPathRenderer.cpp
@@ -217,12 +217,12 @@
         GrColor fColor;
         SkPath fPath;
         SkScalar fTolerance;
-        SkDEBUGCODE(SkRect fDevBounds;)
     };
 
     static GrBatch* Create(const Geometry& geometry, uint8_t coverage, const SkMatrix& viewMatrix,
-                           bool isHairline) {
-        return SkNEW_ARGS(DefaultPathBatch, (geometry, coverage, viewMatrix, isHairline));
+                           bool isHairline, const SkRect& devBounds) {
+        return SkNEW_ARGS(DefaultPathBatch, (geometry, coverage, viewMatrix, isHairline,
+                                             devBounds));
     }
 
     const char* name() const override { return "DefaultPathBatch"; }
@@ -393,12 +393,14 @@
 
 private:
     DefaultPathBatch(const Geometry& geometry, uint8_t coverage, const SkMatrix& viewMatrix,
-                     bool isHairline) {
+                     bool isHairline, const SkRect& devBounds) {
         this->initClassID<DefaultPathBatch>();
         fBatch.fCoverage = coverage;
         fBatch.fIsHairline = isHairline;
         fBatch.fViewMatrix = viewMatrix;
         fGeoData.push_back(geometry);
+
+        this->setBounds(devBounds);
     }
 
     bool onCombineIfPossible(GrBatch* t) override {
@@ -421,6 +423,7 @@
         }
 
         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
+        this->joinBounds(that->bounds());
         return true;
     }
 
@@ -704,12 +707,11 @@
             geometry.fColor = color;
             geometry.fPath = path;
             geometry.fTolerance = srcSpaceTol;
-            SkDEBUGCODE(geometry.fDevBounds = devBounds;)
 
             SkAutoTUnref<GrBatch> batch(DefaultPathBatch::Create(geometry, newCoverage, viewMatrix,
-                                                                 isHairline));
+                                                                 isHairline, devBounds));
 
-            target->drawBatch(pipelineBuilder, batch, &devBounds);
+            target->drawBatch(pipelineBuilder, batch);
         }
     }
     return true;
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 1521a9b..8503097 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -163,8 +163,7 @@
 }
 
 void GrDrawTarget::drawBatch(GrPipelineBuilder* pipelineBuilder,
-                             GrBatch* batch,
-                             const SkRect* devBounds) {
+                             GrBatch* batch) {
     SkASSERT(pipelineBuilder);
     // TODO some kind of checkdraw, but not at this level
 
@@ -172,11 +171,17 @@
     GrScissorState scissorState;
     GrPipelineBuilder::AutoRestoreFragmentProcessors arfp;
     GrPipelineBuilder::AutoRestoreStencil ars;
-    if (!this->setupClip(pipelineBuilder, &arfp, &ars, &scissorState, devBounds)) {
+    if (!this->setupClip(pipelineBuilder, &arfp, &ars, &scissorState, &batch->bounds())) {
         return;
     }
 
-    GrDrawTarget::PipelineInfo pipelineInfo(pipelineBuilder, &scissorState, batch, devBounds, this);
+    // Batch bounds are tight, so for dev copies
+    // TODO move this into setupDstReadIfNecessary when paths are in batch
+    SkRect bounds = batch->bounds();
+    bounds.outset(0.5f, 0.5f);
+
+    GrDrawTarget::PipelineInfo pipelineInfo(pipelineBuilder, &scissorState, batch, &bounds,
+                                            this);
     if (pipelineInfo.mustSkipDraw()) {
         return;
     }
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index cd2f436..0dca57a 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -68,8 +68,7 @@
      */
     const GrDrawTargetCaps* caps() const { return fCaps.get(); }
 
-    // TODO devbounds should live on the batch
-    void drawBatch(GrPipelineBuilder*, GrBatch*, const SkRect* devBounds = NULL);
+    void drawBatch(GrPipelineBuilder*, GrBatch*);
 
     /**
      * Draws path into the stencil buffer. The fill must be either even/odd or
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index cb1e741..e298be6 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -212,6 +212,9 @@
     RectBatch(const Geometry& geometry) {
         this->initClassID<RectBatch>();
         fGeoData.push_back(geometry);
+
+        fBounds = geometry.fRect;
+        geometry.fViewMatrix.mapRect(&fBounds);
     }
 
     GrColor color() const { return fBatch.fColor; }
@@ -248,6 +251,7 @@
             fBatch.fColor = GrColor_ILLEGAL;
         }
         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
+        this->joinBounds(that->bounds());
         return true;
     }
 
@@ -291,10 +295,7 @@
     }
 
     SkAutoTUnref<GrBatch> batch(RectBatch::Create(geometry));
-
-    SkRect bounds = rect;
-    viewMatrix.mapRect(&bounds);
-    this->drawBatch(pipelineBuilder, batch, &bounds);
+    this->drawBatch(pipelineBuilder, batch);
 }
 
 void GrInOrderDrawBuffer::onDrawBatch(GrBatch* batch,
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index b9303cf..8723d70 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -836,6 +836,8 @@
     CircleBatch(const Geometry& geometry) {
         this->initClassID<CircleBatch>();
         fGeoData.push_back(geometry);
+
+        this->setBounds(geometry.fDevBounds);
     }
 
     bool onCombineIfPossible(GrBatch* t) override {
@@ -856,6 +858,7 @@
         }
 
         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
+        this->joinBounds(that->bounds());
         return true;
     }
 
@@ -942,7 +945,7 @@
     SkRect bounds;
     SkAutoTUnref<GrBatch> batch(create_circle_batch(color, viewMatrix, useCoverageAA, circle,
                                                     stroke, &bounds));
-    target->drawBatch(pipelineBuilder, batch, &bounds);
+    target->drawBatch(pipelineBuilder, batch);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1103,6 +1106,8 @@
     EllipseBatch(const Geometry& geometry) {
         this->initClassID<EllipseBatch>();
         fGeoData.push_back(geometry);
+
+        this->setBounds(geometry.fDevBounds);
     }
 
     bool onCombineIfPossible(GrBatch* t) override {
@@ -1123,6 +1128,7 @@
         }
 
         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
+        this->joinBounds(that->bounds());
         return true;
     }
 
@@ -1250,7 +1256,7 @@
         return false;
     }
 
-    target->drawBatch(pipelineBuilder, batch, &bounds);
+    target->drawBatch(pipelineBuilder, batch);
     return true;
 }
 
@@ -1271,8 +1277,8 @@
         SkRect fBounds;
     };
 
-    static GrBatch* Create(const Geometry& geometry) {
-        return SkNEW_ARGS(DIEllipseBatch, (geometry));
+    static GrBatch* Create(const Geometry& geometry, const SkRect& bounds) {
+        return SkNEW_ARGS(DIEllipseBatch, (geometry, bounds));
     }
 
     const char* name() const override { return "DIEllipseBatch"; }
@@ -1402,9 +1408,11 @@
     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
 
 private:
-    DIEllipseBatch(const Geometry& geometry) {
+    DIEllipseBatch(const Geometry& geometry, const SkRect& bounds) {
         this->initClassID<DIEllipseBatch>();
         fGeoData.push_back(geometry);
+
+        this->setBounds(bounds);
     }
 
     bool onCombineIfPossible(GrBatch* t) override {
@@ -1425,6 +1433,7 @@
         }
 
         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
+        this->joinBounds(that->bounds());
         return true;
     }
 
@@ -1525,7 +1534,7 @@
     geometry.fBounds = *bounds;
 
     viewMatrix.mapRect(bounds);
-    return DIEllipseBatch::Create(geometry);
+    return DIEllipseBatch::Create(geometry, *bounds);
 }
 
 bool GrOvalRenderer::drawDIEllipse(GrDrawTarget* target,
@@ -1541,7 +1550,7 @@
     if (!batch) {
         return false;
     }
-    target->drawBatch(pipelineBuilder, batch, &bounds);
+    target->drawBatch(pipelineBuilder, batch);
     return true;
 }
 
@@ -1803,6 +1812,8 @@
         : fIndexBuffer(indexBuffer) {
         this->initClassID<RRectCircleRendererBatch>();
         fGeoData.push_back(geometry);
+
+        this->setBounds(geometry.fDevBounds);
     }
 
     bool onCombineIfPossible(GrBatch* t) override {
@@ -1823,6 +1834,7 @@
         }
 
         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
+        this->joinBounds(that->bounds());
         return true;
     }
 
@@ -2022,6 +2034,8 @@
         : fIndexBuffer(indexBuffer) {
         this->initClassID<RRectEllipseRendererBatch>();
         fGeoData.push_back(geometry);
+
+        this->setBounds(geometry.fDevBounds);
     }
 
     bool onCombineIfPossible(GrBatch* t) override {
@@ -2042,6 +2056,7 @@
         }
 
         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
+        this->joinBounds(that->bounds());
         return true;
     }
 
@@ -2279,7 +2294,7 @@
         return false;
     }
 
-    target->drawBatch(pipelineBuilder, batch, &bounds);
+    target->drawBatch(pipelineBuilder, batch);
     return true;
 }
 
diff --git a/src/gpu/GrTargetCommands.h b/src/gpu/GrTargetCommands.h
index 42a8ca3..f9259c7 100644
--- a/src/gpu/GrTargetCommands.h
+++ b/src/gpu/GrTargetCommands.h
@@ -82,13 +82,6 @@
     Cmd* recordDrawBatch(GrInOrderDrawBuffer*,
                          GrBatch*,
                          const GrDrawTarget::PipelineInfo&);
-    void recordDrawRect(GrInOrderDrawBuffer*,
-                        GrPipelineBuilder*,
-                        GrColor,
-                        const SkMatrix& viewMatrix,
-                        const SkRect& rect,
-                        const SkRect* localRect,
-                        const SkMatrix* localMatrix);
     Cmd* recordStencilPath(GrInOrderDrawBuffer*,
                            const GrPipelineBuilder&,
                            const GrPathProcessor*,
@@ -120,11 +113,6 @@
                            const SkIRect& srcRect,
                            const SkIPoint& dstPoint);
 
-protected:
-    void willReserveVertexAndIndexSpace(int vertexCount,
-                                        size_t vertexStride,
-                                        int indexCount);
-
 private:
     friend class GrInOrderDrawBuffer;
 
diff --git a/src/gpu/GrTessellatingPathRenderer.cpp b/src/gpu/GrTessellatingPathRenderer.cpp
index e00792e..7a9c5a7 100644
--- a/src/gpu/GrTessellatingPathRenderer.cpp
+++ b/src/gpu/GrTessellatingPathRenderer.cpp
@@ -1485,6 +1485,9 @@
       , fViewMatrix(viewMatrix)
       , fClipBounds(clipBounds) {
         this->initClassID<TessellatingPathBatch>();
+
+        fBounds = path.getBounds();
+        viewMatrix.mapRect(&fBounds);
     }
 
     GrColor        fColor;
diff --git a/src/gpu/GrTestBatch.h b/src/gpu/GrTestBatch.h
index 8e16f52..e180fac 100644
--- a/src/gpu/GrTestBatch.h
+++ b/src/gpu/GrTestBatch.h
@@ -68,8 +68,10 @@
     }
 
 protected:
-    GrTestBatch(const GrGeometryProcessor* gp) {
+    GrTestBatch(const GrGeometryProcessor* gp, const SkRect& bounds) {
         fGeometryProcessor.reset(SkRef(gp));
+
+        this->setBounds(bounds);
     }
 
     const GrGeometryProcessor* geometryProcessor() const { return fGeometryProcessor; }
diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp
index a284b27..3f0df67 100644
--- a/src/gpu/effects/GrDashingEffect.cpp
+++ b/src/gpu/effects/GrDashingEffect.cpp
@@ -256,7 +256,6 @@
         SkScalar fIntervals[2];
         SkScalar fParallelScale;
         SkScalar fPerpendicularScale;
-        SkDEBUGCODE(SkRect fDevBounds;)
     };
 
     static GrBatch* Create(const Geometry& geometry, SkPaint::Cap cap, DashAAMode aaMode,
@@ -367,9 +366,6 @@
 
             SkScalar startAdj = 0;
 
-            SkMatrix& combinedMatrix = args.fSrcRotInv;
-            combinedMatrix.postConcat(args.fViewMatrix);
-
             bool lineDone = false;
 
             // Too simplify the algorithm, we always push back rects for start and end rect.
@@ -646,6 +642,17 @@
         fBatch.fAAMode = aaMode;
         fBatch.fCap = cap;
         fBatch.fFullDash = fullDash;
+
+        // compute bounds
+        SkScalar halfStrokeWidth = 0.5f * geometry.fSrcStrokeWidth;
+        SkScalar xBloat = SkPaint::kButt_Cap == cap ? 0 : halfStrokeWidth;
+        fBounds.set(geometry.fPtsRot[0], geometry.fPtsRot[1]);
+        fBounds.outset(xBloat, halfStrokeWidth);
+
+        // Note, we actually create the combined matrix here, and save the work
+        SkMatrix& combinedMatrix = fGeoData[0].fSrcRotInv;
+        combinedMatrix.postConcat(geometry.fViewMatrix);
+        combinedMatrix.mapRect(&fBounds);
     }
 
     bool onCombineIfPossible(GrBatch* t) override {
@@ -674,6 +681,7 @@
         }
 
         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
+        this->joinBounds(that->bounds());
         return true;
     }