Index: src/gpu/GrResourceCache.cpp |
diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp |
index 5cb1dd2a94f0b2933503500a0c8b93e9ee35aaea..d87e1a5b588211fe70716f6cc6cd1024487b23c3 100644 |
--- a/src/gpu/GrResourceCache.cpp |
+++ b/src/gpu/GrResourceCache.cpp |
@@ -58,7 +58,8 @@ static const int kDefaultMaxCount = 2 * (1 << 10); |
static const size_t kDefaultMaxSize = 96 * (1 << 20); |
GrResourceCache::GrResourceCache() |
- : fMaxCount(kDefaultMaxCount) |
+ : fTimestamp(0) |
+ , fMaxCount(kDefaultMaxCount) |
, fMaxBytes(kDefaultMaxSize) |
#if GR_CACHE_STATS |
, fHighWaterCount(0) |
@@ -70,8 +71,6 @@ GrResourceCache::GrResourceCache() |
, fBytes(0) |
, fBudgetedCount(0) |
, fBudgetedBytes(0) |
- , fPurging(false) |
- , fNewlyPurgeableResourceWhilePurging(false) |
, fOverBudgetCB(NULL) |
, fOverBudgetData(NULL) { |
} |
@@ -90,7 +89,6 @@ void GrResourceCache::insertResource(GrGpuResource* resource) { |
SkASSERT(resource); |
SkASSERT(!resource->wasDestroyed()); |
SkASSERT(!this->isInCache(resource)); |
- SkASSERT(!fPurging); |
fResources.addToHead(resource); |
size_t size = resource->gpuMemorySize(); |
@@ -112,13 +110,20 @@ void GrResourceCache::insertResource(GrGpuResource* resource) { |
SkASSERT(!resource->cacheAccess().isWrapped()); |
fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource); |
} |
- |
+ |
+ resource->cacheAccess().setTimestamp(fTimestamp++); |
+ |
this->purgeAsNeeded(); |
} |
void GrResourceCache::removeResource(GrGpuResource* resource) { |
+ this->validate(); |
SkASSERT(this->isInCache(resource)); |
+ if (resource->isPurgeable()) { |
+ fPurgeableQueue.remove(resource); |
+ } |
+ |
size_t size = resource->gpuMemorySize(); |
--fCount; |
fBytes -= size; |
@@ -140,7 +145,6 @@ void GrResourceCache::removeResource(GrGpuResource* resource) { |
void GrResourceCache::abandonAll() { |
AutoValidate av(this); |
- SkASSERT(!fPurging); |
while (GrGpuResource* head = fResources.head()) { |
SkASSERT(!head->wasDestroyed()); |
head->cacheAccess().abandon(); |
@@ -158,7 +162,6 @@ void GrResourceCache::abandonAll() { |
void GrResourceCache::releaseAll() { |
AutoValidate av(this); |
- SkASSERT(!fPurging); |
while (GrGpuResource* head = fResources.head()) { |
SkASSERT(!head->wasDestroyed()); |
head->cacheAccess().release(); |
@@ -188,16 +191,14 @@ private: |
}; |
GrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& scratchKey, |
- uint32_t flags) { |
- SkASSERT(!fPurging); |
+ uint32_t flags) { |
SkASSERT(scratchKey.isValid()); |
GrGpuResource* resource; |
if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFlag)) { |
resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true)); |
if (resource) { |
- resource->ref(); |
- this->makeResourceMRU(resource); |
+ this->refAndMakeResourceMRU(resource); |
this->validate(); |
return resource; |
} else if (flags & kRequireNoPendingIO_ScratchFlag) { |
@@ -208,8 +209,7 @@ GrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& sc |
} |
resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false)); |
if (resource) { |
- resource->ref(); |
- this->makeResourceMRU(resource); |
+ this->refAndMakeResourceMRU(resource); |
this->validate(); |
} |
return resource; |
@@ -228,7 +228,6 @@ void GrResourceCache::willRemoveContentKey(const GrGpuResource* resource) { |
} |
bool GrResourceCache::didSetContentKey(GrGpuResource* resource) { |
- SkASSERT(!fPurging); |
SkASSERT(resource); |
SkASSERT(this->isInCache(resource)); |
SkASSERT(resource->getContentKey().isValid()); |
@@ -243,12 +242,16 @@ bool GrResourceCache::didSetContentKey(GrGpuResource* resource) { |
return true; |
} |
-void GrResourceCache::makeResourceMRU(GrGpuResource* resource) { |
- SkASSERT(!fPurging); |
+void GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) { |
SkASSERT(resource); |
SkASSERT(this->isInCache(resource)); |
- fResources.remove(resource); |
- fResources.addToHead(resource); |
+ if (resource->isPurgeable()) { |
+ // It's about to become unpurgeable. |
+ fPurgeableQueue.remove(resource); |
+ } |
+ resource->ref(); |
+ resource->cacheAccess().setTimestamp(fTimestamp++); |
+ SkASSERT(!resource->isPurgeable()); |
} |
void GrResourceCache::notifyPurgeable(GrGpuResource* resource) { |
@@ -256,49 +259,37 @@ void GrResourceCache::notifyPurgeable(GrGpuResource* resource) { |
SkASSERT(this->isInCache(resource)); |
SkASSERT(resource->isPurgeable()); |
- // We can't purge if in the middle of purging because purge is iterating. Instead record |
- // that additional resources became purgeable. |
- if (fPurging) { |
- fNewlyPurgeableResourceWhilePurging = true; |
- return; |
- } |
- |
- bool release = false; |
+ SkASSERT(-1 == *resource->cacheAccess().accessCacheIndex()); |
+ fPurgeableQueue.insert(resource); |
- if (resource->cacheAccess().isWrapped()) { |
- release = true; |
- } else if (!resource->resourcePriv().isBudgeted()) { |
+ if (!resource->resourcePriv().isBudgeted()) { |
// Check whether this resource could still be used as a scratch resource. |
- if (resource->resourcePriv().getScratchKey().isValid()) { |
+ if (!resource->cacheAccess().isWrapped() && |
+ resource->resourcePriv().getScratchKey().isValid()) { |
// We won't purge an existing resource to make room for this one. |
bool underBudget = fBudgetedCount < fMaxCount && |
fBudgetedBytes + resource->gpuMemorySize() <= fMaxBytes; |
if (underBudget) { |
resource->resourcePriv().makeBudgeted(); |
- } else { |
- release = true; |
+ return; |
} |
- } else { |
- release = true; |
} |
} else { |
- // Purge the resource if we're over budget |
+ // Purge the resource immediately if we're over budget |
bool overBudget = fBudgetedCount > fMaxCount || fBudgetedBytes > fMaxBytes; |
// Also purge if the resource has neither a valid scratch key nor a content key. |
bool noKey = !resource->resourcePriv().getScratchKey().isValid() && |
- !resource->getContentKey().isValid(); |
- if (overBudget || noKey) { |
- release = true; |
+ !resource->getContentKey().isValid(); |
+ if (!overBudget && !noKey) { |
+ return; |
} |
} |
- if (release) { |
- SkDEBUGCODE(int beforeCount = fCount;) |
- resource->cacheAccess().release(); |
- // We should at least free this resource, perhaps dependent resources as well. |
- SkASSERT(fCount < beforeCount); |
- } |
+ SkDEBUGCODE(int beforeCount = fCount;) |
+ resource->cacheAccess().release(); |
+ // We should at least free this resource, perhaps dependent resources as well. |
+ SkASSERT(fCount < beforeCount); |
this->validate(); |
} |
@@ -325,7 +316,6 @@ void GrResourceCache::didChangeGpuMemorySize(const GrGpuResource* resource, size |
} |
void GrResourceCache::didChangeBudgetStatus(GrGpuResource* resource) { |
- SkASSERT(!fPurging); |
SkASSERT(resource); |
SkASSERT(this->isInCache(resource)); |
@@ -348,67 +338,38 @@ void GrResourceCache::didChangeBudgetStatus(GrGpuResource* resource) { |
} |
void GrResourceCache::internalPurgeAsNeeded() { |
- SkASSERT(!fPurging); |
- SkASSERT(!fNewlyPurgeableResourceWhilePurging); |
SkASSERT(fBudgetedCount > fMaxCount || fBudgetedBytes > fMaxBytes); |
- fPurging = true; |
- |
- bool overBudget = true; |
- do { |
- fNewlyPurgeableResourceWhilePurging = false; |
- ResourceList::Iter resourceIter; |
- GrGpuResource* resource = resourceIter.init(fResources, |
- ResourceList::Iter::kTail_IterStart); |
- |
- while (resource) { |
- GrGpuResource* prev = resourceIter.prev(); |
- if (resource->isPurgeable()) { |
- resource->cacheAccess().release(); |
- } |
- resource = prev; |
- if (fBudgetedCount <= fMaxCount && fBudgetedBytes <= fMaxBytes) { |
- overBudget = false; |
- resource = NULL; |
- } |
- } |
- |
- if (!fNewlyPurgeableResourceWhilePurging && overBudget && fOverBudgetCB) { |
- // Despite the purge we're still over budget. Call our over budget callback. |
- (*fOverBudgetCB)(fOverBudgetData); |
+ bool stillOverbudget = true; |
+ while (fPurgeableQueue.count()) { |
+ GrGpuResource* resource = fPurgeableQueue.peek(); |
+ SkASSERT(resource->isPurgeable()); |
+ resource->cacheAccess().release(); |
+ if (fBudgetedCount <= fMaxCount && fBudgetedBytes <= fMaxBytes) { |
+ stillOverbudget = false; |
+ break; |
} |
- } while (overBudget && fNewlyPurgeableResourceWhilePurging); |
+ } |
- fNewlyPurgeableResourceWhilePurging = false; |
- fPurging = false; |
this->validate(); |
+ |
+ if (stillOverbudget) { |
+ // Despite the purge we're still over budget. Call our over budget callback. If this frees |
+ // any resources then we'll get notifyPurgeable() calls and take appropriate action. |
+ (*fOverBudgetCB)(fOverBudgetData); |
+ this->validate(); |
+ } |
} |
void GrResourceCache::purgeAllUnlocked() { |
- SkASSERT(!fPurging); |
- SkASSERT(!fNewlyPurgeableResourceWhilePurging); |
- |
- fPurging = true; |
- |
- do { |
- fNewlyPurgeableResourceWhilePurging = false; |
- ResourceList::Iter resourceIter; |
- GrGpuResource* resource = |
- resourceIter.init(fResources, ResourceList::Iter::kTail_IterStart); |
- |
- while (resource) { |
- GrGpuResource* prev = resourceIter.prev(); |
- if (resource->isPurgeable()) { |
- resource->cacheAccess().release(); |
- } |
- resource = prev; |
- } |
+ // We could disable maintaining the heap property here, but it would add a lot of complexity. |
+ // Moreover, this is rarely called. |
+ while (fPurgeableQueue.count()) { |
+ GrGpuResource* resource = fPurgeableQueue.peek(); |
+ SkASSERT(resource->isPurgeable()); |
+ resource->cacheAccess().release(); |
+ } |
- if (!fNewlyPurgeableResourceWhilePurging && fCount && fOverBudgetCB) { |
- (*fOverBudgetCB)(fOverBudgetData); |
- } |
- } while (fNewlyPurgeableResourceWhilePurging); |
- fPurging = false; |
this->validate(); |
} |
@@ -475,8 +436,17 @@ void GrResourceCache::validate() const { |
++budgetedCount; |
budgetedBytes += resource->gpuMemorySize(); |
} |
+ |
+ if (!resource->isPurgeable()) { |
+ SkASSERT(-1 == *resource->cacheAccess().accessCacheIndex()); |
+ } |
+ } |
+ |
+ for (int i = 0; i < fPurgeableQueue.count(); ++i) { |
+ SkASSERT(fPurgeableQueue.at(i)->isPurgeable()); |
} |
+ SkASSERT(fCount - locked == fPurgeableQueue.count()); |
SkASSERT(fBudgetedCount <= fCount); |
SkASSERT(fBudgetedBytes <= fBudgetedBytes); |
SkASSERT(bytes == fBytes); |