Attempt to combine batches in forward direction before flush
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1763883005

Review URL: https://codereview.chromium.org/1763883005
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index 2d2a455..ead02c2 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -869,6 +869,8 @@
 DEFINE_bool(batchClip, false, "Clip each GrBatch to its device bounds for testing.");
 DEFINE_bool(batchBounds, false, "Draw a wireframe bounds of each GrBatch.");
 DEFINE_int32(batchLookback, -1, "Maximum GrBatch lookback for combining, negative means default.");
+DEFINE_int32(batchLookahead, -1, "Maximum GrBatch lookahead for combining, negative means "
+                                 "default.");
 
 Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const {
     GrContextOptions grOptions;
@@ -876,6 +878,7 @@
     grOptions.fClipBatchToBounds = FLAGS_batchClip;
     grOptions.fDrawBatchBounds = FLAGS_batchBounds;
     grOptions.fMaxBatchLookback = FLAGS_batchLookback;
+    grOptions.fMaxBatchLookahead = FLAGS_batchLookahead;
 
     src.modifyGrContextOptions(&grOptions);
 
diff --git a/include/gpu/GrContextOptions.h b/include/gpu/GrContextOptions.h
index 8e6368a..d7070db 100644
--- a/include/gpu/GrContextOptions.h
+++ b/include/gpu/GrContextOptions.h
@@ -23,6 +23,7 @@
         , fClipBatchToBounds(false)
         , fDrawBatchBounds(false)
         , fMaxBatchLookback(-1)
+        , fMaxBatchLookahead(-1)
         , fUseShaderSwizzling(false) {}
 
     // EXPERIMENTAL
@@ -64,8 +65,10 @@
         of their dev bounds. */
     bool fDrawBatchBounds;
 
-    /** For debugging, override the default maximum look-back window for GrBatch combining. */
+    /** For debugging, override the default maximum look-back or look-ahead window for GrBatch
+        combining. */
     int fMaxBatchLookback;
+    int fMaxBatchLookahead;
 
     /** Force us to do all swizzling manually in the shader and don't rely on extensions to do
         swizzling. */
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 8844f1a..a16d5c0 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -95,6 +95,7 @@
     dtOptions.fClipBatchToBounds = options.fClipBatchToBounds;
     dtOptions.fDrawBatchBounds = options.fDrawBatchBounds;
     dtOptions.fMaxBatchLookback = options.fMaxBatchLookback;
+    dtOptions.fMaxBatchLookahead = options.fMaxBatchLookahead;
     fDrawingManager.reset(new GrDrawingManager(this, dtOptions, &fSingleOwner));
 
     // GrBatchFontCache will eventually replace GrFontCache
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index fc8c71b..cf3baa1 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -35,7 +35,8 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 // Experimentally we have found that most batching occurs within the first 10 comparisons.
-static const int kDefaultMaxBatchLookback = 10;
+static const int kDefaultMaxBatchLookback  = 10;
+static const int kDefaultMaxBatchLookahead = 10;
 
 GrDrawTarget::GrDrawTarget(GrRenderTarget* rt, GrGpu* gpu, GrResourceProvider* resourceProvider,
                            GrAuditTrail* auditTrail, const Options& options)
@@ -51,6 +52,8 @@
     fDrawBatchBounds = options.fDrawBatchBounds;
     fMaxBatchLookback = (options.fMaxBatchLookback < 0) ? kDefaultMaxBatchLookback :
                                                           options.fMaxBatchLookback;
+    fMaxBatchLookahead = (options.fMaxBatchLookahead < 0) ? kDefaultMaxBatchLookahead :
+                                                           options.fMaxBatchLookahead;
 
     rt->setLastDrawTarget(this);
 
@@ -113,11 +116,15 @@
 #if 0
         SkDebugf("*******************************\n");
 #endif
-        SkDebugf("%d: %s\n", i, fBatches[i]->name());
+        if (fBatches[i]) {
+            SkDebugf("%d: <combined forward>\n", i);
+        } else {
+            SkDebugf("%d: %s\n", i, fBatches[i]->name());
 #if 0
-        SkString str = fBatches[i]->dumpInfo();
-        SkDebugf("%s\n", str.c_str());
+            SkString str = fBatches[i]->dumpInfo();
+            SkDebugf("%s\n", str.c_str());
 #endif
+        }
     }
 }
 #endif
@@ -193,7 +200,9 @@
 
     // Loop over the batches that haven't yet generated their geometry
     for (int i = 0; i < fBatches.count(); ++i) {
-        fBatches[i]->prepare(flushState);
+        if (fBatches[i]) {
+            fBatches[i]->prepare(flushState);
+        }
     }
 }
 
