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