Make the intervals in GrResourceAllocator use SkArenaAlloc

Change-Id: I3190396fe34c01c232654fcb225dbf76df3137b4
Reviewed-on: https://skia-review.googlesource.com/66463
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp
index 6076609..9b15f3c 100644
--- a/src/gpu/GrDrawingManager.cpp
+++ b/src/gpu/GrDrawingManager.cpp
@@ -171,12 +171,12 @@
     }
 #endif
 
-#ifdef MDB_ALLOC_RESOURCES
     GrResourceAllocator alloc(fContext->resourceProvider());
     for (int i = 0; i < fOpLists.count(); ++i) {
         fOpLists[i]->gatherProxyIntervals(&alloc);
     }
 
+#ifdef MDB_ALLOC_RESOURCES
     alloc.assign();
 #endif
 
diff --git a/src/gpu/GrRenderTargetOpList.cpp b/src/gpu/GrRenderTargetOpList.cpp
index af870ca..09486c7 100644
--- a/src/gpu/GrRenderTargetOpList.cpp
+++ b/src/gpu/GrRenderTargetOpList.cpp
@@ -257,6 +257,10 @@
 }
 
 void GrRenderTargetOpList::gatherProxyIntervals(GrResourceAllocator* alloc) const {
+    if (!fRecordedOps.count()) {
+        return;
+    }
+
     unsigned int cur = alloc->numOps();
 
     // Add the interval for all the writes to this opList's target
@@ -266,12 +270,12 @@
         alloc->addInterval(p);
     };
     for (int i = 0; i < fRecordedOps.count(); ++i) {
-        SkASSERT(alloc->curOp() == cur+i);
-
         const GrOp* op = fRecordedOps[i].fOp.get(); // only diff from the GrTextureOpList version
-        op->visitProxies(gather);
+        if (op) {
+            op->visitProxies(gather);
 
-        alloc->incOps();
+            alloc->incOps();
+        }
     }
 }
 
diff --git a/src/gpu/GrResourceAllocator.cpp b/src/gpu/GrResourceAllocator.cpp
index ba62854..62f780b 100644
--- a/src/gpu/GrResourceAllocator.cpp
+++ b/src/gpu/GrResourceAllocator.cpp
@@ -17,13 +17,19 @@
 
     if (Interval* intvl = fIntvlHash.find(proxy->uniqueID().asUInt())) {
         // Revise the interval for an existing use
-        SkASSERT(intvl->fEnd < start);
+        //SkASSERT(intvl->fEnd <= end);
         intvl->fEnd = end;
         return;
     }
 
-    // TODO: given the usage pattern an arena allocation scheme would work well here
-    Interval* newIntvl = new Interval(proxy, start, end);
+    Interval* newIntvl;
+    if (fFreeIntervalList) {
+        newIntvl = fFreeIntervalList;
+        fFreeIntervalList = newIntvl->fNext;
+        newIntvl->resetTo(proxy, start, end);
+    } else {
+        newIntvl = fIntervalAllocator.make<Interval>(proxy, start, end);
+    }
 
     fIntvlList.insertByIncreasingStart(newIntvl);
     fIntvlHash.add(newIntvl);
@@ -109,7 +115,10 @@
     while (!fActiveIntvls.empty() && fActiveIntvls.peekHead()->fEnd < curIndex) {
         Interval* temp = fActiveIntvls.popHead();
         this->freeUpSurface(temp->fProxy->priv().peekSurface());
-        delete temp;
+
+        // Add temp to the free interval list so it can be reused
+        temp->fNext = fFreeIntervalList;
+        fFreeIntervalList = temp;
     }
 }
 
diff --git a/src/gpu/GrResourceAllocator.h b/src/gpu/GrResourceAllocator.h
index 966359c..3be4836 100644
--- a/src/gpu/GrResourceAllocator.h
+++ b/src/gpu/GrResourceAllocator.h
@@ -11,6 +11,8 @@
 #include "GrGpuResourcePriv.h"
 #include "GrSurface.h"
 #include "GrSurfaceProxy.h"
+
+#include "SkArenaAlloc.h"
 #include "SkTDynamicHash.h"
 #include "SkTMultiMap.h"
 
@@ -86,6 +88,16 @@
             SkASSERT(proxy);
         }
 
+        void resetTo(GrSurfaceProxy* proxy, unsigned int start, unsigned int end) {
+            SkASSERT(proxy);
+
+            fProxy = proxy;
+            fProxyID = proxy->uniqueID().asUInt();
+            fStart = start;
+            fEnd = end;
+            fNext = nullptr;
+        }
+
         // for SkTDynamicHash
         static const uint32_t& GetKey(const Interval& intvl) {
             return intvl.fProxyID;
@@ -103,11 +115,8 @@
     public:
         IntervalList() = default;
         ~IntervalList() {
-            while (fHead) {
-                Interval* temp = fHead;
-                fHead = temp->fNext;
-                delete temp;
-            }
+            // The only time we delete an IntervalList is in the GrResourceAllocator dtor.
+            // Since the arena allocator will clean up for us we don't bother here.
         }
 
         bool empty() const { return !SkToBool(fHead); }
@@ -120,6 +129,9 @@
         Interval* fHead = nullptr;
     };
 
+    // Gathered statistics indicate that 99% of flushes will be covered by <= 12 Intervals
+    static const int kInitialArenaSize = 12 * sizeof(Interval);
+
     GrResourceProvider* fResourceProvider;
     FreePoolMultiMap    fFreePool;          // Recently created/used GrSurfaces
     IntvlHash           fIntvlHash;         // All the intervals, hashed by proxyID
@@ -129,6 +141,10 @@
                                             // (sorted by increasing end)
     unsigned int        fNumOps = 0;
     SkDEBUGCODE(bool    fAssigned = false;)
+
+    char                fStorage[kInitialArenaSize];
+    SkArenaAlloc        fIntervalAllocator { fStorage, kInitialArenaSize, 0 };
+    Interval*           fFreeIntervalList = nullptr;
 };
 
 #endif // GrResourceAllocator_DEFINED
diff --git a/src/gpu/GrTextureOpList.cpp b/src/gpu/GrTextureOpList.cpp
index cf00309..9a3d15b 100644
--- a/src/gpu/GrTextureOpList.cpp
+++ b/src/gpu/GrTextureOpList.cpp
@@ -124,6 +124,10 @@
 }
 
 void GrTextureOpList::gatherProxyIntervals(GrResourceAllocator* alloc) const {
+    if (!fRecordedOps.count()) {
+        return;
+    }
+
     unsigned int cur = alloc->numOps();
 
     // Add the interval for all the writes to this opList's target
@@ -133,12 +137,12 @@
         alloc->addInterval(p);
     };
     for (int i = 0; i < fRecordedOps.count(); ++i) {
-        SkASSERT(alloc->curOp() == cur+i);
-
         const GrOp* op = fRecordedOps[i].get(); // only diff from the GrRenderTargetOpList version
-        op->visitProxies(gather);
+        if (op) {
+            op->visitProxies(gather);
 
-        alloc->incOps();
+            alloc->incOps();
+        }
     }
 }