ccpr: Use SkMessageBus for thread-safe eviction of cache entries
Bug: skia:
Change-Id: I87725b95761deb689333315ce681a4968d98190a
Reviewed-on: https://skia-review.googlesource.com/c/163511
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/ccpr/GrCCPathCache.h b/src/gpu/ccpr/GrCCPathCache.h
index 7a552bb..e8ce928 100644
--- a/src/gpu/ccpr/GrCCPathCache.h
+++ b/src/gpu/ccpr/GrCCPathCache.h
@@ -24,13 +24,8 @@
*/
class GrCCPathCache {
public:
-#ifdef SK_DEBUG
- ~GrCCPathCache() {
- // Ensure the hash table and LRU list are still coherent.
- fHashTable.reset();
- SkASSERT(fLRU.isEmpty());
- }
-#endif
+ GrCCPathCache(uint32_t contextUniqueID) : fInvalidatedEntriesInbox(contextUniqueID) {}
+ SkDEBUGCODE(~GrCCPathCache();)
// Stores the components of a transformation that affect a path mask (i.e. everything but
// integer translation). During construction, any integer portions of the matrix's translate are
@@ -55,7 +50,9 @@
sk_sp<GrCCPathCacheEntry> find(const GrShape&, const MaskTransform&,
CreateIfAbsent = CreateIfAbsent::kNo);
- void evict(const GrCCPathCacheEntry*);
+ void evict(GrCCPathCacheEntry*);
+
+ void purgeAsNeeded();
private:
// Wrapper around a raw GrShape key that has a specialized operator==. Used by the hash table.
@@ -64,32 +61,38 @@
};
friend bool operator==(const HashKey&, const HashKey&);
- // This is a special ref ptr for GrCCPathCacheEntry, used by the hash table. It can only be
- // moved, which guarantees the hash table holds exactly one reference for each entry. When a
- // HashNode goes out of scope, it therefore means the entry has been evicted from the cache.
+ // This is a special ref ptr for GrCCPathCacheEntry, used by the hash table. It provides static
+ // methods for SkTHash, and can only be moved. This guarantees the hash table holds exactly one
+ // reference for each entry.
class HashNode : SkNoncopyable {
public:
- static HashKey GetKey(const HashNode& node) { return GetKey(node.fEntry); }
+ static HashKey GetKey(const HashNode& node) { return GetKey(node.entry()); }
static HashKey GetKey(const GrCCPathCacheEntry*);
static uint32_t Hash(HashKey);
HashNode() = default;
- HashNode(GrCCPathCache*, const MaskTransform&, const GrShape&);
- HashNode(HashNode&& node) { fEntry = skstd::exchange(node.fEntry, nullptr); }
- ~HashNode(); // Called when fEntry (if not null) has been evicted from the cache.
+ HashNode(uint32_t pathCacheUniqueID, const MaskTransform&, const GrShape&);
+ HashNode(HashNode&& node) : fEntry(std::move(node.fEntry)) {
+ SkASSERT(!node.fEntry);
+ }
- HashNode& operator=(HashNode&&);
+ HashNode& operator=(HashNode&& node) {
+ fEntry = std::move(node.fEntry);
+ SkASSERT(!node.fEntry);
+ return *this;
+ }
- GrCCPathCacheEntry* entry() const { return fEntry; }
+ GrCCPathCacheEntry* entry() const { return fEntry.get(); }
private:
- GrCCPathCacheEntry* fEntry = nullptr;
+ sk_sp<GrCCPathCacheEntry> fEntry;
// The GrShape's unstyled key is stored as a variable-length footer to the 'fEntry'
// allocation. GetKey provides access to it.
};
SkTHashTable<HashNode, HashKey> fHashTable;
SkTInternalLList<GrCCPathCacheEntry> fLRU;
+ SkMessageBus<sk_sp<GrCCPathCacheEntry>>::Inbox fInvalidatedEntriesInbox;
};
/**
@@ -102,6 +105,8 @@
~GrCCPathCacheEntry() override;
+ uint32_t pathCacheUniqueID() const { return fPathCacheUniqueID; }
+
// The number of times this specific entry (path + matrix combination) has been pulled from
// the path cache. As long as the caller does exactly one lookup per draw, this translates to
// the number of times the path has been drawn with a compatible matrix.
@@ -121,15 +126,14 @@
// Called once our path has been rendered into the mainline CCPR (fp16, coverage count) atlas.
// The caller will stash this atlas texture away after drawing, and during the next flush,
// recover it and attempt to copy any paths that got reused into permanent 8-bit atlases.
- void initAsStashedAtlas(const GrUniqueKey& atlasKey, uint32_t contextUniqueID,
- const SkIVector& atlasOffset, const SkRect& devBounds,
- const SkRect& devBounds45, const SkIRect& devIBounds,
- const SkIVector& maskShift);
+ void initAsStashedAtlas(const GrUniqueKey& atlasKey, const SkIVector& atlasOffset,
+ const SkRect& devBounds, const SkRect& devBounds45,
+ const SkIRect& devIBounds, const SkIVector& maskShift);
// Called once our path mask has been copied into a permanent, 8-bit atlas. This method points
// the entry at the new atlas and updates the CachedAtlasInfo data.
- void updateToCachedAtlas(const GrUniqueKey& atlasKey, uint32_t contextUniqueID,
- const SkIVector& newAtlasOffset, sk_sp<GrCCAtlas::CachedAtlasInfo>);
+ void updateToCachedAtlas(const GrUniqueKey& atlasKey, const SkIVector& newAtlasOffset,
+ sk_sp<GrCCAtlas::CachedAtlasInfo>);
const GrUniqueKey& atlasKey() const { return fAtlasKey; }
@@ -153,18 +157,19 @@
private:
using MaskTransform = GrCCPathCache::MaskTransform;
- GrCCPathCacheEntry(GrCCPathCache* cache, const MaskTransform& m)
- : fCacheWeakPtr(cache), fMaskTransform(m) {}
+ GrCCPathCacheEntry(uint32_t pathCacheUniqueID, const MaskTransform& maskTransform)
+ : fPathCacheUniqueID(pathCacheUniqueID), fMaskTransform(maskTransform) {
+ SkASSERT(SK_InvalidUniqueID != fPathCacheUniqueID);
+ }
// Resets this entry back to not having an atlas, and purges its previous atlas texture from the
// resource cache if needed.
void invalidateAtlas();
- // Called when our corresponding path is modified or deleted.
+ // Called when our corresponding path is modified or deleted. Not threadsafe.
void onChange() override;
- uint32_t fContextUniqueID;
- GrCCPathCache* fCacheWeakPtr; // Gets manually reset to null by the path cache upon eviction.
+ const uint32_t fPathCacheUniqueID;
MaskTransform fMaskTransform;
int fHitCount = 1;