Allow the resource cache to (indirectly) flush the InOrderDrawBuffer

R=bsalomon@google.com

Author: robertphillips@google.com

Review URL: https://chromiumcodereview.appspot.com/18466005

git-svn-id: http://skia.googlecode.com/svn/trunk@9949 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp
index fa4edad..baae6bd 100644
--- a/src/gpu/GrResourceCache.cpp
+++ b/src/gpu/GrResourceCache.cpp
@@ -62,7 +62,10 @@
     fClientDetachedCount          = 0;
     fClientDetachedBytes          = 0;
 
-    fPurging = false;
+    fPurging                      = false;
+
+    fOverbudgetCB                 = NULL;
+    fOverbudgetData               = NULL;
 }
 
 GrResourceCache::~GrResourceCache() {
@@ -275,48 +278,66 @@
  * potentially make purgeAsNeeded loop infinitely.
  */
 void GrResourceCache::purgeAsNeeded() {
-    if (!fPurging) {
-        fPurging = true;
-        bool withinBudget = false;
-        bool changed = false;
-
-        // The purging process is repeated several times since one pass
-        // may free up other resources
-        do {
-            EntryList::Iter iter;
-
-            changed = false;
-
-            // Note: the following code relies on the fact that the
-            // doubly linked list doesn't invalidate its data/pointers
-            // outside of the specific area where a deletion occurs (e.g.,
-            // in internalDetach)
-            GrResourceEntry* entry = iter.init(fList, EntryList::Iter::kTail_IterStart);
-
-            while (NULL != entry) {
-                GrAutoResourceCacheValidate atcv(this);
-
-                if (fEntryCount <= fMaxCount && fEntryBytes <= fMaxBytes) {
-                    withinBudget = true;
-                    break;
-                }
-
-                GrResourceEntry* prev = iter.prev();
-                if (1 == entry->fResource->getRefCnt()) {
-                    changed = true;
-
-                    // remove from our cache
-                    fCache.remove(entry->key(), entry);
-
-                    // remove from our llist
-                    this->internalDetach(entry);
-                    delete entry;
-                }
-                entry = prev;
-            }
-        } while (!withinBudget && changed);
-        fPurging = false;
+    if (fPurging) {
+        return;
     }
+
+    fPurging = true;
+
+    this->internalPurge();
+    if ((fEntryCount > fMaxCount || fEntryBytes > fMaxBytes) &&
+        NULL != fOverbudgetCB) {
+        // Despite the purge we're still over budget. See if Ganesh can
+        // release some resources and purge again.
+        if ((*fOverbudgetCB)(fOverbudgetData)) {
+            this->internalPurge();
+        }
+    }
+
+    fPurging = false;
+}
+
+void GrResourceCache::internalPurge() {
+    SkASSERT(fPurging);
+
+    bool withinBudget = false;
+    bool changed = false;
+
+    // The purging process is repeated several times since one pass
+    // may free up other resources
+    do {
+        EntryList::Iter iter;
+
+        changed = false;
+
+        // Note: the following code relies on the fact that the
+        // doubly linked list doesn't invalidate its data/pointers
+        // outside of the specific area where a deletion occurs (e.g.,
+        // in internalDetach)
+        GrResourceEntry* entry = iter.init(fList, EntryList::Iter::kTail_IterStart);
+
+        while (NULL != entry) {
+            GrAutoResourceCacheValidate atcv(this);
+
+            if (fEntryCount <= fMaxCount && fEntryBytes <= fMaxBytes) {
+                withinBudget = true;
+                break;
+            }
+
+            GrResourceEntry* prev = iter.prev();
+            if (1 == entry->fResource->getRefCnt()) {
+                changed = true;
+
+                // remove from our cache
+                fCache.remove(entry->key(), entry);
+
+                // remove from our llist
+                this->internalDetach(entry);
+                delete entry;
+            }
+            entry = prev;
+        }
+    } while (!withinBudget && changed);
 }
 
 void GrResourceCache::purgeAllUnlocked() {