| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #ifndef GrResourceCache_DEFINED | 8 #ifndef GrResourceCache_DEFINED |
| 9 #define GrResourceCache_DEFINED | 9 #define GrResourceCache_DEFINED |
| 10 | 10 |
| 11 #include "GrGpuResource.h" | 11 #include "GrGpuResource.h" |
| 12 #include "GrGpuResourceCacheAccess.h" | 12 #include "GrGpuResourceCacheAccess.h" |
| 13 #include "GrGpuResourcePriv.h" | 13 #include "GrGpuResourcePriv.h" |
| 14 #include "GrResourceCache.h" | 14 #include "GrResourceCache.h" |
| 15 #include "GrResourceKey.h" | 15 #include "GrResourceKey.h" |
| 16 #include "SkChunkAlloc.h" | |
| 17 #include "SkMessageBus.h" | 16 #include "SkMessageBus.h" |
| 18 #include "SkRandom.h" | |
| 19 #include "SkRefCnt.h" | 17 #include "SkRefCnt.h" |
| 20 #include "SkTArray.h" | 18 #include "SkTArray.h" |
| 21 #include "SkTDPQueue.h" | 19 #include "SkTDPQueue.h" |
| 22 #include "SkTInternalLList.h" | 20 #include "SkTInternalLList.h" |
| 23 #include "SkTMultiMap.h" | 21 #include "SkTMultiMap.h" |
| 24 | 22 |
| 25 class GrCaps; | 23 class GrCaps; |
| 26 class SkString; | 24 class SkString; |
| 27 class SkTraceMemoryDump; | 25 class SkTraceMemoryDump; |
| 28 | 26 |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 #ifdef SK_DEBUG | 130 #ifdef SK_DEBUG |
| 133 // This is not particularly fast and only used for validation, so debug only
. | 131 // This is not particularly fast and only used for validation, so debug only
. |
| 134 int countScratchEntriesForKey(const GrScratchKey& scratchKey) const { | 132 int countScratchEntriesForKey(const GrScratchKey& scratchKey) const { |
| 135 return fScratchMap.countForKey(scratchKey); | 133 return fScratchMap.countForKey(scratchKey); |
| 136 } | 134 } |
| 137 #endif | 135 #endif |
| 138 | 136 |
| 139 /** | 137 /** |
| 140 * Find a resource that matches a unique key. | 138 * Find a resource that matches a unique key. |
| 141 */ | 139 */ |
| 142 GrGpuResource* findAndRefUniqueResource(const GrUniqueKey& key); | 140 GrGpuResource* findAndRefUniqueResource(const GrUniqueKey& key) { |
| 141 GrGpuResource* resource = fUniqueHash.find(key); |
| 142 if (resource) { |
| 143 this->refAndMakeResourceMRU(resource); |
| 144 } |
| 145 return resource; |
| 146 } |
| 143 | 147 |
| 144 /** | 148 /** |
| 145 * Query whether a unique key exists in the cache. | 149 * Query whether a unique key exists in the cache. |
| 146 */ | 150 */ |
| 147 bool hasUniqueKey(const GrUniqueKey& key) const { | 151 bool hasUniqueKey(const GrUniqueKey& key) const { |
| 148 return SkToBool(fUniqueHash.find(key)); | 152 return SkToBool(fUniqueHash.find(key)); |
| 149 } | 153 } |
| 150 | 154 |
| 151 /** Purges resources to become under budget and processes resources with inv
alidated unique | 155 /** Purges resources to become under budget and processes resources with inv
alidated unique |
| 152 keys. */ | 156 keys. */ |
| 153 void purgeAsNeeded() { this->internalPurgeAsNeeded(false); } | 157 void purgeAsNeeded(); |
| 154 | 158 |
| 155 /** Purges all resources that don't have external owners. */ | 159 /** Purges all resources that don't have external owners. */ |
| 156 void purgeAllUnlocked(); | 160 void purgeAllUnlocked(); |
| 157 | 161 |
| 158 /** Returns true if the cache would like a flush to occur in order to make m
ore resources | 162 /** Returns true if the cache would like a flush to occur in order to make m
ore resources |
| 159 purgeable. */ | 163 purgeable. */ |
| 160 bool requestsFlush() const { | 164 bool requestsFlush() const { return fRequestFlush; } |
| 161 // When in random replacement mode we request a flush in order to make a
s many resources | |
| 162 // as possible subject to replacement. | |
| 163 return this->overBudget() && (ReplacementStrategy::kRandom == fStrategy
|| | |
| 164 0 == fPurgeableQueue.count()); | |
| 165 } | |
| 166 | 165 |
| 167 enum FlushType { | 166 enum FlushType { |
| 168 kExternal, | 167 kExternal, |
| 169 kImmediateMode, | 168 kImmediateMode, |
| 170 kCacheRequested, | 169 kCacheRequested, |
| 171 }; | 170 }; |
| 172 void notifyFlushOccurred(FlushType); | 171 void notifyFlushOccurred(FlushType); |
| 173 | 172 |
| 174 #if GR_CACHE_STATS | 173 #if GR_CACHE_STATS |
| 175 struct Stats { | 174 struct Stats { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 226 void removeResource(GrGpuResource*); | 225 void removeResource(GrGpuResource*); |
| 227 void notifyCntReachedZero(GrGpuResource*, uint32_t flags); | 226 void notifyCntReachedZero(GrGpuResource*, uint32_t flags); |
| 228 void didChangeGpuMemorySize(const GrGpuResource*, size_t oldSize); | 227 void didChangeGpuMemorySize(const GrGpuResource*, size_t oldSize); |
| 229 void changeUniqueKey(GrGpuResource*, const GrUniqueKey&); | 228 void changeUniqueKey(GrGpuResource*, const GrUniqueKey&); |
| 230 void removeUniqueKey(GrGpuResource*); | 229 void removeUniqueKey(GrGpuResource*); |
| 231 void willRemoveScratchKey(const GrGpuResource*); | 230 void willRemoveScratchKey(const GrGpuResource*); |
| 232 void didChangeBudgetStatus(GrGpuResource*); | 231 void didChangeBudgetStatus(GrGpuResource*); |
| 233 void refAndMakeResourceMRU(GrGpuResource*); | 232 void refAndMakeResourceMRU(GrGpuResource*); |
| 234 /// @} | 233 /// @} |
| 235 | 234 |
| 236 void internalPurgeAsNeeded(bool fromFlushNotification); | |
| 237 void processInvalidUniqueKeys(const SkTArray<GrUniqueKeyInvalidatedMessage>&
); | 235 void processInvalidUniqueKeys(const SkTArray<GrUniqueKeyInvalidatedMessage>&
); |
| 238 void addToNonpurgeableArray(GrGpuResource*); | 236 void addToNonpurgeableArray(GrGpuResource*); |
| 239 void removeFromNonpurgeableArray(GrGpuResource*); | 237 void removeFromNonpurgeableArray(GrGpuResource*); |
| 240 bool overBudget() const { return fBudgetedBytes > fMaxBytes || fBudgetedCoun
t > fMaxCount; } | 238 bool overBudget() const { return fBudgetedBytes > fMaxBytes || fBudgetedCoun
t > fMaxCount; } |
| 241 GrGpuResource* selectResourceUsingStrategy(); | |
| 242 void recordPurgedKey(GrGpuResource*); | |
| 243 void recordKeyMiss(const GrUniqueKey&); | |
| 244 | 239 |
| 245 bool wouldFit(size_t bytes) { | 240 bool wouldFit(size_t bytes) { |
| 246 return fBudgetedBytes+bytes <= fMaxBytes && fBudgetedCount+1 <= fMaxCoun
t; | 241 return fBudgetedBytes+bytes <= fMaxBytes && fBudgetedCount+1 <= fMaxCoun
t; |
| 247 } | 242 } |
| 248 | 243 |
| 249 uint32_t getNextTimestamp(); | 244 uint32_t getNextTimestamp(); |
| 250 | 245 |
| 251 #ifdef SK_DEBUG | 246 #ifdef SK_DEBUG |
| 252 bool isInCache(const GrGpuResource* r) const; | 247 bool isInCache(const GrGpuResource* r) const; |
| 253 void validate() const; | 248 void validate() const; |
| 254 #else | 249 #else |
| 255 void validate() const {} | 250 void validate() const {} |
| 256 #endif | 251 #endif |
| 257 | 252 |
| 258 class AutoValidate; | 253 class AutoValidate; |
| 259 | 254 |
| 260 class AvailableForScratchUse; | 255 class AvailableForScratchUse; |
| 261 | 256 |
| 262 struct HashTraitsBase { | 257 struct ScratchMapTraits { |
| 263 static uint32_t Hash(const GrResourceKey& key) { return key.hash(); } | |
| 264 }; | |
| 265 | |
| 266 struct ScratchMapTraits : public HashTraitsBase { | |
| 267 static const GrScratchKey& GetKey(const GrGpuResource& r) { | 258 static const GrScratchKey& GetKey(const GrGpuResource& r) { |
| 268 return r.resourcePriv().getScratchKey(); | 259 return r.resourcePriv().getScratchKey(); |
| 269 } | 260 } |
| 261 |
| 262 static uint32_t Hash(const GrScratchKey& key) { return key.hash(); } |
| 270 }; | 263 }; |
| 271 typedef SkTMultiMap<GrGpuResource, GrScratchKey, ScratchMapTraits> ScratchMa
p; | 264 typedef SkTMultiMap<GrGpuResource, GrScratchKey, ScratchMapTraits> ScratchMa
p; |
| 272 | 265 |
| 273 struct UniqueHashTraits : public HashTraitsBase { | 266 struct UniqueHashTraits { |
| 274 static const GrUniqueKey& GetKey(const GrGpuResource& r) { return r.getU
niqueKey(); } | 267 static const GrUniqueKey& GetKey(const GrGpuResource& r) { return r.getU
niqueKey(); } |
| 268 |
| 269 static uint32_t Hash(const GrUniqueKey& key) { return key.hash(); } |
| 275 }; | 270 }; |
| 276 typedef SkTDynamicHash<GrGpuResource, GrUniqueKey, UniqueHashTraits> UniqueH
ash; | 271 typedef SkTDynamicHash<GrGpuResource, GrUniqueKey, UniqueHashTraits> UniqueH
ash; |
| 277 | 272 |
| 278 struct UniqueSetTraits : public HashTraitsBase { | |
| 279 static const GrUniqueKey& GetKey(const GrUniqueKey& key) { return key; } | |
| 280 }; | |
| 281 typedef SkTDynamicHash<GrUniqueKey, GrUniqueKey, UniqueSetTraits> UniqueKeyS
et; | |
| 282 | |
| 283 static bool CompareTimestamp(GrGpuResource* const& a, GrGpuResource* const&
b) { | 273 static bool CompareTimestamp(GrGpuResource* const& a, GrGpuResource* const&
b) { |
| 284 return a->cacheAccess().timestamp() < b->cacheAccess().timestamp(); | 274 return a->cacheAccess().timestamp() < b->cacheAccess().timestamp(); |
| 285 } | 275 } |
| 286 | 276 |
| 287 static int* AccessResourceIndex(GrGpuResource* const& res) { | 277 static int* AccessResourceIndex(GrGpuResource* const& res) { |
| 288 return res->cacheAccess().accessCacheIndex(); | 278 return res->cacheAccess().accessCacheIndex(); |
| 289 } | 279 } |
| 290 | 280 |
| 291 /** | |
| 292 * The resource cache chooses one of these replacement strategies based on a
"strategy score" | |
| 293 * updated after each external flush based on unique key cache misses. | |
| 294 */ | |
| 295 enum class ReplacementStrategy { | |
| 296 kLRU, | |
| 297 kRandom | |
| 298 }; | |
| 299 /** | |
| 300 * When the current strategy score is >=0 LRU is chosen, when it is < 0 rand
om is chosen. The | |
| 301 * absolute value of the score moves by 1 each flush. | |
| 302 */ | |
| 303 static constexpr int kStrategyScoreMin = -5; | |
| 304 static constexpr int kStrategyScoreMax = 4; | |
| 305 static constexpr int kInitialStrategyScore = 2; | |
| 306 | |
| 307 typedef SkMessageBus<GrUniqueKeyInvalidatedMessage>::Inbox InvalidUniqueKeyI
nbox; | 281 typedef SkMessageBus<GrUniqueKeyInvalidatedMessage>::Inbox InvalidUniqueKeyI
nbox; |
| 308 typedef SkTDPQueue<GrGpuResource*, CompareTimestamp, AccessResourceIndex> Pu
rgeableQueue; | 282 typedef SkTDPQueue<GrGpuResource*, CompareTimestamp, AccessResourceIndex> Pu
rgeableQueue; |
| 309 typedef SkTDArray<GrGpuResource*> ResourceArray; | 283 typedef SkTDArray<GrGpuResource*> ResourceArray; |
| 310 | 284 |
| 311 // Whenever a resource is added to the cache or the result of a cache lookup
, fTimestamp is | 285 // Whenever a resource is added to the cache or the result of a cache lookup
, fTimestamp is |
| 312 // assigned as the resource's timestamp and then incremented. fPurgeableQueu
e orders the | 286 // assigned as the resource's timestamp and then incremented. fPurgeableQueu
e orders the |
| 313 // purgeable resources by this value, and thus is used to purge resources in
LRU order. | 287 // purgeable resources by this value, and thus is used to purge resources in
LRU order. |
| 314 uint32_t fTimestamp; | 288 uint32_t fTimestamp; |
| 315 PurgeableQueue fPurgeableQueue; | 289 PurgeableQueue fPurgeableQueue; |
| 316 ResourceArray fNonpurgeableResources; | 290 ResourceArray fNonpurgeableResources; |
| 317 | 291 |
| 318 // This map holds all resources that can be used as scratch resources. | 292 // This map holds all resources that can be used as scratch resources. |
| 319 ScratchMap fScratchMap; | 293 ScratchMap fScratchMap; |
| 320 // This holds all resources that have unique keys. | 294 // This holds all resources that have unique keys. |
| 321 UniqueHash fUniqueHash; | 295 UniqueHash fUniqueHash; |
| 322 | 296 |
| 323 // our budget, used in purgeAsNeeded() | 297 // our budget, used in purgeAsNeeded() |
| 324 int fMaxCount; | 298 int fMaxCount; |
| 325 size_t fMaxBytes; | 299 size_t fMaxBytes; |
| 326 int fMaxUnusedFlushes; | 300 int fMaxUnusedFlushes; |
| 327 | 301 |
| 328 // Data related to replacement strategy. | |
| 329 SkRandom fRandom; | |
| 330 ReplacementStrategy fStrategy; | |
| 331 int fStrategyScore; | |
| 332 int fTotalMissesThisFlush; | |
| 333 int fMissesThisFlushPurgedRecently; | |
| 334 UniqueKeySet fUniqueKeysPurgedThisFlush[2]; | |
| 335 // These are pointers to SkChunckAlloc because of gcc bug 63707 | |
| 336 SkChunkAlloc* fUniqueKeysPurgedThisFlushStorage[2]; | |
| 337 int fFlushParity; | |
| 338 | |
| 339 #if GR_CACHE_STATS | 302 #if GR_CACHE_STATS |
| 340 int fHighWaterCount; | 303 int fHighWaterCount; |
| 341 size_t fHighWaterBytes; | 304 size_t fHighWaterBytes; |
| 342 int fBudgetedHighWaterCount; | 305 int fBudgetedHighWaterCount; |
| 343 size_t fBudgetedHighWaterBytes; | 306 size_t fBudgetedHighWaterBytes; |
| 344 #endif | 307 #endif |
| 345 | 308 |
| 346 // our current stats for all resources | 309 // our current stats for all resources |
| 347 SkDEBUGCODE(int fCount;) | 310 SkDEBUGCODE(int fCount;) |
| 348 size_t fBytes; | 311 size_t fBytes; |
| 349 | 312 |
| 350 // our current stats for resources that count against the budget | 313 // our current stats for resources that count against the budget |
| 351 int fBudgetedCount; | 314 int fBudgetedCount; |
| 352 size_t fBudgetedBytes; | 315 size_t fBudgetedBytes; |
| 353 | 316 |
| 317 bool fRequestFlush; |
| 354 uint32_t fExternalFlushCnt; | 318 uint32_t fExternalFlushCnt; |
| 355 | 319 |
| 356 bool fIsPurging; | |
| 357 | |
| 358 InvalidUniqueKeyInbox fInvalidUniqueKeyInbox; | 320 InvalidUniqueKeyInbox fInvalidUniqueKeyInbox; |
| 359 | 321 |
| 360 // This resource is allowed to be in the nonpurgeable array for the sake of
validate() because | 322 // This resource is allowed to be in the nonpurgeable array for the sake of
validate() because |
| 361 // we're in the midst of converting it to purgeable status. | 323 // we're in the midst of converting it to purgeable status. |
| 362 SkDEBUGCODE(GrGpuResource* fNewlyPurgeableResourceForValidation;) | 324 SkDEBUGCODE(GrGpuResource* fNewlyPurgeableResourceForValidation;) |
| 363 | 325 |
| 364 bool fPreferVRAMUseOverFlushes; | 326 bool fPreferVRAMUseOverFlushes; |
| 365 }; | 327 }; |
| 366 | 328 |
| 367 class GrResourceCache::ResourceAccess { | 329 class GrResourceCache::ResourceAccess { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 441 | 403 |
| 442 friend class GrGpuResource; // To access all the proxy inline methods. | 404 friend class GrGpuResource; // To access all the proxy inline methods. |
| 443 friend class GrResourceCache; // To create this type. | 405 friend class GrResourceCache; // To create this type. |
| 444 }; | 406 }; |
| 445 | 407 |
| 446 inline GrResourceCache::ResourceAccess GrResourceCache::resourceAccess() { | 408 inline GrResourceCache::ResourceAccess GrResourceCache::resourceAccess() { |
| 447 return ResourceAccess(this); | 409 return ResourceAccess(this); |
| 448 } | 410 } |
| 449 | 411 |
| 450 #endif | 412 #endif |
| OLD | NEW |