| Index: src/gpu/GrResourceCache.cpp
 | 
| ===================================================================
 | 
| --- src/gpu/GrResourceCache.cpp	(revision 9928)
 | 
| +++ src/gpu/GrResourceCache.cpp	(working copy)
 | 
| @@ -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;
 | 
| +    if (fPurging) {
 | 
| +        return;
 | 
| +    }
 | 
|  
 | 
| -        // The purging process is repeated several times since one pass
 | 
| -        // may free up other resources
 | 
| -        do {
 | 
| -            EntryList::Iter iter;
 | 
| +    fPurging = true;
 | 
|  
 | 
| -            changed = false;
 | 
| +    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();
 | 
| +        }
 | 
| +    }
 | 
|  
 | 
| -            // 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);
 | 
| +    fPurging = false;
 | 
| +}
 | 
|  
 | 
| -            while (NULL != entry) {
 | 
| -                GrAutoResourceCacheValidate atcv(this);
 | 
| +void GrResourceCache::internalPurge() {
 | 
| +    SkASSERT(fPurging);
 | 
|  
 | 
| -                if (fEntryCount <= fMaxCount && fEntryBytes <= fMaxBytes) {
 | 
| -                    withinBudget = true;
 | 
| -                    break;
 | 
| -                }
 | 
| +    bool withinBudget = false;
 | 
| +    bool changed = false;
 | 
|  
 | 
| -                GrResourceEntry* prev = iter.prev();
 | 
| -                if (1 == entry->fResource->getRefCnt()) {
 | 
| -                    changed = true;
 | 
| +    // The purging process is repeated several times since one pass
 | 
| +    // may free up other resources
 | 
| +    do {
 | 
| +        EntryList::Iter iter;
 | 
|  
 | 
| -                    // remove from our cache
 | 
| -                    fCache.remove(entry->key(), entry);
 | 
| +        changed = false;
 | 
|  
 | 
| -                    // remove from our llist
 | 
| -                    this->internalDetach(entry);
 | 
| -                    delete entry;
 | 
| -                }
 | 
| -                entry = prev;
 | 
| +        // 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;
 | 
|              }
 | 
| -        } while (!withinBudget && changed);
 | 
| -        fPurging = false;
 | 
| -    }
 | 
| +
 | 
| +            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() {
 | 
| 
 |