| 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 | 8 |
| 9 #include "GrResourceCache.h" | 9 #include "GrResourceCache.h" |
| 10 | 10 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 50 | 50 |
| 51 class GrResourceCache::AutoValidate : ::SkNoncopyable { | 51 class GrResourceCache::AutoValidate : ::SkNoncopyable { |
| 52 public: | 52 public: |
| 53 AutoValidate(GrResourceCache* cache) : fCache(cache) { cache->validate(); } | 53 AutoValidate(GrResourceCache* cache) : fCache(cache) { cache->validate(); } |
| 54 ~AutoValidate() { fCache->validate(); } | 54 ~AutoValidate() { fCache->validate(); } |
| 55 private: | 55 private: |
| 56 GrResourceCache* fCache; | 56 GrResourceCache* fCache; |
| 57 }; | 57 }; |
| 58 | 58 |
| 59 ////////////////////////////////////////////////////////////////////////////// | 59 ////////////////////////////////////////////////////////////////////////////// |
| 60 | 60 constexpr int GrResourceCache::kStrategyScoreMin; |
| 61 constexpr int GrResourceCache::kStrategyScoreMax; |
| 62 constexpr int GrResourceCache::kInitialStrategyScore; |
| 61 | 63 |
| 62 GrResourceCache::GrResourceCache(const GrCaps* caps) | 64 GrResourceCache::GrResourceCache(const GrCaps* caps) |
| 63 : fTimestamp(0) | 65 : fTimestamp(0) |
| 64 , fMaxCount(kDefaultMaxCount) | 66 , fMaxCount(kDefaultMaxCount) |
| 65 , fMaxBytes(kDefaultMaxSize) | 67 , fMaxBytes(kDefaultMaxSize) |
| 66 , fMaxUnusedFlushes(kDefaultMaxUnusedFlushes) | 68 , fMaxUnusedFlushes(kDefaultMaxUnusedFlushes) |
| 69 , fStrategy(ReplacementStrategy::kLRU) |
| 70 , fStrategyScore(kInitialStrategyScore) |
| 71 , fTotalMissesThisFlush(0) |
| 72 , fMissesThisFlushPurgedRecently(0) |
| 73 , fUniqueKeysPurgedThisFlushStorage {new SkChunkAlloc(8*sizeof(GrUniqueKey))
, |
| 74 new SkChunkAlloc(8*sizeof(GrUniqueKey))
} |
| 75 , fFlushParity(0) |
| 67 #if GR_CACHE_STATS | 76 #if GR_CACHE_STATS |
| 68 , fHighWaterCount(0) | 77 , fHighWaterCount(0) |
| 69 , fHighWaterBytes(0) | 78 , fHighWaterBytes(0) |
| 70 , fBudgetedHighWaterCount(0) | 79 , fBudgetedHighWaterCount(0) |
| 71 , fBudgetedHighWaterBytes(0) | 80 , fBudgetedHighWaterBytes(0) |
| 72 #endif | 81 #endif |
| 73 , fBytes(0) | 82 , fBytes(0) |
| 74 , fBudgetedCount(0) | 83 , fBudgetedCount(0) |
| 75 , fBudgetedBytes(0) | 84 , fBudgetedBytes(0) |
| 76 , fRequestFlush(false) | |
| 77 , fExternalFlushCnt(0) | 85 , fExternalFlushCnt(0) |
| 86 , fIsPurging(false) |
| 78 , fPreferVRAMUseOverFlushes(caps->preferVRAMUseOverFlushes()) { | 87 , fPreferVRAMUseOverFlushes(caps->preferVRAMUseOverFlushes()) { |
| 79 SkDEBUGCODE(fCount = 0;) | 88 SkDEBUGCODE(fCount = 0;) |
| 80 SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr;) | 89 SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr;) |
| 81 } | 90 } |
| 82 | 91 |
| 83 GrResourceCache::~GrResourceCache() { | 92 GrResourceCache::~GrResourceCache() { |
| 84 this->releaseAll(); | 93 this->releaseAll(); |
| 94 delete fUniqueKeysPurgedThisFlushStorage[0]; |
| 95 delete fUniqueKeysPurgedThisFlushStorage[1]; |
| 85 } | 96 } |
| 86 | 97 |
| 87 void GrResourceCache::setLimits(int count, size_t bytes, int maxUnusedFlushes) { | 98 void GrResourceCache::setLimits(int count, size_t bytes, int maxUnusedFlushes) { |
| 88 fMaxCount = count; | 99 fMaxCount = count; |
| 89 fMaxBytes = bytes; | 100 fMaxBytes = bytes; |
| 90 fMaxUnusedFlushes = maxUnusedFlushes; | 101 fMaxUnusedFlushes = maxUnusedFlushes; |
| 91 this->purgeAsNeeded(); | 102 this->purgeAsNeeded(); |
| 92 } | 103 } |
| 93 | 104 |
| 94 void GrResourceCache::insertResource(GrGpuResource* resource) { | 105 void GrResourceCache::insertResource(GrGpuResource* resource) { |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 return !fRejectPendingIO || !resource->internalHasPendingIO(); | 231 return !fRejectPendingIO || !resource->internalHasPendingIO(); |
| 221 } | 232 } |
| 222 | 233 |
| 223 private: | 234 private: |
| 224 bool fRejectPendingIO; | 235 bool fRejectPendingIO; |
| 225 }; | 236 }; |
| 226 | 237 |
| 227 GrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& sc
ratchKey, | 238 GrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& sc
ratchKey, |
| 228 size_t resourceSize, | 239 size_t resourceSize, |
| 229 uint32_t flags) { | 240 uint32_t flags) { |
| 241 // We don't currently track misses for scratch resources for selecting the r
eplacement policy. |
| 242 // The reason is that it is common to look for a scratch resource before cre
ating a texture |
| 243 // that will immediately become uniquely keyed. |
| 230 SkASSERT(scratchKey.isValid()); | 244 SkASSERT(scratchKey.isValid()); |
| 231 | |
| 232 GrGpuResource* resource; | 245 GrGpuResource* resource; |
| 233 if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFla
g)) { | 246 if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFla
g)) { |
| 234 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true)); | 247 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true)); |
| 235 if (resource) { | 248 if (resource) { |
| 236 this->refAndMakeResourceMRU(resource); | 249 this->refAndMakeResourceMRU(resource); |
| 237 this->validate(); | 250 this->validate(); |
| 238 return resource; | 251 return resource; |
| 239 } else if (flags & kRequireNoPendingIO_ScratchFlag) { | 252 } else if (flags & kRequireNoPendingIO_ScratchFlag) { |
| 240 return nullptr; | 253 return nullptr; |
| 241 } | 254 } |
| 242 // We would prefer to consume more available VRAM rather than flushing | 255 // We would prefer to consume more available VRAM rather than flushing |
| 243 // immediately, but on ANGLE this can lead to starving of the GPU. | 256 // immediately, but on ANGLE this can lead to starving of the GPU. |
| 244 if (fPreferVRAMUseOverFlushes && this->wouldFit(resourceSize)) { | 257 if (fPreferVRAMUseOverFlushes && this->wouldFit(resourceSize)) { |
| 245 // kPrefer is specified, we didn't find a resource without pending i
o, | 258 // kPrefer is specified, we didn't find a resource without pending i
o, |
| 246 // but there is still space in our budget for the resource so force | 259 // but there is still space in our budget for the resource so force |
| 247 // the caller to allocate a new resource. | 260 // the caller to allocate a new resource. |
| 248 return nullptr; | 261 return nullptr; |
| 249 } | 262 } |
| 250 } | 263 } |
| 251 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false)); | 264 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false)); |
| 252 if (resource) { | 265 if (resource) { |
| 253 this->refAndMakeResourceMRU(resource); | 266 this->refAndMakeResourceMRU(resource); |
| 254 this->validate(); | 267 this->validate(); |
| 255 } | 268 } |
| 256 return resource; | 269 return resource; |
| 257 } | 270 } |
| 258 | 271 |
| 272 GrGpuResource* GrResourceCache::findAndRefUniqueResource(const GrUniqueKey& key)
{ |
| 273 GrGpuResource* resource = fUniqueHash.find(key); |
| 274 if (resource) { |
| 275 this->refAndMakeResourceMRU(resource); |
| 276 } else { |
| 277 this->recordKeyMiss(key); |
| 278 } |
| 279 return resource; |
| 280 } |
| 281 |
| 282 void GrResourceCache::recordKeyMiss(const GrUniqueKey& key) { |
| 283 // If a resource with this key was purged either this flush or the previous
flush, consider it |
| 284 // a recent purge. |
| 285 if (fUniqueKeysPurgedThisFlush[0].find(key) || fUniqueKeysPurgedThisFlush[1]
.find(key)) { |
| 286 ++fMissesThisFlushPurgedRecently; |
| 287 } |
| 288 ++fTotalMissesThisFlush; |
| 289 } |
| 290 |
| 259 void GrResourceCache::willRemoveScratchKey(const GrGpuResource* resource) { | 291 void GrResourceCache::willRemoveScratchKey(const GrGpuResource* resource) { |
| 260 SkASSERT(resource->resourcePriv().getScratchKey().isValid()); | 292 SkASSERT(resource->resourcePriv().getScratchKey().isValid()); |
| 261 if (!resource->getUniqueKey().isValid()) { | 293 if (!resource->getUniqueKey().isValid()) { |
| 262 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource); | 294 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource); |
| 263 } | 295 } |
| 264 } | 296 } |
| 265 | 297 |
| 266 void GrResourceCache::removeUniqueKey(GrGpuResource* resource) { | 298 void GrResourceCache::removeUniqueKey(GrGpuResource* resource) { |
| 267 // Someone has a ref to this resource in order to have removed the key. When
the ref count | 299 // Someone has a ref to this resource in order to have removed the key. When
the ref count |
| 268 // reaches zero we will get a ref cnt notification and figure out what to do
with it. | 300 // reaches zero we will get a ref cnt notification and figure out what to do
with it. |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 // We won't purge an existing resource to make room for this one. | 405 // We won't purge an existing resource to make room for this one. |
| 374 if (fBudgetedCount < fMaxCount && | 406 if (fBudgetedCount < fMaxCount && |
| 375 fBudgetedBytes + resource->gpuMemorySize() <= fMaxBytes) { | 407 fBudgetedBytes + resource->gpuMemorySize() <= fMaxBytes) { |
| 376 resource->resourcePriv().makeBudgeted(); | 408 resource->resourcePriv().makeBudgeted(); |
| 377 return; | 409 return; |
| 378 } | 410 } |
| 379 } | 411 } |
| 380 } else { | 412 } else { |
| 381 // Purge the resource immediately if we're over budget | 413 // Purge the resource immediately if we're over budget |
| 382 // Also purge if the resource has neither a valid scratch key nor a uniq
ue key. | 414 // Also purge if the resource has neither a valid scratch key nor a uniq
ue key. |
| 383 bool noKey = !resource->resourcePriv().getScratchKey().isValid() && | 415 bool hasKey = resource->resourcePriv().getScratchKey().isValid() || |
| 384 !resource->getUniqueKey().isValid(); | 416 resource->getUniqueKey().isValid(); |
| 385 if (!this->overBudget() && !noKey) { | 417 if (hasKey) { |
| 418 if (this->overBudget()) { |
| 419 this->purgeAsNeeded(); |
| 420 } |
| 386 return; | 421 return; |
| 387 } | 422 } |
| 388 } | 423 } |
| 389 | 424 |
| 390 SkDEBUGCODE(int beforeCount = this->getResourceCount();) | 425 SkDEBUGCODE(int beforeCount = this->getResourceCount();) |
| 391 resource->cacheAccess().release(); | 426 resource->cacheAccess().release(); |
| 392 // We should at least free this resource, perhaps dependent resources as wel
l. | 427 // We should at least free this resource, perhaps dependent resources as wel
l. |
| 393 SkASSERT(this->getResourceCount() < beforeCount); | 428 SkASSERT(this->getResourceCount() < beforeCount); |
| 394 this->validate(); | 429 this->validate(); |
| 395 } | 430 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 435 } else { | 470 } else { |
| 436 --fBudgetedCount; | 471 --fBudgetedCount; |
| 437 fBudgetedBytes -= size; | 472 fBudgetedBytes -= size; |
| 438 } | 473 } |
| 439 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "
used", | 474 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "
used", |
| 440 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes); | 475 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes); |
| 441 | 476 |
| 442 this->validate(); | 477 this->validate(); |
| 443 } | 478 } |
| 444 | 479 |
| 445 void GrResourceCache::purgeAsNeeded() { | 480 void GrResourceCache::recordPurgedKey(GrGpuResource* resource) { |
| 481 // This maximum exists to avoid allocating too much space for key tracking. |
| 482 static constexpr int kMaxTrackedKeys = 256; |
| 483 if (fUniqueKeysPurgedThisFlush[fFlushParity].count() >= kMaxTrackedKeys) { |
| 484 return; |
| 485 } |
| 486 if (resource->getUniqueKey().isValid() && |
| 487 !fUniqueKeysPurgedThisFlush[fFlushParity].find(resource->getUniqueKey())
) { |
| 488 void* p = fUniqueKeysPurgedThisFlushStorage[fFlushParity]->allocThrow(si
zeof(GrUniqueKey)); |
| 489 GrUniqueKey* copy = new (p) GrUniqueKey; |
| 490 *copy = resource->getUniqueKey(); |
| 491 fUniqueKeysPurgedThisFlush[fFlushParity].add(copy); |
| 492 } |
| 493 } |
| 494 |
| 495 GrGpuResource* GrResourceCache::selectResourceUsingStrategy() { |
| 496 switch (fStrategy) { |
| 497 case ReplacementStrategy::kLRU: |
| 498 return fPurgeableQueue.peek(); |
| 499 case ReplacementStrategy::kRandom: |
| 500 return fPurgeableQueue.at(fRandom.nextULessThan(fPurgeableQueue.coun
t())); |
| 501 } |
| 502 return nullptr; |
| 503 } |
| 504 |
| 505 void GrResourceCache::internalPurgeAsNeeded(bool fromFlushNotification) { |
| 506 if (fIsPurging) { |
| 507 return; |
| 508 } |
| 509 fIsPurging = true; |
| 446 SkTArray<GrUniqueKeyInvalidatedMessage> invalidKeyMsgs; | 510 SkTArray<GrUniqueKeyInvalidatedMessage> invalidKeyMsgs; |
| 447 fInvalidUniqueKeyInbox.poll(&invalidKeyMsgs); | 511 fInvalidUniqueKeyInbox.poll(&invalidKeyMsgs); |
| 448 if (invalidKeyMsgs.count()) { | 512 if (invalidKeyMsgs.count()) { |
| 449 this->processInvalidUniqueKeys(invalidKeyMsgs); | 513 this->processInvalidUniqueKeys(invalidKeyMsgs); |
| 450 } | 514 } |
| 451 | 515 |
| 452 if (fMaxUnusedFlushes > 0) { | 516 if (fMaxUnusedFlushes > 0) { |
| 453 // We want to know how many complete flushes have occurred without the r
esource being used. | 517 // We want to know how many complete flushes have occurred without the r
esource being used. |
| 454 // If the resource was tagged when fExternalFlushCnt was N then this mea
ns it became | 518 // If the resource was tagged when fExternalFlushCnt was N then this mea
ns it became |
| 455 // purgeable during activity that became the N+1th flush. So when the fl
ush count is N+2 | 519 // purgeable during activity that became the N+1th flush. So when the fl
ush count is N+2 |
| 456 // it has sat in the purgeable queue for one entire flush. | 520 // it has sat in the purgeable queue for one entire flush. |
| 457 uint32_t oldestAllowedFlushCnt = fExternalFlushCnt - fMaxUnusedFlushes -
1; | 521 uint32_t oldestAllowedFlushCnt = fExternalFlushCnt - fMaxUnusedFlushes -
1; |
| 458 // check for underflow | 522 // check for underflow |
| 459 if (oldestAllowedFlushCnt < fExternalFlushCnt) { | 523 if (oldestAllowedFlushCnt < fExternalFlushCnt) { |
| 460 while (fPurgeableQueue.count()) { | 524 while (fPurgeableQueue.count()) { |
| 461 uint32_t flushWhenResourceBecamePurgeable = | 525 uint32_t flushWhenResourceBecamePurgeable = |
| 462 fPurgeableQueue.peek()->cacheAccess().flushCntWhenResour
ceBecamePurgeable(); | 526 fPurgeableQueue.peek()->cacheAccess().flushCntWhenResour
ceBecamePurgeable(); |
| 463 if (oldestAllowedFlushCnt < flushWhenResourceBecamePurgeable) { | 527 if (oldestAllowedFlushCnt < flushWhenResourceBecamePurgeable) { |
| 464 // Resources were given both LRU timestamps and tagged with
a flush cnt when | 528 // Resources were given both LRU timestamps and tagged with
a flush cnt when |
| 465 // they first became purgeable. The LRU timestamp won't chan
ge again until the | 529 // they first became purgeable. The LRU timestamp won't chan
ge again until the |
| 466 // resource is made non-purgeable again. So, at this point a
ll the remaining | 530 // resource is made non-purgeable again. So, at this point a
ll the remaining |
| 467 // resources in the timestamp-sorted queue will have a flush
count >= to this | 531 // resources in the timestamp-sorted queue will have a flush
count >= to this |
| 468 // one. | 532 // one. |
| 469 break; | 533 break; |
| 470 } | 534 } |
| 471 GrGpuResource* resource = fPurgeableQueue.peek(); | 535 GrGpuResource* resource = fPurgeableQueue.peek(); |
| 472 SkASSERT(resource->isPurgeable()); | 536 SkASSERT(resource->isPurgeable()); |
| 537 this->recordPurgedKey(resource); |
| 473 resource->cacheAccess().release(); | 538 resource->cacheAccess().release(); |
| 474 } | 539 } |
| 475 } | 540 } |
| 476 } | 541 } |
| 477 | 542 |
| 543 if (ReplacementStrategy::kRandom == fStrategy && !fromFlushNotification) { |
| 544 // Wait until after the requested flush when all the pending IO resource
s will be eligible |
| 545 // for the draft. |
| 546 SkASSERT(!this->overBudget() || this->requestsFlush()); |
| 547 fIsPurging = false; |
| 548 return; |
| 549 } |
| 550 |
| 478 bool stillOverbudget = this->overBudget(); | 551 bool stillOverbudget = this->overBudget(); |
| 479 while (stillOverbudget && fPurgeableQueue.count()) { | 552 while (stillOverbudget && fPurgeableQueue.count()) { |
| 480 GrGpuResource* resource = fPurgeableQueue.peek(); | 553 GrGpuResource* resource = this->selectResourceUsingStrategy(); |
| 481 SkASSERT(resource->isPurgeable()); | 554 SkASSERT(resource->isPurgeable()); |
| 555 this->recordPurgedKey(resource); |
| 482 resource->cacheAccess().release(); | 556 resource->cacheAccess().release(); |
| 483 stillOverbudget = this->overBudget(); | 557 stillOverbudget = this->overBudget(); |
| 484 } | 558 } |
| 485 | 559 |
| 486 this->validate(); | 560 this->validate(); |
| 487 | 561 fIsPurging = false; |
| 488 if (stillOverbudget) { | |
| 489 // Set this so that GrDrawingManager will issue a flush to free up resou
rces with pending | |
| 490 // IO that we were unable to purge in this pass. | |
| 491 fRequestFlush = true; | |
| 492 } | |
| 493 } | 562 } |
| 494 | 563 |
| 495 void GrResourceCache::purgeAllUnlocked() { | 564 void GrResourceCache::purgeAllUnlocked() { |
| 496 // We could disable maintaining the heap property here, but it would add a l
ot of complexity. | 565 // We could disable maintaining the heap property here, but it would add a l
ot of complexity. |
| 497 // Moreover, this is rarely called. | 566 // Moreover, this is rarely called. |
| 498 while (fPurgeableQueue.count()) { | 567 while (fPurgeableQueue.count()) { |
| 499 GrGpuResource* resource = fPurgeableQueue.peek(); | 568 GrGpuResource* resource = fPurgeableQueue.peek(); |
| 500 SkASSERT(resource->isPurgeable()); | 569 SkASSERT(resource->isPurgeable()); |
| 501 resource->cacheAccess().release(); | 570 resource->cacheAccess().release(); |
| 502 } | 571 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 542 // Reset all the timestamps. We sort the resources by timestamp and
then assign | 611 // Reset all the timestamps. We sort the resources by timestamp and
then assign |
| 543 // sequential timestamps beginning with 0. This is O(n*lg(n)) but it
should be extremely | 612 // sequential timestamps beginning with 0. This is O(n*lg(n)) but it
should be extremely |
| 544 // rare. | 613 // rare. |
| 545 SkTDArray<GrGpuResource*> sortedPurgeableResources; | 614 SkTDArray<GrGpuResource*> sortedPurgeableResources; |
| 546 sortedPurgeableResources.setReserve(fPurgeableQueue.count()); | 615 sortedPurgeableResources.setReserve(fPurgeableQueue.count()); |
| 547 | 616 |
| 548 while (fPurgeableQueue.count()) { | 617 while (fPurgeableQueue.count()) { |
| 549 *sortedPurgeableResources.append() = fPurgeableQueue.peek(); | 618 *sortedPurgeableResources.append() = fPurgeableQueue.peek(); |
| 550 fPurgeableQueue.pop(); | 619 fPurgeableQueue.pop(); |
| 551 } | 620 } |
| 552 | |
| 553 SkTQSort(fNonpurgeableResources.begin(), fNonpurgeableResources.end(
) - 1, | 621 SkTQSort(fNonpurgeableResources.begin(), fNonpurgeableResources.end(
) - 1, |
| 554 CompareTimestamp); | 622 CompareTimestamp); |
| 555 | 623 |
| 556 // Pick resources out of the purgeable and non-purgeable arrays base
d on lowest | 624 // Pick resources out of the purgeable and non-purgeable arrays base
d on lowest |
| 557 // timestamp and assign new timestamps. | 625 // timestamp and assign new timestamps. |
| 558 int currP = 0; | 626 int currP = 0; |
| 559 int currNP = 0; | 627 int currNP = 0; |
| 560 while (currP < sortedPurgeableResources.count() && | 628 while (currP < sortedPurgeableResources.count() && |
| 561 currNP < fNonpurgeableResources.count()) { | 629 currNP < fNonpurgeableResources.count()) { |
| 562 uint32_t tsP = sortedPurgeableResources[currP]->cacheAccess().ti
mestamp(); | 630 uint32_t tsP = sortedPurgeableResources[currP]->cacheAccess().ti
mestamp(); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 593 } | 661 } |
| 594 } | 662 } |
| 595 return fTimestamp++; | 663 return fTimestamp++; |
| 596 } | 664 } |
| 597 | 665 |
| 598 void GrResourceCache::notifyFlushOccurred(FlushType type) { | 666 void GrResourceCache::notifyFlushOccurred(FlushType type) { |
| 599 switch (type) { | 667 switch (type) { |
| 600 case FlushType::kImmediateMode: | 668 case FlushType::kImmediateMode: |
| 601 break; | 669 break; |
| 602 case FlushType::kCacheRequested: | 670 case FlushType::kCacheRequested: |
| 603 SkASSERT(fRequestFlush); | |
| 604 fRequestFlush = false; | |
| 605 break; | 671 break; |
| 606 case FlushType::kExternal: | 672 case FlushType::kExternal: { |
| 673 int scoreDelta = 1; |
| 674 if (fMissesThisFlushPurgedRecently) { |
| 675 // If > 60% of our cache misses were things we purged in the las
t two flushes |
| 676 // then we move closer towards selecting random replacement. |
| 677 if ((float)fMissesThisFlushPurgedRecently / fTotalMissesThisFlus
h > 0.6f) { |
| 678 scoreDelta = -1; |
| 679 } |
| 680 } |
| 681 fStrategyScore = SkTPin(fStrategyScore + scoreDelta, kStrategyScoreM
in, |
| 682 kStrategyScoreMax); |
| 683 fStrategy = fStrategyScore < 0 ? ReplacementStrategy::kRandom |
| 684 : ReplacementStrategy::kLRU; |
| 685 fMissesThisFlushPurgedRecently = 0; |
| 686 fTotalMissesThisFlush = 0; |
| 687 fFlushParity = -(fFlushParity - 1); |
| 688 fUniqueKeysPurgedThisFlush[fFlushParity].reset(); |
| 689 fUniqueKeysPurgedThisFlushStorage[fFlushParity]->rewind(); |
| 607 ++fExternalFlushCnt; | 690 ++fExternalFlushCnt; |
| 608 if (0 == fExternalFlushCnt) { | 691 if (0 == fExternalFlushCnt) { |
| 609 // When this wraps just reset all the purgeable resources' last
used flush state. | 692 // When this wraps just reset all the purgeable resources' last
used flush state. |
| 610 for (int i = 0; i < fPurgeableQueue.count(); ++i) { | 693 for (int i = 0; i < fPurgeableQueue.count(); ++i) { |
| 611 fPurgeableQueue.at(i)->cacheAccess().setFlushCntWhenResource
BecamePurgeable(0); | 694 fPurgeableQueue.at(i)->cacheAccess().setFlushCntWhenResource
BecamePurgeable(0); |
| 612 } | 695 } |
| 613 } | 696 } |
| 614 break; | 697 break; |
| 698 } |
| 615 } | 699 } |
| 616 this->purgeAsNeeded(); | 700 this->internalPurgeAsNeeded(true); |
| 617 } | 701 } |
| 618 | 702 |
| 619 void GrResourceCache::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) c
onst { | 703 void GrResourceCache::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) c
onst { |
| 620 for (int i = 0; i < fNonpurgeableResources.count(); ++i) { | 704 for (int i = 0; i < fNonpurgeableResources.count(); ++i) { |
| 621 fNonpurgeableResources[i]->dumpMemoryStatistics(traceMemoryDump); | 705 fNonpurgeableResources[i]->dumpMemoryStatistics(traceMemoryDump); |
| 622 } | 706 } |
| 623 for (int i = 0; i < fPurgeableQueue.count(); ++i) { | 707 for (int i = 0; i < fPurgeableQueue.count(); ++i) { |
| 624 fPurgeableQueue.at(i)->dumpMemoryStatistics(traceMemoryDump); | 708 fPurgeableQueue.at(i)->dumpMemoryStatistics(traceMemoryDump); |
| 625 } | 709 } |
| 626 } | 710 } |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 754 return true; | 838 return true; |
| 755 } | 839 } |
| 756 if (index < fNonpurgeableResources.count() && fNonpurgeableResources[index]
== resource) { | 840 if (index < fNonpurgeableResources.count() && fNonpurgeableResources[index]
== resource) { |
| 757 return true; | 841 return true; |
| 758 } | 842 } |
| 759 SkDEBUGFAIL("Resource index should be -1 or the resource should be in the ca
che."); | 843 SkDEBUGFAIL("Resource index should be -1 or the resource should be in the ca
che."); |
| 760 return false; | 844 return false; |
| 761 } | 845 } |
| 762 | 846 |
| 763 #endif | 847 #endif |
| OLD | NEW |