Add MRU to GrThreadSafeUniquelyKeyedProxyViewCache

Bug: 1108408
Change-Id: I54ae1512340408e61c2fb2f408b006d6f7697cf7
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/317860
Reviewed-by: Adlai Holler <adlai@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrThreadSafeUniquelyKeyedProxyViewCache.cpp b/src/gpu/GrThreadSafeUniquelyKeyedProxyViewCache.cpp
index 0c305d2..4a40198 100644
--- a/src/gpu/GrThreadSafeUniquelyKeyedProxyViewCache.cpp
+++ b/src/gpu/GrThreadSafeUniquelyKeyedProxyViewCache.cpp
@@ -7,59 +7,111 @@
 
 #include "src/gpu/GrThreadSafeUniquelyKeyedProxyViewCache.h"
 
-GrThreadSafeUniquelyKeyedProxyViewCache::GrThreadSafeUniquelyKeyedProxyViewCache() {}
+GrThreadSafeUniquelyKeyedProxyViewCache::GrThreadSafeUniquelyKeyedProxyViewCache()
+    : fFreeEntryList(nullptr) {
+}
 
 GrThreadSafeUniquelyKeyedProxyViewCache::~GrThreadSafeUniquelyKeyedProxyViewCache() {
-    fUniquelyKeyedProxyViews.foreach([this](Entry* v) { this->recycleEntry(v); });
+    this->dropAllRefs();
 }
 
 #if GR_TEST_UTILS
 int GrThreadSafeUniquelyKeyedProxyViewCache::numEntries() const {
     SkAutoSpinlock lock{fSpinLock};
 
-    return fUniquelyKeyedProxyViews.count();
+    return fUniquelyKeyedProxyViewMap.count();
 }
 
 int GrThreadSafeUniquelyKeyedProxyViewCache::count() const {
     SkAutoSpinlock lock{fSpinLock};
 
-    return fUniquelyKeyedProxyViews.count();
+    return fUniquelyKeyedProxyViewMap.count();
 }
 #endif
 
 void GrThreadSafeUniquelyKeyedProxyViewCache::dropAllRefs() {
     SkAutoSpinlock lock{fSpinLock};
 
-    fUniquelyKeyedProxyViews.foreach([this](Entry* v) { this->recycleEntry(v); });
-    fUniquelyKeyedProxyViews.reset();
+    fUniquelyKeyedProxyViewMap.reset();
+    while (auto tmp = fUniquelyKeyedProxyViewList.head()) {
+        fUniquelyKeyedProxyViewList.remove(tmp);
+        this->recycleEntry(tmp);
+    }
+    // TODO: should we empty out the fFreeEntryList and reset fEntryAllocator?
 }
 
 void GrThreadSafeUniquelyKeyedProxyViewCache::dropAllUniqueRefs() {
     SkAutoSpinlock lock{fSpinLock};
 
-    fUniquelyKeyedProxyViews.foreach([](Entry* v) {
-                                        // problematic
-                                    });
+    Entry* cur = fUniquelyKeyedProxyViewList.head();
+    Entry* next = cur ? cur->fNext : nullptr;
+
+    while (cur) {
+        if (cur->fView.proxy()->unique()) {
+            fUniquelyKeyedProxyViewMap.remove(cur->fKey);
+            fUniquelyKeyedProxyViewList.remove(cur);
+            this->recycleEntry(cur);
+        }
+
+        cur = next;
+        next = cur ? cur->fNext : nullptr;
+    }
 }
 
 GrSurfaceProxyView GrThreadSafeUniquelyKeyedProxyViewCache::find(const GrUniqueKey& key) {
     SkAutoSpinlock lock{fSpinLock};
 
-    Entry* tmp = fUniquelyKeyedProxyViews.find(key);
+    Entry* tmp = fUniquelyKeyedProxyViewMap.find(key);
     if (tmp) {
+        SkASSERT(fUniquelyKeyedProxyViewList.isInList(tmp));
+        // make the sought out entry the MRU
+        fUniquelyKeyedProxyViewList.remove(tmp);
+        fUniquelyKeyedProxyViewList.addToHead(tmp);
         return tmp->fView;
     }
 
     return {};
 }
 
+GrThreadSafeUniquelyKeyedProxyViewCache::Entry*
+GrThreadSafeUniquelyKeyedProxyViewCache::getEntry(const GrUniqueKey& key,
+                                                  const GrSurfaceProxyView& view) {
+    Entry* entry;
+
+    if (fFreeEntryList) {
+        entry = fFreeEntryList;
+        fFreeEntryList = entry->fNext;
+        entry->fNext = nullptr;
+
+        entry->fKey = key;
+        entry->fView = view;
+    } else {
+        entry = fEntryAllocator.make<Entry>(key, view);
+    }
+
+    fUniquelyKeyedProxyViewList.addToHead(entry);  // make 'entry' the MRU
+    fUniquelyKeyedProxyViewMap.add(entry);
+    return entry;
+}
+
+void GrThreadSafeUniquelyKeyedProxyViewCache::recycleEntry(Entry* dead) {
+    SkASSERT(!dead->fPrev && !dead->fNext && !dead->fList);
+
+    dead->fKey.reset();
+    dead->fView.reset();
+
+    dead->fNext = fFreeEntryList;
+    fFreeEntryList = dead;
+}
+
 GrSurfaceProxyView GrThreadSafeUniquelyKeyedProxyViewCache::internalAdd(
                                                                 const GrUniqueKey& key,
                                                                 const GrSurfaceProxyView& view) {
-    Entry* tmp = fUniquelyKeyedProxyViews.find(key);
+    Entry* tmp = fUniquelyKeyedProxyViewMap.find(key);
     if (!tmp) {
         tmp = this->getEntry(key, view);
-        fUniquelyKeyedProxyViews.add(tmp);
+
+        SkASSERT(fUniquelyKeyedProxyViewMap.find(key));
     }
 
     return tmp->fView;