@@ -201,6 +210,9 @@
     // Draw all the generated geometry.
     SkRandom random;
     for (int i = 0; i < fBatches.count(); ++i) {
+        if (!fBatches[i]) {
+            continue;
+        }
         if (fDrawBatchBounds) {
             const SkRect& bounds = fBatches[i]->bounds();
             SkIRect ibounds;
@@ -496,6 +508,48 @@
     fBatches.push_back().reset(SkRef(batch));
 }
 
+void GrDrawTarget::forwardCombine() {
+    for (int i = 0; i < fBatches.count() - 2; ++i) {
+        GrBatch* batch = fBatches[i];
+        int maxCandidateIdx = SkTMin(i + fMaxBatchLookahead, fBatches.count() - 1);
+        int j = i + 1;
+        while (true) {
+            GrBatch* candidate = fBatches[j];
+            // We cannot continue to search if the render target changes
+            if (candidate->renderTargetUniqueID() != batch->renderTargetUniqueID()) {
+                GrBATCH_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n",
+                             candidate->name(), candidate->uniqueID());
+                break;
+            }
+            if (j == i +1) {
+                // We assume batch would have combined with candidate when the candidate was added
+                // via backwards combining in recordBatch.
+                SkASSERT(!batch->combineIfPossible(candidate, *this->caps()));
+            } else if (batch->combineIfPossible(candidate, *this->caps())) {
+                GrBATCH_INFO("\t\tCombining with (%s, B%u)\n", candidate->name(),
+                             candidate->uniqueID());
+                GR_AUDIT_TRAIL_BATCHING_RESULT_COMBINED(fAuditTrail, candidate);
+                fBatches[j].reset(SkRef(batch));
+                fBatches[i].reset(nullptr);
+                break;
+            }
+            // Stop going traversing if we would cause a painter's order violation.
+            // TODO: The bounds used here do not fully consider the clip. It may be advantageous
+            // to clip each batch's bounds to the clip.
+            if (intersect(candidate->bounds(), batch->bounds())) {
+                GrBATCH_INFO("\t\tIntersects with (%s, B%u)\n", candidate->name(),
+                             candidate->uniqueID());
+                break;
+            }
+            ++j;
+            if (j > maxCandidateIdx) {
+                GrBATCH_INFO("\t\tReached max lookahead or end of batch array %d\n", i);
+                break;
+            }
+        }
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 bool GrDrawTarget::installPipelineInDrawBatch(const GrPipelineBuilder* pipelineBuilder,
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index 8b30ab9..9a6dbc9 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -45,10 +45,15 @@
 public:
     /** Options for GrDrawTarget behavior. */
     struct Options {
-        Options () : fClipBatchToBounds(false), fDrawBatchBounds(false), fMaxBatchLookback(-1) {}
+        Options ()
+            : fClipBatchToBounds(false)
+            , fDrawBatchBounds(false)
+            , fMaxBatchLookback(-1)
+            , fMaxBatchLookahead(-1) {}
         bool fClipBatchToBounds;
         bool fDrawBatchBounds;
         int  fMaxBatchLookback;
+        int  fMaxBatchLookahead;
     };
 
     GrDrawTarget(GrRenderTarget*, GrGpu*, GrResourceProvider*, GrAuditTrail*, const Options&);
@@ -61,7 +66,9 @@
 #ifdef ENABLE_MDB
         this->setFlag(kClosed_Flag);
 #endif
+        this->forwardCombine();
     }
+
     bool isClosed() const { return this->isSetFlag(kClosed_Flag); }
 
     // TODO: this entry point is only needed in the non-MDB world. Remove when
@@ -216,6 +223,7 @@
     };
 
     void recordBatch(GrBatch*);
+    void forwardCombine();
     bool installPipelineInDrawBatch(const GrPipelineBuilder* pipelineBuilder,
                                     const GrScissorState* scissor,
                                     GrDrawBatch* batch);
@@ -232,11 +240,6 @@
     void getPathStencilSettingsForFilltype(GrPathRendering::FillType,
                                            const GrStencilAttachment*,
                                            GrStencilSettings*);
-    bool setupClip(const GrPipelineBuilder&,
-                           GrPipelineBuilder::AutoRestoreFragmentProcessorState*,
-                           GrPipelineBuilder::AutoRestoreStencil*,
-                           GrScissorState*,
-                           const SkRect* devBounds);
 
     void addDependency(GrDrawTarget* dependedOn);
 
@@ -260,6 +263,7 @@
 
     bool                                        fDrawBatchBounds;
     int                                         fMaxBatchLookback;
+    int                                         fMaxBatchLookahead;
 
     typedef SkRefCnt INHERITED;
 };