Index: src/gpu/GrResourceCache.h |
diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h |
index bf7b237006b0fd270a1056744c130b5ce006be94..a481c222171a9ae4e71d09a0753233046879416a 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" |
@@ -142,13 +144,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. |
@@ -159,14 +155,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, |
@@ -237,11 +238,15 @@ private: |
void refAndMakeResourceMRU(GrGpuResource*); |
/// @} |
+ void internalPurgeAsNeeded(bool fromFlushNotification); |
void resetFlushTimestamps(); |
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; |
@@ -260,22 +265,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; |
robertphillips
2016/09/13 13:05:21
missing space before '{' ?
bsalomon
2016/09/13 13:31:33
Done.
|
+ 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(); |
} |
@@ -284,6 +294,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 kInitialStrategyScoreMax = 3; |
+ |
typedef SkMessageBus<GrUniqueKeyInvalidatedMessage>::Inbox InvalidUniqueKeyInbox; |
typedef SkTDPQueue<GrGpuResource*, CompareTimestamp, AccessResourceIndex> PurgeableQueue; |
typedef SkTDArray<GrGpuResource*> ResourceArray; |
@@ -305,6 +331,16 @@ private: |
size_t fMaxBytes; |
int fMaxUnusedFlushes; |
+ // Data related to replacement strategy. |
+ SkRandom fRandom; |
+ ReplacementStrategy fStrategy; |
+ int fStrategyScore; |
+ int fTotalMissesThisFlush; |
+ int fMissesThisFlushPurgedRecently; |
+ UniqueKeySet fUniqueKeysPurgedThisFlush[2]; |
+ SkChunkAlloc fUniqueKeysPurgedThisFlushStorage[2]; |
+ int fFlushParity; |
+ |
#if GR_CACHE_STATS |
int fHighWaterCount; |
size_t fHighWaterBytes; |
@@ -320,8 +356,6 @@ private: |
int fBudgetedCount; |
size_t fBudgetedBytes; |
- bool fRequestFlush; |
- |
// We keep track of the "timestamps" of the last n flushes. If a resource hasn't been used in |
// that time then we well preemptively purge it to reduce memory usage. |
uint32_t* fFlushTimestamps; |