diff options
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrContext.cpp | 14 | ||||
-rw-r--r-- | src/gpu/GrResourceCache.cpp | 105 | ||||
-rw-r--r-- | src/gpu/GrResourceCache.h | 26 |
3 files changed, 102 insertions, 43 deletions
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 78220c0279..39d0db33b4 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -541,6 +541,20 @@ void GrContext::purgeCache() { } } +bool GrContext::OverbudgetCB(void* data) { + GrAssert(NULL != data); + + GrContext* context = reinterpret_cast<GrContext*>(data); + + // Flush the InOrderDrawBuffer to possibly free up some textures + context->flush(); + + // TODO: actually track flush's behavior rather than always just + // returning true. + return true; +} + + GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& descIn, void* srcData, size_t rowBytes) { diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp index fa4edadfe9..baae6bd31c 100644 --- a/src/gpu/GrResourceCache.cpp +++ b/src/gpu/GrResourceCache.cpp @@ -62,7 +62,10 @@ GrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) : fClientDetachedCount = 0; fClientDetachedBytes = 0; - fPurging = false; + fPurging = false; + + fOverbudgetCB = NULL; + fOverbudgetData = NULL; } GrResourceCache::~GrResourceCache() { @@ -275,48 +278,66 @@ void GrResourceCache::makeNonExclusive(GrResourceEntry* entry) { * 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() { diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h index c4ead34595..5ac4bf17ae 100644 --- a/src/gpu/GrResourceCache.h +++ b/src/gpu/GrResourceCache.h @@ -238,6 +238,25 @@ public: void setLimits(int maxResource, size_t maxResourceBytes); /** + * The callback function used by the cache when it is still over budget + * after a purge. The passed in 'data' is the same 'data' handed to + * setOverbudgetCallback. The callback returns true if some resources + * have been freed. + */ + typedef bool (*PFOverbudgetCB)(void* data); + + /** + * Set the callback the cache should use when it is still over budget + * after a purge. The 'data' provided here will be passed back to the + * callback. The cache will attempt to purge any resources newly freed + * by the callback. + */ + void setOverbudgetCallback(PFOverbudgetCB overbudgetCB, void* data) { + fOverbudgetCB = overbudgetCB; + fOverbudgetData = data; + } + + /** * Returns the number of bytes consumed by cached resources. */ size_t getCachedResourceBytes() const { return fEntryBytes; } @@ -360,7 +379,12 @@ private: size_t fClientDetachedBytes; // prevents recursive purging - bool fPurging; + bool fPurging; + + PFOverbudgetCB fOverbudgetCB; + void* fOverbudgetData; + + void internalPurge(); #if GR_DEBUG static size_t countBytes(const SkTInternalLList<GrResourceEntry>& list); |