ccpr: Age out path cache entries
Adds a hook that gets called from GrContext::performDeferredCleanup.
Bug: skia:8452
Change-Id: I4e5f4d263528b21247fbc032a1b4881a23cbb2ff
Reviewed-on: https://skia-review.googlesource.com/c/167181
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/ccpr/GrCCPathCache.cpp b/src/gpu/ccpr/GrCCPathCache.cpp
index 4816858..a5b9a10 100644
--- a/src/gpu/ccpr/GrCCPathCache.cpp
+++ b/src/gpu/ccpr/GrCCPathCache.cpp
@@ -209,17 +209,18 @@
if (HashNode* node = fHashTable.find(*fScratchKey)) {
entry = node->entry();
SkASSERT(fLRU.isInList(entry));
- if (fuzzy_equals(m, entry->fMaskTransform)) {
- ++entry->fHitCount; // The path was reused with a compatible matrix.
- } else if (CreateIfAbsent::kYes == createIfAbsent && entry->unique()) {
- // This entry is unique: we can recycle it instead of deleting and malloc-ing a new one.
- entry->fMaskTransform = m;
- entry->fHitCount = 1;
- entry->invalidateAtlas();
- SkASSERT(!entry->fCurrFlushAtlas); // Should be null because 'entry' is unique.
- } else {
- this->evict(*fScratchKey);
- entry = nullptr;
+ if (!fuzzy_equals(m, entry->fMaskTransform)) {
+ // The path was reused with an incompatible matrix.
+ if (CreateIfAbsent::kYes == createIfAbsent && entry->unique()) {
+ // This entry is unique: recycle it instead of deleting and malloc-ing a new one.
+ entry->fMaskTransform = m;
+ entry->fHitCount = 0;
+ entry->invalidateAtlas();
+ SkASSERT(!entry->fCurrFlushAtlas); // Should be null because 'entry' is unique.
+ } else {
+ this->evict(*fScratchKey);
+ entry = nullptr;
+ }
}
}
@@ -248,10 +249,41 @@
SkDEBUGCODE(HashNode* node = fHashTable.find(*fScratchKey));
SkASSERT(node && node->entry() == entry);
fLRU.addToHead(entry);
+
+ entry->fTimestamp = this->quickPerFlushTimestamp();
+ ++entry->fHitCount;
return sk_ref_sp(entry);
}
-void GrCCPathCache::purgeAsNeeded() {
+void GrCCPathCache::doPostFlushProcessing() {
+ this->purgeInvalidatedKeys();
+
+ // Mark the per-flush timestamp as needing to be updated with a newer clock reading.
+ fPerFlushTimestamp = GrStdSteadyClock::time_point::min();
+}
+
+void GrCCPathCache::purgeEntriesOlderThan(const GrStdSteadyClock::time_point& purgeTime) {
+ this->purgeInvalidatedKeys();
+
+#ifdef SK_DEBUG
+ auto lastTimestamp = (fLRU.isEmpty())
+ ? GrStdSteadyClock::time_point::max()
+ : fLRU.tail()->fTimestamp;
+#endif
+
+ // Drop every cache entry whose timestamp is older than purgeTime.
+ while (!fLRU.isEmpty() && fLRU.tail()->fTimestamp < purgeTime) {
+#ifdef SK_DEBUG
+ // Verify that fLRU is sorted by timestamp.
+ auto timestamp = fLRU.tail()->fTimestamp;
+ SkASSERT(timestamp >= lastTimestamp);
+ lastTimestamp = timestamp;
+#endif
+ this->evict(*fLRU.tail()->fCacheKey);
+ }
+}
+
+void GrCCPathCache::purgeInvalidatedKeys() {
SkTArray<sk_sp<Key>> invalidatedKeys;
fInvalidatedKeysInbox.poll(&invalidatedKeys);
for (const sk_sp<Key>& key : invalidatedKeys) {