OLD | NEW |
---|---|
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2014 Google Inc. | 3 * Copyright 2014 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 | 9 |
10 #include "GrResourceCache.h" | 10 #include "GrResourceCache.h" |
11 #include "GrGpuResourceCacheAccess.h" | 11 #include "GrGpuResourceCacheAccess.h" |
12 #include "SkChecksum.h" | 12 #include "SkChecksum.h" |
13 #include "SkGr.h" | 13 #include "SkGr.h" |
14 #include "SkMessageBus.h" | 14 #include "SkMessageBus.h" |
15 #include "SkTSort.h" | |
15 | 16 |
16 DECLARE_SKMESSAGEBUS_MESSAGE(GrUniqueKeyInvalidatedMessage); | 17 DECLARE_SKMESSAGEBUS_MESSAGE(GrUniqueKeyInvalidatedMessage); |
17 | 18 |
18 ////////////////////////////////////////////////////////////////////////////// | 19 ////////////////////////////////////////////////////////////////////////////// |
19 | 20 |
20 GrScratchKey::ResourceType GrScratchKey::GenerateResourceType() { | 21 GrScratchKey::ResourceType GrScratchKey::GenerateResourceType() { |
21 static int32_t gType = INHERITED::kInvalidDomain + 1; | 22 static int32_t gType = INHERITED::kInvalidDomain + 1; |
22 | 23 |
23 int32_t type = sk_atomic_inc(&gType); | 24 int32_t type = sk_atomic_inc(&gType); |
24 if (type > SK_MaxU16) { | 25 if (type > SK_MaxU16) { |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
83 fMaxCount = count; | 84 fMaxCount = count; |
84 fMaxBytes = bytes; | 85 fMaxBytes = bytes; |
85 this->purgeAsNeeded(); | 86 this->purgeAsNeeded(); |
86 } | 87 } |
87 | 88 |
88 void GrResourceCache::insertResource(GrGpuResource* resource) { | 89 void GrResourceCache::insertResource(GrGpuResource* resource) { |
89 SkASSERT(resource); | 90 SkASSERT(resource); |
90 SkASSERT(!this->isInCache(resource)); | 91 SkASSERT(!this->isInCache(resource)); |
91 SkASSERT(!resource->wasDestroyed()); | 92 SkASSERT(!resource->wasDestroyed()); |
92 SkASSERT(!resource->isPurgeable()); | 93 SkASSERT(!resource->isPurgeable()); |
94 | |
robertphillips
2015/02/19 18:47:32
adding _to_ ?
bsalomon
2015/02/19 18:52:54
Done.
| |
95 // We must set the timestamp before adding the array in case the timestamp w raps and we wind | |
robertphillips
2015/02/19 18:47:32
iterating _over_ ?
bsalomon
2015/02/19 18:52:54
Done.
| |
96 // up iterating all the resources that already have timestamps. | |
97 resource->cacheAccess().setTimestamp(this->getNextTimestamp()); | |
98 | |
93 this->addToNonpurgeableArray(resource); | 99 this->addToNonpurgeableArray(resource); |
94 | 100 |
95 size_t size = resource->gpuMemorySize(); | 101 size_t size = resource->gpuMemorySize(); |
96 SkDEBUGCODE(++fCount;) | 102 SkDEBUGCODE(++fCount;) |
97 fBytes += size; | 103 fBytes += size; |
98 #if GR_CACHE_STATS | 104 #if GR_CACHE_STATS |
99 fHighWaterCount = SkTMax(this->getResourceCount(), fHighWaterCount); | 105 fHighWaterCount = SkTMax(this->getResourceCount(), fHighWaterCount); |
100 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes); | 106 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes); |
101 #endif | 107 #endif |
102 if (resource->resourcePriv().isBudgeted()) { | 108 if (resource->resourcePriv().isBudgeted()) { |
103 ++fBudgetedCount; | 109 ++fBudgetedCount; |
104 fBudgetedBytes += size; | 110 fBudgetedBytes += size; |
105 #if GR_CACHE_STATS | 111 #if GR_CACHE_STATS |
106 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount ); | 112 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount ); |
107 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes ); | 113 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes ); |
108 #endif | 114 #endif |
109 } | 115 } |
110 if (resource->resourcePriv().getScratchKey().isValid()) { | 116 if (resource->resourcePriv().getScratchKey().isValid()) { |
111 SkASSERT(!resource->cacheAccess().isWrapped()); | 117 SkASSERT(!resource->cacheAccess().isWrapped()); |
112 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource); | 118 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource); |
113 } | 119 } |
114 | 120 |
115 resource->cacheAccess().setTimestamp(fTimestamp++); | |
116 | |
117 this->purgeAsNeeded(); | 121 this->purgeAsNeeded(); |
118 } | 122 } |
119 | 123 |
120 void GrResourceCache::removeResource(GrGpuResource* resource) { | 124 void GrResourceCache::removeResource(GrGpuResource* resource) { |
121 this->validate(); | 125 this->validate(); |
122 SkASSERT(this->isInCache(resource)); | 126 SkASSERT(this->isInCache(resource)); |
123 | 127 |
124 if (resource->isPurgeable()) { | 128 if (resource->isPurgeable()) { |
125 fPurgeableQueue.remove(resource); | 129 fPurgeableQueue.remove(resource); |
126 } else { | 130 } else { |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
279 } else { | 283 } else { |
280 resource->cacheAccess().removeUniqueKey(); | 284 resource->cacheAccess().removeUniqueKey(); |
281 } | 285 } |
282 | 286 |
283 this->validate(); | 287 this->validate(); |
284 } | 288 } |
285 | 289 |
286 void GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) { | 290 void GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) { |
287 SkASSERT(resource); | 291 SkASSERT(resource); |
288 SkASSERT(this->isInCache(resource)); | 292 SkASSERT(this->isInCache(resource)); |
293 | |
289 if (resource->isPurgeable()) { | 294 if (resource->isPurgeable()) { |
290 // It's about to become unpurgeable. | 295 // It's about to become unpurgeable. |
291 fPurgeableQueue.remove(resource); | 296 fPurgeableQueue.remove(resource); |
292 this->addToNonpurgeableArray(resource); | 297 this->addToNonpurgeableArray(resource); |
293 } | 298 } |
294 resource->ref(); | 299 resource->ref(); |
295 resource->cacheAccess().setTimestamp(fTimestamp++); | 300 |
301 resource->cacheAccess().setTimestamp(this->getNextTimestamp()); | |
296 this->validate(); | 302 this->validate(); |
297 } | 303 } |
298 | 304 |
299 void GrResourceCache::notifyPurgeable(GrGpuResource* resource) { | 305 void GrResourceCache::notifyPurgeable(GrGpuResource* resource) { |
300 SkASSERT(resource); | 306 SkASSERT(resource); |
301 SkASSERT(this->isInCache(resource)); | 307 SkASSERT(this->isInCache(resource)); |
302 SkASSERT(resource->isPurgeable()); | 308 SkASSERT(resource->isPurgeable()); |
303 | 309 |
304 this->removeFromNonpurgeableArray(resource); | 310 this->removeFromNonpurgeableArray(resource); |
305 fPurgeableQueue.insert(resource); | 311 fPurgeableQueue.insert(resource); |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
434 // Fill the whole we will create in the array with the tail object, adjust i ts index, and | 440 // Fill the whole we will create in the array with the tail object, adjust i ts index, and |
435 // then pop the array | 441 // then pop the array |
436 GrGpuResource* tail = *(fNonpurgeableResources.end() - 1); | 442 GrGpuResource* tail = *(fNonpurgeableResources.end() - 1); |
437 SkASSERT(fNonpurgeableResources[*index] == resource); | 443 SkASSERT(fNonpurgeableResources[*index] == resource); |
438 fNonpurgeableResources[*index] = tail; | 444 fNonpurgeableResources[*index] = tail; |
439 *tail->cacheAccess().accessCacheIndex() = *index; | 445 *tail->cacheAccess().accessCacheIndex() = *index; |
440 fNonpurgeableResources.pop(); | 446 fNonpurgeableResources.pop(); |
441 SkDEBUGCODE(*index = -1); | 447 SkDEBUGCODE(*index = -1); |
442 } | 448 } |
443 | 449 |
450 uint32_t GrResourceCache::getNextTimestamp() { | |
451 // If we wrap then all the existing resources will appear older than any res ources that get | |
452 // a timestamp after the wrap. | |
453 if (0 == fTimestamp) { | |
454 int count = this->getResourceCount(); | |
455 if (count) { | |
robertphillips
2015/02/19 18:47:33
resource -> resources
bsalomon
2015/02/19 18:52:54
Done.
| |
456 // Reset all the timestamps. We sort the resource by timestamp and t hen assign | |
457 // sequential timestamps beginning with 0. This is O(n*lg(n)) but it should be extremely | |
458 // rare. | |
459 SkTDArray<GrGpuResource*> sortedPurgeableResources; | |
460 sortedPurgeableResources.setReserve(fPurgeableQueue.count()); | |
461 | |
462 while (fPurgeableQueue.count()) { | |
463 *sortedPurgeableResources.append() = fPurgeableQueue.peek(); | |
464 fPurgeableQueue.pop(); | |
465 } | |
466 | |
467 struct Less { | |
468 bool operator()(GrGpuResource* a, GrGpuResource* b) { | |
469 return CompareTimestamp(a,b); | |
470 } | |
471 }; | |
472 Less less; | |
473 SkTQSort(fNonpurgeableResources.begin(), fNonpurgeableResources.end( ) - 1, less); | |
474 | |
robertphillips
2015/02/19 18:47:32
_arrays_ based ?
bsalomon
2015/02/19 18:52:54
Done.
| |
475 // Pick resources out of the purgeable and non-purgeable based on lo west timestamp | |
476 // and assign new timestamps. | |
477 int currP = 0; | |
478 int currNP = 0; | |
479 while (currP < sortedPurgeableResources.count() && | |
480 currNP < fNonpurgeableResources.count()) { | |
481 uint32_t tsP = sortedPurgeableResources[currP]->cacheAccess().ti mestamp(); | |
482 uint32_t tsNP = fNonpurgeableResources[currNP]->cacheAccess().ti mestamp(); | |
483 SkASSERT(tsP != tsNP); | |
484 if (tsP < tsNP) { | |
485 sortedPurgeableResources[currP++]->cacheAccess().setTimestam p(fTimestamp++); | |
486 } else { | |
487 // Correct the index in the nonpurgeable array stored on the resource post-sort. | |
488 *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIn dex() = currNP; | |
489 fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp (fTimestamp++); | |
490 } | |
491 } | |
492 | |
493 // The above loop ended when we hit the end of one array. Finish the other one. | |
494 while (currP < sortedPurgeableResources.count()) { | |
495 sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fT imestamp++); | |
496 } | |
497 while (currNP < fNonpurgeableResources.count()) { | |
robertphillips
2015/02/19 18:47:32
rm a tab level ?
bsalomon
2015/02/19 18:52:54
Done.
| |
498 *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIn dex() = currNP; | |
499 fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp (fTimestamp++); | |
500 } | |
501 | |
502 // Rebuild the queue. | |
503 for (int i = 0; i < sortedPurgeableResources.count(); ++i) { | |
504 fPurgeableQueue.insert(sortedPurgeableResources[i]); | |
505 } | |
506 | |
507 this->validate(); | |
508 SkASSERT(count == this->getResourceCount()); | |
509 | |
510 // count should be the next timestamp we return. | |
511 SkASSERT(fTimestamp == count); | |
512 } | |
513 } | |
514 return fTimestamp++; | |
515 } | |
516 | |
444 #ifdef SK_DEBUG | 517 #ifdef SK_DEBUG |
445 void GrResourceCache::validate() const { | 518 void GrResourceCache::validate() const { |
446 // Reduce the frequency of validations for large resource counts. | 519 // Reduce the frequency of validations for large resource counts. |
447 static SkRandom gRandom; | 520 static SkRandom gRandom; |
448 int mask = (SkNextPow2(fCount + 1) >> 5) - 1; | 521 int mask = (SkNextPow2(fCount + 1) >> 5) - 1; |
449 if (~mask && (gRandom.nextU() & mask)) { | 522 if (~mask && (gRandom.nextU() & mask)) { |
450 return; | 523 return; |
451 } | 524 } |
452 | 525 |
453 struct Stats { | 526 struct Stats { |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
548 return true; | 621 return true; |
549 } | 622 } |
550 if (index < fNonpurgeableResources.count() && fNonpurgeableResources[index] == resource) { | 623 if (index < fNonpurgeableResources.count() && fNonpurgeableResources[index] == resource) { |
551 return true; | 624 return true; |
552 } | 625 } |
553 SkDEBUGFAIL("Resource index should be -1 or the resource should be in the ca che."); | 626 SkDEBUGFAIL("Resource index should be -1 or the resource should be in the ca che."); |
554 return false; | 627 return false; |
555 } | 628 } |
556 | 629 |
557 #endif | 630 #endif |
OLD | NEW |