Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(263)

Unified Diff: src/gpu/GrResourceCache.cpp

Issue 1032873002: Add mechanism to proactively purge old resources in GrResourceCache. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Add comment Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/gpu/GrResourceCache.h ('k') | tests/ResourceCacheTest.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/gpu/GrResourceCache.cpp
diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp
index f8b1a1266e2848d0abddd6a4ddd62ac08fc425ea..f1a51b06c34971b8d4675c1c5aabed829ca45b52 100644
--- a/src/gpu/GrResourceCache.cpp
+++ b/src/gpu/GrResourceCache.cpp
@@ -40,6 +40,7 @@ GrUniqueKey::Domain GrUniqueKey::GenerateDomain() {
return static_cast<Domain>(domain);
}
+
uint32_t GrResourceKeyHash(const uint32_t* data, size_t size) {
return SkChecksum::Compute(data, size);
}
@@ -56,13 +57,12 @@ private:
//////////////////////////////////////////////////////////////////////////////
-static const int kDefaultMaxCount = 2 * (1 << 12);
-static const size_t kDefaultMaxSize = 96 * (1 << 20);
GrResourceCache::GrResourceCache()
: fTimestamp(0)
, fMaxCount(kDefaultMaxCount)
, fMaxBytes(kDefaultMaxSize)
+ , fMaxUnusedFlushes(kDefaultMaxUnusedFlushes)
#if GR_CACHE_STATS
, fHighWaterCount(0)
, fHighWaterBytes(0)
@@ -73,20 +73,49 @@ GrResourceCache::GrResourceCache()
, fBudgetedCount(0)
, fBudgetedBytes(0)
, fOverBudgetCB(NULL)
- , fOverBudgetData(NULL) {
+ , fOverBudgetData(NULL)
+ , fFlushTimestamps(NULL)
+ , fLastFlushTimestampIndex(0){
SkDEBUGCODE(fCount = 0;)
+ SkDEBUGCODE(fNewlyPurgeableResourceForValidation = NULL;)
+ this->resetFlushTimestamps();
}
GrResourceCache::~GrResourceCache() {
this->releaseAll();
+ SkDELETE(fFlushTimestamps);
}
-void GrResourceCache::setLimits(int count, size_t bytes) {
+void GrResourceCache::setLimits(int count, size_t bytes, int maxUnusedFlushes) {
fMaxCount = count;
fMaxBytes = bytes;
+ fMaxUnusedFlushes = maxUnusedFlushes;
+ this->resetFlushTimestamps();
this->purgeAsNeeded();
}
+void GrResourceCache::resetFlushTimestamps() {
+ SkDELETE(fFlushTimestamps);
+
+ // We assume this number is a power of two when wrapping indices into the timestamp array.
+ fMaxUnusedFlushes = SkNextPow2(fMaxUnusedFlushes);
+
+ // Since our implementation is to store the timestamps of the last fMaxUnusedFlushes flush calls
+ // we just turn the feature off if that array would be large.
+ static const int kMaxSupportedTimestampHistory = 128;
+
+ if (fMaxUnusedFlushes > kMaxSupportedTimestampHistory) {
+ fFlushTimestamps = NULL;
+ return;
+ }
+
+ fFlushTimestamps = SkNEW_ARRAY(uint32_t, fMaxUnusedFlushes);
+ fLastFlushTimestampIndex = 0;
+ // Set all the historical flush timestamps to initially be at the beginning of time (timestamp
+ // 0).
+ sk_bzero(fFlushTimestamps, fMaxUnusedFlushes * sizeof(uint32_t));
+}
+
void GrResourceCache::insertResource(GrGpuResource* resource) {
SkASSERT(resource);
SkASSERT(!this->isInCache(resource));
@@ -247,8 +276,8 @@ void GrResourceCache::willRemoveScratchKey(const GrGpuResource* resource) {
}
void GrResourceCache::removeUniqueKey(GrGpuResource* resource) {
- // Someone has a ref to this resource in order to invalidate it. When the ref count reaches
- // zero we will get a notifyPurgable() and figure out what to do with it.
+ // Someone has a ref to this resource in order to have removed the key. When the ref count
+ // reaches zero we will get a ref cnt notification and figure out what to do with it.
if (resource->getUniqueKey().isValid()) {
SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
fUniqueHash.remove(resource->getUniqueKey());
@@ -307,11 +336,34 @@ void GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) {
this->validate();
}
-void GrResourceCache::notifyPurgeable(GrGpuResource* resource) {
+void GrResourceCache::notifyCntReachedZero(GrGpuResource* resource, uint32_t flags) {
SkASSERT(resource);
+ SkASSERT(!resource->wasDestroyed());
+ SkASSERT(flags);
SkASSERT(this->isInCache(resource));
- SkASSERT(resource->isPurgeable());
+ // This resource should always be in the nonpurgeable array when this function is called. It
+ // will be moved to the queue if it is newly purgeable.
+ SkASSERT(fNonpurgeableResources[*resource->cacheAccess().accessCacheIndex()] == resource);
+
+ if (SkToBool(ResourceAccess::kRefCntReachedZero_RefNotificationFlag & flags)) {
+#ifdef SK_DEBUG
+ // When the timestamp overflows validate() is called. validate() checks that resources in
+ // the nonpurgeable array are indeed not purgeable. However, the movement from the array to
+ // the purgeable queue happens just below in this function. So we mark it as an exception.
+ if (resource->isPurgeable()) {
+ fNewlyPurgeableResourceForValidation = resource;
+ }
+#endif
+ resource->cacheAccess().setTimestamp(this->getNextTimestamp());
+ SkDEBUGCODE(fNewlyPurgeableResourceForValidation = NULL);
+ }
+ if (!SkToBool(ResourceAccess::kAllCntsReachedZero_RefNotificationFlag & flags)) {
+ SkASSERT(!resource->isPurgeable());
+ return;
+ }
+
+ SkASSERT(resource->isPurgeable());
this->removeFromNonpurgeableArray(resource);
fPurgeableQueue.insert(resource);
@@ -391,25 +443,43 @@ void GrResourceCache::didChangeBudgetStatus(GrGpuResource* resource) {
this->validate();
}
-void GrResourceCache::internalPurgeAsNeeded() {
- SkASSERT(this->overBudget());
+void GrResourceCache::purgeAsNeeded() {
+ SkTArray<GrUniqueKeyInvalidatedMessage> invalidKeyMsgs;
+ fInvalidUniqueKeyInbox.poll(&invalidKeyMsgs);
+ if (invalidKeyMsgs.count()) {
+ this->processInvalidUniqueKeys(invalidKeyMsgs);
+ }
- bool stillOverbudget = true;
- while (fPurgeableQueue.count()) {
+ if (fFlushTimestamps) {
+ // Assuming kNumFlushesToDeleteUnusedResource is a power of 2.
+ SkASSERT(SkIsPow2(fMaxUnusedFlushes));
+ int oldestFlushIndex = (fLastFlushTimestampIndex + 1) & (fMaxUnusedFlushes - 1);
+
+ uint32_t oldestAllowedTimestamp = fFlushTimestamps[oldestFlushIndex];
+ while (fPurgeableQueue.count()) {
+ uint32_t oldestResourceTimestamp = fPurgeableQueue.peek()->cacheAccess().timestamp();
+ if (oldestAllowedTimestamp < oldestResourceTimestamp) {
+ break;
+ }
+ GrGpuResource* resource = fPurgeableQueue.peek();
+ SkASSERT(resource->isPurgeable());
+ resource->cacheAccess().release();
+ }
+ }
+
+ bool stillOverbudget = this->overBudget();
+ while (stillOverbudget && fPurgeableQueue.count()) {
GrGpuResource* resource = fPurgeableQueue.peek();
SkASSERT(resource->isPurgeable());
resource->cacheAccess().release();
- if (!this->overBudget()) {
- stillOverbudget = false;
- break;
- }
+ stillOverbudget = this->overBudget();
}
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.
+ // any resources then we'll get notified and take appropriate action.
(*fOverBudgetCB)(fOverBudgetData);
this->validate();
}
@@ -433,7 +503,7 @@ void GrResourceCache::processInvalidUniqueKeys(
GrGpuResource* resource = this->findAndRefUniqueResource(msgs[i].key());
if (resource) {
resource->resourcePriv().removeUniqueKey();
- resource->unref(); // will call notifyPurgeable, if it is indeed now purgeable.
+ resource->unref(); // If this resource is now purgeable, the cache will be notified.
}
}
}
@@ -518,11 +588,26 @@ uint32_t GrResourceCache::getNextTimestamp() {
// count should be the next timestamp we return.
SkASSERT(fTimestamp == SkToU32(count));
+
+ // The historical timestamps of flushes are now invalid.
+ this->resetFlushTimestamps();
}
}
return fTimestamp++;
}
+void GrResourceCache::notifyFlushOccurred() {
+ if (fFlushTimestamps) {
+ SkASSERT(SkIsPow2(fMaxUnusedFlushes));
+ fLastFlushTimestampIndex = (fLastFlushTimestampIndex + 1) & (fMaxUnusedFlushes - 1);
+ // get the timestamp before accessing fFlushTimestamps because getNextTimestamp will
+ // reallocate fFlushTimestamps on timestamp overflow.
+ uint32_t timestamp = this->getNextTimestamp();
+ fFlushTimestamps[fLastFlushTimestampIndex] = timestamp;
+ this->purgeAsNeeded();
+ }
+}
+
#ifdef SK_DEBUG
void GrResourceCache::validate() const {
// Reduce the frequency of validations for large resource counts.
@@ -586,7 +671,8 @@ void GrResourceCache::validate() const {
Stats stats(this);
for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
- SkASSERT(!fNonpurgeableResources[i]->isPurgeable());
+ SkASSERT(!fNonpurgeableResources[i]->isPurgeable() ||
+ fNewlyPurgeableResourceForValidation == fNonpurgeableResources[i]);
SkASSERT(*fNonpurgeableResources[i]->cacheAccess().accessCacheIndex() == i);
SkASSERT(!fNonpurgeableResources[i]->wasDestroyed());
stats.update(fNonpurgeableResources[i]);
@@ -615,7 +701,7 @@ void GrResourceCache::validate() const {
SkASSERT(stats.fContent == fUniqueHash.count());
SkASSERT(stats.fScratch + stats.fCouldBeScratch == fScratchMap.count());
- // This assertion is not currently valid because we can be in recursive notifyIsPurgeable()
+ // This assertion is not currently valid because we can be in recursive notifyCntReachedZero()
// calls. This will be fixed when subresource registration is explicit.
// bool overBudget = budgetedBytes > fMaxBytes || budgetedCount > fMaxCount;
// SkASSERT(!overBudget || locked == count || fPurging);
« no previous file with comments | « src/gpu/GrResourceCache.h ('k') | tests/ResourceCacheTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698