Index: src/gpu/GrResourceCache.h |
diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h |
index ae9a4e7ee7e3bae513b5503083209b96e1d8fb74..d6cdf81612205235060502b17f2e13f06b308f47 100644 |
--- a/src/gpu/GrResourceCache.h |
+++ b/src/gpu/GrResourceCache.h |
@@ -13,7 +13,9 @@ |
#include "GrGpuResourcePriv.h" |
#include "GrResourceCache.h" |
#include "GrResourceKey.h" |
+#include "SkChunkAlloc.h" |
#include "SkMessageBus.h" |
+#include "SkRandom.h" |
#include "SkRefCnt.h" |
#include "SkTArray.h" |
#include "SkTDPQueue.h" |
@@ -137,13 +139,7 @@ public: |
/** |
* Find a resource that matches a unique key. |
*/ |
- GrGpuResource* findAndRefUniqueResource(const GrUniqueKey& key) { |
- GrGpuResource* resource = fUniqueHash.find(key); |
- if (resource) { |
- this->refAndMakeResourceMRU(resource); |
- } |
- return resource; |
- } |
+ GrGpuResource* findAndRefUniqueResource(const GrUniqueKey& key); |
/** |
* Query whether a unique key exists in the cache. |
@@ -154,14 +150,19 @@ public: |
/** Purges resources to become under budget and processes resources with invalidated unique |
keys. */ |
- void purgeAsNeeded(); |
+ void purgeAsNeeded() { this->internalPurgeAsNeeded(false); } |
/** Purges all resources that don't have external owners. */ |
void purgeAllUnlocked(); |
/** Returns true if the cache would like a flush to occur in order to make more resources |
purgeable. */ |
- bool requestsFlush() const { return fRequestFlush; } |
+ bool requestsFlush() const { |
+ // When in random replacement mode we request a flush in order to make as many resources |
+ // as possible subject to replacement. |
+ return this->overBudget() && (ReplacementStrategy::kRandom == fStrategy || |
+ 0 == fPurgeableQueue.count()); |
+ } |
enum FlushType { |
kExternal, |
@@ -232,10 +233,14 @@ private: |
void refAndMakeResourceMRU(GrGpuResource*); |
/// @} |
+ void internalPurgeAsNeeded(bool fromFlushNotification); |
void processInvalidUniqueKeys(const SkTArray<GrUniqueKeyInvalidatedMessage>&); |
void addToNonpurgeableArray(GrGpuResource*); |
void removeFromNonpurgeableArray(GrGpuResource*); |
bool overBudget() const { return fBudgetedBytes > fMaxBytes || fBudgetedCount > fMaxCount; } |
+ GrGpuResource* selectResourceUsingStrategy(); |
+ void recordPurgedKey(GrGpuResource*); |
+ void recordKeyMiss(const GrUniqueKey&); |
bool wouldFit(size_t bytes) { |
return fBudgetedBytes+bytes <= fMaxBytes && fBudgetedCount+1 <= fMaxCount; |
@@ -254,22 +259,27 @@ private: |
class AvailableForScratchUse; |
- struct ScratchMapTraits { |
+ struct HashTraitsBase { |
+ static uint32_t Hash(const GrResourceKey& key) { return key.hash(); } |
+ }; |
+ |
+ struct ScratchMapTraits : public HashTraitsBase { |
static const GrScratchKey& GetKey(const GrGpuResource& r) { |
return r.resourcePriv().getScratchKey(); |
} |
- |
- static uint32_t Hash(const GrScratchKey& key) { return key.hash(); } |
}; |
typedef SkTMultiMap<GrGpuResource, GrScratchKey, ScratchMapTraits> ScratchMap; |
- struct UniqueHashTraits { |
+ struct UniqueHashTraits : public HashTraitsBase { |
static const GrUniqueKey& GetKey(const GrGpuResource& r) { return r.getUniqueKey(); } |
- |
- static uint32_t Hash(const GrUniqueKey& key) { return key.hash(); } |
}; |
typedef SkTDynamicHash<GrGpuResource, GrUniqueKey, UniqueHashTraits> UniqueHash; |
+ struct UniqueSetTraits : public HashTraitsBase { |
+ static const GrUniqueKey& GetKey(const GrUniqueKey& key) { return key; } |
+ }; |
+ typedef SkTDynamicHash<GrUniqueKey, GrUniqueKey, UniqueSetTraits> UniqueKeySet; |
+ |
static bool CompareTimestamp(GrGpuResource* const& a, GrGpuResource* const& b) { |
return a->cacheAccess().timestamp() < b->cacheAccess().timestamp(); |
} |
@@ -278,6 +288,22 @@ private: |
return res->cacheAccess().accessCacheIndex(); |
} |
+ /** |
+ * The resource cache chooses one of these replacement strategies based on a "strategy score" |
+ * updated after each external flush based on unique key cache misses. |
+ */ |
+ enum class ReplacementStrategy { |
+ kLRU, |
+ kRandom |
+ }; |
+ /** |
+ * When the current strategy score is >=0 LRU is chosen, when it is < 0 random is chosen. The |
+ * absolute value of the score moves by 1 each flush. |
+ */ |
+ static constexpr int kStrategyScoreMin = -5; |
+ static constexpr int kStrategyScoreMax = 4; |
+ static constexpr int kInitialStrategyScore = 2; |
+ |
typedef SkMessageBus<GrUniqueKeyInvalidatedMessage>::Inbox InvalidUniqueKeyInbox; |
typedef SkTDPQueue<GrGpuResource*, CompareTimestamp, AccessResourceIndex> PurgeableQueue; |
typedef SkTDArray<GrGpuResource*> ResourceArray; |
@@ -299,6 +325,17 @@ private: |
size_t fMaxBytes; |
int fMaxUnusedFlushes; |
+ // Data related to replacement strategy. |
+ SkRandom fRandom; |
+ ReplacementStrategy fStrategy; |
+ int fStrategyScore; |
+ int fTotalMissesThisFlush; |
+ int fMissesThisFlushPurgedRecently; |
+ UniqueKeySet fUniqueKeysPurgedThisFlush[2]; |
+ // These are pointers to SkChunckAlloc because of gcc bug 63707 |
+ SkChunkAlloc* fUniqueKeysPurgedThisFlushStorage[2]; |
+ int fFlushParity; |
+ |
#if GR_CACHE_STATS |
int fHighWaterCount; |
size_t fHighWaterBytes; |
@@ -314,9 +351,10 @@ private: |
int fBudgetedCount; |
size_t fBudgetedBytes; |
- bool fRequestFlush; |
uint32_t fExternalFlushCnt; |
+ bool fIsPurging; |
+ |
InvalidUniqueKeyInbox fInvalidUniqueKeyInbox; |
// This resource is allowed to be in the nonpurgeable array for the sake of validate() because |