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 |