Move Op chain bounds calculations into tryConcat

Bug: skia:8671
Change-Id: I253a753db1aa225bd4e0a7e9bd869dbd52f2f063
Reviewed-on: https://skia-review.googlesource.com/c/185811
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/GrRenderTargetOpList.cpp b/src/gpu/GrRenderTargetOpList.cpp
index b75dd67..7823cdb 100644
--- a/src/gpu/GrRenderTargetOpList.cpp
+++ b/src/gpu/GrRenderTargetOpList.cpp
@@ -14,6 +14,7 @@
 #include "GrRect.h"
 #include "GrRenderTargetContext.h"
 #include "GrResourceAllocator.h"
+#include "SkExchange.h"
 #include "SkRectPriv.h"
 #include "SkTraceEvent.h"
 #include "ops/GrClearOp.h"
@@ -226,7 +227,7 @@
 // (and null for the second head/tail).
 bool GrRenderTargetOpList::OpChain::tryConcat(
         List* list, const DstProxy& dstProxy, const GrAppliedClip* appliedClip,
-        const GrCaps& caps, GrOpMemoryPool* pool, GrAuditTrail* auditTrail) {
+        const SkRect& bounds, const GrCaps& caps, GrOpMemoryPool* pool, GrAuditTrail* auditTrail) {
     SkASSERT(!fList.empty());
     SkASSERT(!list->empty());
     // All returns use explicit tuple constructor rather than {a, b} to work around old GCC bug.
@@ -237,6 +238,7 @@
         (fDstProxy.proxy() && fDstProxy != dstProxy)) {
         return false;
     }
+
     SkDEBUGCODE(bool first = true;)
     do {
         switch (fList.tail()->combineIfPossible(list->head(), caps)) {
@@ -248,8 +250,12 @@
                 SkASSERT(first);
                 return false;
             case GrOp::CombineResult::kMayChain:
-                fList = DoConcat(std::move(fList), std::move(*list), caps, pool, auditTrail);
-                return true;
+                fList = DoConcat(std::move(fList), skstd::exchange(*list, List()), caps, pool,
+                                 auditTrail);
+                // The above exchange cleared out 'list'. The list needs to be empty now for the
+                // loop to terminate.
+                SkASSERT(list->empty());
+                break;
             case GrOp::CombineResult::kMerged: {
                 GrOP_INFO("\t\t: (%s opID: %u) -> Combining with (%s, opID: %u)\n",
                           list->tail()->name(), list->tail()->uniqueID(), list->head()->name(),
@@ -261,14 +267,15 @@
         }
         SkDEBUGCODE(first = false);
     } while (!list->empty());
-    // All the ops from chain b merged.
+
+    // The new ops were successfully merged and/or chained onto our own.
+    fBounds.joinPossiblyEmptyRect(bounds);
     return true;
 }
 
 bool GrRenderTargetOpList::OpChain::prependChain(OpChain* that, const GrCaps& caps,
                                                  GrOpMemoryPool* pool, GrAuditTrail* auditTrail) {
-    if (!that->tryConcat(
-            &fList, this->dstProxy(), this->appliedClip(), caps, pool, auditTrail)) {
+    if (!that->tryConcat(&fList, fDstProxy, fAppliedClip, fBounds, caps, pool, auditTrail)) {
         this->validate();
         // append failed
         return false;
@@ -277,7 +284,7 @@
     // 'that' owns the combined chain. Move it into 'this'.
     SkASSERT(fList.empty());
     fList = std::move(that->fList);
-    fBounds.joinPossiblyEmptyRect(that->fBounds);
+    fBounds = that->fBounds;
 
     that->fDstProxy.setProxy(nullptr);
     if (that->fAppliedClip) {
@@ -302,14 +309,13 @@
     SkASSERT(op->isChainHead() && op->isChainTail());
     SkRect opBounds = op->bounds();
     List chain(std::move(op));
-    if (!this->tryConcat(&chain, *dstProxy, appliedClip, caps, pool, auditTrail)) {
+    if (!this->tryConcat(&chain, *dstProxy, appliedClip, opBounds, caps, pool, auditTrail)) {
         // append failed, give the op back to the caller.
         this->validate();
         return chain.popHead();
     }
 
     SkASSERT(chain.empty());
-    fBounds.joinPossiblyEmptyRect(opBounds);
     this->validate();
     return nullptr;
 }