Revert of GrResourceCache2 manages scratch texture. (patchset #14 id:260001 of https://codereview.chromium.org/608883003/)

Reason for revert:
Turning bots red:
Nanobench seems to be uniformly failing on Android
(http://108.170.220.21:10117/builders/Perf-Android-Venue8-PowerVR-x86-Release/builds/99/steps/RunNanobench/logs/stdio)

Ubuntu GTX660 32bit is failing in both Debug and Release on GM generation (it appears to be out of memory) (http://108.170.220.120:10117/builders/Test-Ubuntu12-ShuttleA-GTX660-x86-Debug/builds/2457/steps/GenerateGMs/logs/stdio)

Original issue's description:
> GrResourceCache2 manages scratch texture.
>
>
> BUG=skia:
>
> Committed: https://skia.googlesource.com/skia/+/3d398c876440deaab39bbf2a9b881c337e6dc8d4

R=bsalomon@google.com
TBR=bsalomon@google.com
NOTREECHECKS=true
NOTRY=true
BUG=skia:

Author: robertphillips@google.com

Review URL: https://codereview.chromium.org/611383003
diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp
index 12e959f..e9be509 100644
--- a/src/gpu/GrResourceCache.cpp
+++ b/src/gpu/GrResourceCache.cpp
@@ -82,10 +82,14 @@
 #if GR_CACHE_STATS
     fHighWaterEntryCount          = 0;
     fHighWaterEntryBytes          = 0;
+    fHighWaterClientDetachedCount = 0;
+    fHighWaterClientDetachedBytes = 0;
 #endif
 
     fEntryCount                   = 0;
     fEntryBytes                   = 0;
+    fClientDetachedCount          = 0;
+    fClientDetachedBytes          = 0;
 
     fPurging                      = false;
 
@@ -132,26 +136,55 @@
     }
 }
 
-void GrResourceCache::internalDetach(GrResourceCacheEntry* entry) {
+void GrResourceCache::internalDetach(GrResourceCacheEntry* entry,
+                                     BudgetBehaviors behavior) {
     fList.remove(entry);
-    fEntryCount -= 1;
-    fEntryBytes -= entry->fCachedSize;
-}
 
-void GrResourceCache::attachToHead(GrResourceCacheEntry* entry) {
-    fList.addToHead(entry);
-
-    fEntryCount += 1;
-    fEntryBytes += entry->fCachedSize;
+    // update our stats
+    if (kIgnore_BudgetBehavior == behavior) {
+        fClientDetachedCount += 1;
+        fClientDetachedBytes += entry->fCachedSize;
 
 #if GR_CACHE_STATS
-    if (fHighWaterEntryCount < fEntryCount) {
-        fHighWaterEntryCount = fEntryCount;
-    }
-    if (fHighWaterEntryBytes < fEntryBytes) {
-        fHighWaterEntryBytes = fEntryBytes;
-    }
+        if (fHighWaterClientDetachedCount < fClientDetachedCount) {
+            fHighWaterClientDetachedCount = fClientDetachedCount;
+        }
+        if (fHighWaterClientDetachedBytes < fClientDetachedBytes) {
+            fHighWaterClientDetachedBytes = fClientDetachedBytes;
+        }
 #endif
+
+    } else {
+        SkASSERT(kAccountFor_BudgetBehavior == behavior);
+
+        fEntryCount -= 1;
+        fEntryBytes -= entry->fCachedSize;
+    }
+}
+
+void GrResourceCache::attachToHead(GrResourceCacheEntry* entry,
+                                   BudgetBehaviors behavior) {
+    fList.addToHead(entry);
+
+    // update our stats
+    if (kIgnore_BudgetBehavior == behavior) {
+        fClientDetachedCount -= 1;
+        fClientDetachedBytes -= entry->fCachedSize;
+    } else {
+        SkASSERT(kAccountFor_BudgetBehavior == behavior);
+
+        fEntryCount += 1;
+        fEntryBytes += entry->fCachedSize;
+
+#if GR_CACHE_STATS
+        if (fHighWaterEntryCount < fEntryCount) {
+            fHighWaterEntryCount = fEntryCount;
+        }
+        if (fHighWaterEntryBytes < fEntryBytes) {
+            fHighWaterEntryBytes = fEntryBytes;
+        }
+#endif
+    }
 }
 
 // This functor just searches for an entry with only a single ref (from
@@ -160,40 +193,41 @@
 class GrTFindUnreffedFunctor {
 public:
     bool operator()(const GrResourceCacheEntry* entry) const {
-        return entry->resource()->isPurgable();
+        return entry->resource()->unique();
     }
 };
 
-
-void GrResourceCache::makeResourceMRU(GrGpuResource* resource) {
-    GrResourceCacheEntry* entry = resource->getCacheEntry();
-    if (entry) {
-        this->internalDetach(entry);
-        this->attachToHead(entry);
-    }
-}
-
-GrGpuResource* GrResourceCache::find(const GrResourceKey& key) {
+GrGpuResource* GrResourceCache::find(const GrResourceKey& key, uint32_t ownershipFlags) {
     GrAutoResourceCacheValidate atcv(this);
 
     GrResourceCacheEntry* entry = NULL;
 
-    entry = fCache.find(key);
+    if (ownershipFlags & kNoOtherOwners_OwnershipFlag) {
+        GrTFindUnreffedFunctor functor;
+
+        entry = fCache.find<GrTFindUnreffedFunctor>(key, functor);
+    } else {
+        entry = fCache.find(key);
+    }
 
     if (NULL == entry) {
         return NULL;
     }
 
-    // Make this resource MRU
-    this->internalDetach(entry);
-    this->attachToHead(entry);
+    if (ownershipFlags & kHide_OwnershipFlag) {
+        this->makeExclusive(entry);
+    } else {
+        // Make this resource MRU
+        this->internalDetach(entry);
+        this->attachToHead(entry);
+    }
 
-    // GrResourceCache2 is responsible for scratch resources.
-    SkASSERT(GrIORef::kNo_IsScratch == entry->resource()->fIsScratch);
     return entry->fResource;
 }
 
-void GrResourceCache::addResource(const GrResourceKey& key, GrGpuResource* resource) {
+void GrResourceCache::addResource(const GrResourceKey& key,
+                                  GrGpuResource* resource,
+                                  uint32_t ownershipFlags) {
     SkASSERT(NULL == resource->getCacheEntry());
     // we don't expect to create new resources during a purge. In theory
     // this could cause purgeAsNeeded() into an infinite loop (e.g.
@@ -207,15 +241,77 @@
 
     this->attachToHead(entry);
     fCache.insert(key, entry);
+
+    if (ownershipFlags & kHide_OwnershipFlag) {
+        this->makeExclusive(entry);
+    }
+
+}
+
+void GrResourceCache::makeExclusive(GrResourceCacheEntry* entry) {
+    GrAutoResourceCacheValidate atcv(this);
+
+    SkASSERT(!entry->fIsExclusive);
+    entry->fIsExclusive = true;
+
+    // When scratch textures are detached (to hide them from future finds) they
+    // still count against the resource budget
+    this->internalDetach(entry, kIgnore_BudgetBehavior);
+    fCache.remove(entry->key(), entry);
+
+#ifdef SK_DEBUG
+    fExclusiveList.addToHead(entry);
+#endif
+}
+
+void GrResourceCache::removeInvalidResource(GrResourceCacheEntry* entry) {
+    // If the resource went invalid while it was detached then purge it
+    // This can happen when a 3D context was lost,
+    // the client called GrContext::abandonContext() to notify Gr,
+    // and then later an SkGpuDevice's destructor releases its backing
+    // texture (which was invalidated at contextDestroyed time).
+    // TODO: Safely delete the GrResourceCacheEntry as well.
+    fClientDetachedCount -= 1;
+    fEntryCount -= 1;
+    fClientDetachedBytes -= entry->fCachedSize;
+    fEntryBytes -= entry->fCachedSize;
+    entry->fCachedSize = 0;
+}
+
+void GrResourceCache::makeNonExclusive(GrResourceCacheEntry* entry) {
+    GrAutoResourceCacheValidate atcv(this);
+
+#ifdef SK_DEBUG
+    fExclusiveList.remove(entry);
+#endif
+
+    if (!entry->resource()->wasDestroyed()) {
+        // Since scratch textures still count against the cache budget even
+        // when they have been removed from the cache, re-adding them doesn't
+        // alter the budget information.
+        attachToHead(entry, kIgnore_BudgetBehavior);
+        fCache.insert(entry->key(), entry);
+
+        SkASSERT(entry->fIsExclusive);
+        entry->fIsExclusive = false;
+    } else {
+        this->removeInvalidResource(entry);
+    }
 }
 
 void GrResourceCache::didIncreaseResourceSize(const GrResourceCacheEntry* entry, size_t amountInc) {
     fEntryBytes += amountInc;
+    if (entry->fIsExclusive) {
+        fClientDetachedBytes += amountInc;
+    }
     this->purgeAsNeeded();
 }
 
 void GrResourceCache::didDecreaseResourceSize(const GrResourceCacheEntry* entry, size_t amountDec) {
     fEntryBytes -= amountDec;
+    if (entry->fIsExclusive) {
+        fClientDetachedBytes -= amountDec;
+    }
 #ifdef SK_DEBUG
     this->validate();
 #endif
@@ -263,6 +359,13 @@
     fInvalidationInbox.poll(&invalidated);
 
     for (int i = 0; i < invalidated.count(); i++) {
+        // We're somewhat missing an opportunity here.  We could use the
+        // default find functor that gives us back resources whether we own
+        // them exclusively or not, and when they're not exclusively owned mark
+        // them for purging later when they do become exclusively owned.
+        //
+        // This is complicated and confusing.  May try this in the future.  For
+        // now, these resources are just LRU'd as if we never got the message.
         while (GrResourceCacheEntry* entry = fCache.find(invalidated[i].key, GrTFindUnreffedFunctor())) {
             this->deleteResource(entry);
         }
@@ -270,7 +373,7 @@
 }
 
 void GrResourceCache::deleteResource(GrResourceCacheEntry* entry) {
-    SkASSERT(entry->fResource->isPurgable());
+    SkASSERT(entry->fResource->unique());
 
     // remove from our cache
     fCache.remove(entry->key(), entry);
@@ -309,7 +412,7 @@
             }
 
             GrResourceCacheEntry* prev = iter.prev();
-            if (entry->fResource->isPurgable()) {
+            if (entry->fResource->unique()) {
                 changed = true;
                 this->deleteResource(entry);
             }
@@ -332,7 +435,14 @@
     this->purgeAsNeeded();
 
 #ifdef SK_DEBUG
+    SkASSERT(fExclusiveList.countEntries() == fClientDetachedCount);
+    SkASSERT(countBytes(fExclusiveList) == fClientDetachedBytes);
     if (!fCache.count()) {
+        // Items may have been detached from the cache (such as the backing
+        // texture for an SkGpuDevice). The above purge would not have removed
+        // them.
+        SkASSERT(fEntryCount == fClientDetachedCount);
+        SkASSERT(fEntryBytes == fClientDetachedBytes);
         SkASSERT(fList.isEmpty());
     }
 #endif
@@ -364,26 +474,43 @@
 
 void GrResourceCache::validate() const {
     fList.validate();
+    fExclusiveList.validate();
     SkASSERT(both_zero_or_nonzero(fEntryCount, fEntryBytes));
-    SkASSERT(fEntryCount == fCache.count());
+    SkASSERT(both_zero_or_nonzero(fClientDetachedCount, fClientDetachedBytes));
+    SkASSERT(fClientDetachedBytes <= fEntryBytes);
+    SkASSERT(fClientDetachedCount <= fEntryCount);
+    SkASSERT((fEntryCount - fClientDetachedCount) == fCache.count());
 
     EntryList::Iter iter;
 
-    // check that the shareable entries are okay
-    const GrResourceCacheEntry* entry = iter.init(const_cast<EntryList&>(fList),
+    // check that the exclusively held entries are okay
+    const GrResourceCacheEntry* entry = iter.init(const_cast<EntryList&>(fExclusiveList),
                                                   EntryList::Iter::kHead_IterStart);
 
+    for ( ; entry; entry = iter.next()) {
+        entry->validate();
+    }
+
+    // check that the shareable entries are okay
+    entry = iter.init(const_cast<EntryList&>(fList), EntryList::Iter::kHead_IterStart);
+
     int count = 0;
     for ( ; entry; entry = iter.next()) {
         entry->validate();
         SkASSERT(fCache.find(entry->key()));
         count += 1;
     }
-    SkASSERT(count == fEntryCount);
+    SkASSERT(count == fEntryCount - fClientDetachedCount);
 
-    size_t bytes = this->countBytes(fList);
-    SkASSERT(bytes == fEntryBytes);
-    SkASSERT(fList.countEntries() == fEntryCount);
+    size_t bytes = countBytes(fList);
+    SkASSERT(bytes == fEntryBytes  - fClientDetachedBytes);
+
+    bytes = countBytes(fExclusiveList);
+    SkASSERT(bytes == fClientDetachedBytes);
+
+    SkASSERT(fList.countEntries() == fEntryCount - fClientDetachedCount);
+
+    SkASSERT(fExclusiveList.countEntries() == fClientDetachedCount);
 }
 #endif // SK_DEBUG
 
@@ -407,6 +534,10 @@
                 fEntryCount, locked, fHighWaterEntryCount);
     SkDebugf("\t\tEntry Bytes: current %d high %d\n",
                 fEntryBytes, fHighWaterEntryBytes);
+    SkDebugf("\t\tDetached Entry Count: current %d high %d\n",
+                fClientDetachedCount, fHighWaterClientDetachedCount);
+    SkDebugf("\t\tDetached Bytes: current %d high %d\n",
+                fClientDetachedBytes, fHighWaterClientDetachedBytes);
 }
 
 #endif