ccpr: Don't use cache entries as path listeners
Allocates a separate "Key" object that holds the key and listens on the
path. This eliminates threading concerns and automatically fixes the
recycling logic.
Bug: skia:8452
Change-Id: I9b446ddf1d5da7bc44a8c1c3ff4c4efc0fdc97b1
Reviewed-on: https://skia-review.googlesource.com/c/166100
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 c0e3cef..16f31d0 100644
--- a/src/gpu/ccpr/GrCCPathCache.h
+++ b/src/gpu/ccpr/GrCCPathCache.h
@@ -27,6 +27,42 @@
GrCCPathCache();
~GrCCPathCache();
+ class Key : public SkPathRef::GenIDChangeListener {
+ public:
+ static sk_sp<Key> Make(uint32_t pathCacheUniqueID, int dataCountU32,
+ const void* data = nullptr);
+
+ uint32_t pathCacheUniqueID() const { return fPathCacheUniqueID; }
+
+ int dataSizeInBytes() const { return fDataSizeInBytes; }
+ const uint32_t* data() const;
+
+ void resetDataCountU32(int dataCountU32) {
+ SkASSERT(dataCountU32 <= fDataReserveCountU32);
+ fDataSizeInBytes = dataCountU32 * sizeof(uint32_t);
+ }
+ uint32_t* data();
+
+ bool operator==(const Key&) const;
+
+ // Called when our corresponding path is modified or deleted. Not threadsafe.
+ void onChange() override;
+
+ private:
+ Key(uint32_t pathCacheUniqueID, int dataCountU32)
+ : fPathCacheUniqueID(pathCacheUniqueID)
+ , fDataSizeInBytes(dataCountU32 * sizeof(uint32_t))
+ SkDEBUGCODE(, fDataReserveCountU32(dataCountU32)) {
+ SkASSERT(SK_InvalidUniqueID != fPathCacheUniqueID);
+ }
+
+ const uint32_t fPathCacheUniqueID;
+ int fDataSizeInBytes;
+ SkDEBUGCODE(const int fDataReserveCountU32);
+ // The GrShape's unstyled key is stored as a variable-length footer to this class. GetKey
+ // provides access to it.
+ };
+
// 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
// shaved off and returned to the caller. The caller is responsible for those integer shifts.
@@ -50,29 +86,20 @@
sk_sp<GrCCPathCacheEntry> find(const GrShape&, const MaskTransform&,
CreateIfAbsent = CreateIfAbsent::kNo);
- void evict(GrCCPathCacheEntry*);
-
void purgeAsNeeded();
private:
- // Wrapper around a raw GrShape key that has a specialized operator==. Used by the hash table.
- struct HashKey {
- const uint32_t* fData;
- };
- friend bool operator==(const HashKey&, const HashKey&);
-
// 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. Also, when a HashNode goes out of scope, that means it is exiting
// the hash table. We take that opportunity to remove it from the LRU list and do some cleanup.
class HashNode : SkNoncopyable {
public:
- static HashKey GetKey(const HashNode& node) { return GetKey(node.entry()); }
- static HashKey GetKey(const GrCCPathCacheEntry*);
- static uint32_t Hash(HashKey);
+ static const Key& GetKey(const HashNode&);
+ static uint32_t Hash(const Key&);
HashNode() = default;
- HashNode(GrCCPathCache*, const MaskTransform&, const GrShape&);
+ HashNode(GrCCPathCache*, sk_sp<Key>, const MaskTransform&, const GrShape&);
HashNode(HashNode&& node)
: fPathCache(node.fPathCache), fEntry(std::move(node.fEntry)) {
SkASSERT(!node.fEntry);
@@ -89,28 +116,30 @@
GrCCPathCache* fPathCache = 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;
+ void evict(const GrCCPathCache::Key& key) {
+ fHashTable.remove(key); // HashNode::willExitHashTable() takes care of the rest.
+ }
- SkDEBUGCODE(SkThreadID fGraphicsThreadID = kIllegalThreadID);
+ SkTHashTable<HashNode, const GrCCPathCache::Key&> fHashTable;
+ SkTInternalLList<GrCCPathCacheEntry> fLRU;
+ SkMessageBus<sk_sp<Key>>::Inbox fInvalidatedKeysInbox;
+ sk_sp<Key> fScratchKey; // Reused for creating a temporary key in the find() method.
};
/**
* This class stores all the data necessary to draw a specific path + matrix combination from their
* corresponding cached atlas.
*/
-class GrCCPathCacheEntry : public SkPathRef::GenIDChangeListener {
+class GrCCPathCacheEntry : public GrNonAtomicRef<GrCCPathCacheEntry> {
public:
SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrCCPathCacheEntry);
- ~GrCCPathCacheEntry() override;
-
- uint32_t pathCacheUniqueID() const { return fPathCacheUniqueID; }
+ ~GrCCPathCacheEntry() {
+ SkASSERT(!fCurrFlushAtlas); // Client is required to reset fCurrFlushAtlas back to null.
+ this->invalidateAtlas();
+ }
// 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
@@ -162,16 +191,16 @@
private:
using MaskTransform = GrCCPathCache::MaskTransform;
- GrCCPathCacheEntry(uint32_t pathCacheUniqueID, const MaskTransform&);
+ GrCCPathCacheEntry(sk_sp<GrCCPathCache::Key> cacheKey, const MaskTransform& maskTransform)
+ : fCacheKey(std::move(cacheKey)), fMaskTransform(maskTransform) {
+ }
// 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. Not threadsafe.
- void onChange() override;
+ sk_sp<GrCCPathCache::Key> fCacheKey;
- const uint32_t fPathCacheUniqueID;
MaskTransform fMaskTransform;
int fHitCount = 1;
@@ -188,8 +217,6 @@
// This field is for when a path gets drawn more than once during the same flush.
const GrCCAtlas* fCurrFlushAtlas = nullptr;
- SkDEBUGCODE(SkThreadID fGraphicsThreadID);
-
friend class GrCCPathCache;
friend void GrCCPathProcessor::Instance::set(const GrCCPathCacheEntry&, const SkIVector&,
GrColor, DoEvenOddFill); // To access data.