Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2010 Google Inc. | 3 * Copyright 2010 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 | 10 |
| 11 #include "GrResourceCache.h" | 11 #include "GrResourceCache.h" |
| 12 #include "GrCacheable.h" | 12 #include "GrCacheable.h" |
| 13 | 13 |
| 14 DECLARE_SKMESSAGEBUS_MESSAGE(GrResourceInvalidatedMessage); | 14 DECLARE_SKMESSAGEBUS_MESSAGE(GrResourceInvalidatedMessage); |
| 15 | 15 |
| 16 /////////////////////////////////////////////////////////////////////////////// | |
| 17 | |
| 18 void GrCacheable::onResourceSizeChanged() const { | |
| 19 if (this->isInCache()) | |
| 20 fCacheEntry->onResourceSizeChanged(); | |
|
bsalomon
2014/04/28 21:08:33
{ }
Chris Dalton
2014/04/28 22:30:58
Done.
| |
| 21 } | |
| 22 | |
| 23 /////////////////////////////////////////////////////////////////////////////// | |
| 24 | |
| 16 GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() { | 25 GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() { |
| 17 static int32_t gNextType = 0; | 26 static int32_t gNextType = 0; |
| 18 | 27 |
| 19 int32_t type = sk_atomic_inc(&gNextType); | 28 int32_t type = sk_atomic_inc(&gNextType); |
| 20 if (type >= (1 << 8 * sizeof(ResourceType))) { | 29 if (type >= (1 << 8 * sizeof(ResourceType))) { |
| 21 GrCrash("Too many Resource Types"); | 30 GrCrash("Too many Resource Types"); |
| 22 } | 31 } |
| 23 | 32 |
| 24 return static_cast<ResourceType>(type); | 33 return static_cast<ResourceType>(type); |
| 25 } | 34 } |
| 26 | 35 |
| 27 /////////////////////////////////////////////////////////////////////////////// | 36 /////////////////////////////////////////////////////////////////////////////// |
| 28 | 37 |
| 29 GrResourceCacheEntry::GrResourceCacheEntry(const GrResourceKey& key, GrCacheable * resource) | 38 GrResourceCacheEntry::GrResourceCacheEntry(GrResourceCache* resourceCache, |
| 30 : fKey(key), fResource(resource) { | 39 const GrResourceKey& key, |
| 40 GrCacheable* resource) | |
| 41 : fResourceCache(resourceCache), | |
| 42 fKey(key), | |
| 43 fResource(resource), | |
| 44 fCachedSize(resource->gpuMemorySize()), | |
| 45 fIsExclusive(false) { | |
| 31 // we assume ownership of the resource, and will unref it when we die | 46 // we assume ownership of the resource, and will unref it when we die |
| 32 SkASSERT(resource); | 47 SkASSERT(resource); |
| 33 resource->ref(); | 48 resource->ref(); |
| 34 } | 49 } |
| 35 | 50 |
| 36 GrResourceCacheEntry::~GrResourceCacheEntry() { | 51 GrResourceCacheEntry::~GrResourceCacheEntry() { |
| 37 fResource->setCacheEntry(NULL); | 52 fResource->setCacheEntry(NULL); |
| 38 fResource->unref(); | 53 fResource->unref(); |
| 39 } | 54 } |
| 40 | 55 |
| 41 #ifdef SK_DEBUG | 56 #ifdef SK_DEBUG |
| 42 void GrResourceCacheEntry::validate() const { | 57 void GrResourceCacheEntry::validate() const { |
| 58 SkASSERT(fResourceCache); | |
| 43 SkASSERT(fResource); | 59 SkASSERT(fResource); |
| 44 SkASSERT(fResource->getCacheEntry() == this); | 60 SkASSERT(fResource->getCacheEntry() == this); |
| 61 SkASSERT(fResource->gpuMemorySize() == fCachedSize); | |
| 45 fResource->validate(); | 62 fResource->validate(); |
| 46 } | 63 } |
| 47 #endif | 64 #endif |
| 48 | 65 |
| 66 void GrResourceCacheEntry::onResourceSizeChanged() { | |
| 67 size_t oldSize = fCachedSize; | |
| 68 fCachedSize = fResource->gpuMemorySize(); | |
| 69 if (fCachedSize > oldSize) { | |
| 70 fResourceCache->onResourceSizeIncreased(this, fCachedSize - oldSize); | |
| 71 } else if (fCachedSize < oldSize) { | |
| 72 fResourceCache->onResourceSizeDecreased(this, oldSize - fCachedSize); | |
| 73 } | |
| 74 } | |
| 75 | |
| 49 /////////////////////////////////////////////////////////////////////////////// | 76 /////////////////////////////////////////////////////////////////////////////// |
| 50 | 77 |
| 51 GrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) : | 78 GrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) : |
| 52 fMaxCount(maxCount), | 79 fMaxCount(maxCount), |
| 53 fMaxBytes(maxBytes) { | 80 fMaxBytes(maxBytes) { |
| 54 #if GR_CACHE_STATS | 81 #if GR_CACHE_STATS |
| 55 fHighWaterEntryCount = 0; | 82 fHighWaterEntryCount = 0; |
| 56 fHighWaterEntryBytes = 0; | 83 fHighWaterEntryBytes = 0; |
| 57 fHighWaterClientDetachedCount = 0; | 84 fHighWaterClientDetachedCount = 0; |
| 58 fHighWaterClientDetachedBytes = 0; | 85 fHighWaterClientDetachedBytes = 0; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 108 } | 135 } |
| 109 } | 136 } |
| 110 | 137 |
| 111 void GrResourceCache::internalDetach(GrResourceCacheEntry* entry, | 138 void GrResourceCache::internalDetach(GrResourceCacheEntry* entry, |
| 112 BudgetBehaviors behavior) { | 139 BudgetBehaviors behavior) { |
| 113 fList.remove(entry); | 140 fList.remove(entry); |
| 114 | 141 |
| 115 // update our stats | 142 // update our stats |
| 116 if (kIgnore_BudgetBehavior == behavior) { | 143 if (kIgnore_BudgetBehavior == behavior) { |
| 117 fClientDetachedCount += 1; | 144 fClientDetachedCount += 1; |
| 118 fClientDetachedBytes += entry->resource()->gpuMemorySize(); | 145 fClientDetachedBytes += entry->fCachedSize; |
| 119 | 146 |
| 120 #if GR_CACHE_STATS | 147 #if GR_CACHE_STATS |
| 121 if (fHighWaterClientDetachedCount < fClientDetachedCount) { | 148 if (fHighWaterClientDetachedCount < fClientDetachedCount) { |
| 122 fHighWaterClientDetachedCount = fClientDetachedCount; | 149 fHighWaterClientDetachedCount = fClientDetachedCount; |
| 123 } | 150 } |
| 124 if (fHighWaterClientDetachedBytes < fClientDetachedBytes) { | 151 if (fHighWaterClientDetachedBytes < fClientDetachedBytes) { |
| 125 fHighWaterClientDetachedBytes = fClientDetachedBytes; | 152 fHighWaterClientDetachedBytes = fClientDetachedBytes; |
| 126 } | 153 } |
| 127 #endif | 154 #endif |
| 128 | 155 |
| 129 } else { | 156 } else { |
| 130 SkASSERT(kAccountFor_BudgetBehavior == behavior); | 157 SkASSERT(kAccountFor_BudgetBehavior == behavior); |
| 131 | 158 |
| 132 fEntryCount -= 1; | 159 fEntryCount -= 1; |
| 133 fEntryBytes -= entry->resource()->gpuMemorySize(); | 160 fEntryBytes -= entry->fCachedSize; |
| 134 } | 161 } |
| 135 } | 162 } |
| 136 | 163 |
| 137 void GrResourceCache::attachToHead(GrResourceCacheEntry* entry, | 164 void GrResourceCache::attachToHead(GrResourceCacheEntry* entry, |
| 138 BudgetBehaviors behavior) { | 165 BudgetBehaviors behavior) { |
| 139 fList.addToHead(entry); | 166 fList.addToHead(entry); |
| 140 | 167 |
| 141 // update our stats | 168 // update our stats |
| 142 if (kIgnore_BudgetBehavior == behavior) { | 169 if (kIgnore_BudgetBehavior == behavior) { |
| 143 fClientDetachedCount -= 1; | 170 fClientDetachedCount -= 1; |
| 144 fClientDetachedBytes -= entry->resource()->gpuMemorySize(); | 171 fClientDetachedBytes -= entry->fCachedSize; |
| 145 } else { | 172 } else { |
| 146 SkASSERT(kAccountFor_BudgetBehavior == behavior); | 173 SkASSERT(kAccountFor_BudgetBehavior == behavior); |
| 147 | 174 |
| 148 fEntryCount += 1; | 175 fEntryCount += 1; |
| 149 fEntryBytes += entry->resource()->gpuMemorySize(); | 176 fEntryBytes += entry->fCachedSize; |
| 150 | 177 |
| 151 #if GR_CACHE_STATS | 178 #if GR_CACHE_STATS |
| 152 if (fHighWaterEntryCount < fEntryCount) { | 179 if (fHighWaterEntryCount < fEntryCount) { |
| 153 fHighWaterEntryCount = fEntryCount; | 180 fHighWaterEntryCount = fEntryCount; |
| 154 } | 181 } |
| 155 if (fHighWaterEntryBytes < fEntryBytes) { | 182 if (fHighWaterEntryBytes < fEntryBytes) { |
| 156 fHighWaterEntryBytes = fEntryBytes; | 183 fHighWaterEntryBytes = fEntryBytes; |
| 157 } | 184 } |
| 158 #endif | 185 #endif |
| 159 } | 186 } |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 201 GrCacheable* resource, | 228 GrCacheable* resource, |
| 202 uint32_t ownershipFlags) { | 229 uint32_t ownershipFlags) { |
| 203 SkASSERT(NULL == resource->getCacheEntry()); | 230 SkASSERT(NULL == resource->getCacheEntry()); |
| 204 // we don't expect to create new resources during a purge. In theory | 231 // we don't expect to create new resources during a purge. In theory |
| 205 // this could cause purgeAsNeeded() into an infinite loop (e.g. | 232 // this could cause purgeAsNeeded() into an infinite loop (e.g. |
| 206 // each resource destroyed creates and locks 2 resources and | 233 // each resource destroyed creates and locks 2 resources and |
| 207 // unlocks 1 thereby causing a new purge). | 234 // unlocks 1 thereby causing a new purge). |
| 208 SkASSERT(!fPurging); | 235 SkASSERT(!fPurging); |
| 209 GrAutoResourceCacheValidate atcv(this); | 236 GrAutoResourceCacheValidate atcv(this); |
| 210 | 237 |
| 211 GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (key, resourc e)); | 238 GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (this, key, r esource)); |
| 212 resource->setCacheEntry(entry); | 239 resource->setCacheEntry(entry); |
| 213 | 240 |
| 214 this->attachToHead(entry); | 241 this->attachToHead(entry); |
| 215 fCache.insert(key, entry); | 242 fCache.insert(key, entry); |
| 216 | 243 |
| 217 if (ownershipFlags & kHide_OwnershipFlag) { | 244 if (ownershipFlags & kHide_OwnershipFlag) { |
| 218 this->makeExclusive(entry); | 245 this->makeExclusive(entry); |
| 219 } | 246 } |
| 220 | 247 |
| 221 } | 248 } |
| 222 | 249 |
| 223 void GrResourceCache::makeExclusive(GrResourceCacheEntry* entry) { | 250 void GrResourceCache::makeExclusive(GrResourceCacheEntry* entry) { |
| 224 GrAutoResourceCacheValidate atcv(this); | 251 GrAutoResourceCacheValidate atcv(this); |
| 225 | 252 |
| 253 SkASSERT(!entry->fIsExclusive); | |
| 254 entry->fIsExclusive = true; | |
| 255 | |
| 226 // When scratch textures are detached (to hide them from future finds) they | 256 // When scratch textures are detached (to hide them from future finds) they |
| 227 // still count against the resource budget | 257 // still count against the resource budget |
| 228 this->internalDetach(entry, kIgnore_BudgetBehavior); | 258 this->internalDetach(entry, kIgnore_BudgetBehavior); |
| 229 fCache.remove(entry->key(), entry); | 259 fCache.remove(entry->key(), entry); |
| 230 | 260 |
| 231 #ifdef SK_DEBUG | 261 #ifdef SK_DEBUG |
| 232 fExclusiveList.addToHead(entry); | 262 fExclusiveList.addToHead(entry); |
| 233 #endif | 263 #endif |
| 234 } | 264 } |
| 235 | 265 |
| 236 void GrResourceCache::removeInvalidResource(GrResourceCacheEntry* entry) { | 266 void GrResourceCache::removeInvalidResource(GrResourceCacheEntry* entry) { |
| 237 // If the resource went invalid while it was detached then purge it | 267 // If the resource went invalid while it was detached then purge it |
| 238 // This can happen when a 3D context was lost, | 268 // This can happen when a 3D context was lost, |
| 239 // the client called GrContext::contextDestroyed() to notify Gr, | 269 // the client called GrContext::contextDestroyed() to notify Gr, |
| 240 // and then later an SkGpuDevice's destructor releases its backing | 270 // and then later an SkGpuDevice's destructor releases its backing |
| 241 // texture (which was invalidated at contextDestroyed time). | 271 // texture (which was invalidated at contextDestroyed time). |
| 242 fClientDetachedCount -= 1; | 272 fClientDetachedCount -= 1; |
| 243 fEntryCount -= 1; | 273 fEntryCount -= 1; |
| 244 size_t size = entry->resource()->gpuMemorySize(); | 274 size_t size = entry->fCachedSize; |
| 275 entry->fResource->setCacheEntry(NULL); | |
| 276 delete entry; | |
| 245 fClientDetachedBytes -= size; | 277 fClientDetachedBytes -= size; |
| 246 fEntryBytes -= size; | 278 fEntryBytes -= size; |
| 247 } | 279 } |
| 248 | 280 |
| 249 void GrResourceCache::makeNonExclusive(GrResourceCacheEntry* entry) { | 281 void GrResourceCache::makeNonExclusive(GrResourceCacheEntry* entry) { |
| 250 GrAutoResourceCacheValidate atcv(this); | 282 GrAutoResourceCacheValidate atcv(this); |
| 251 | 283 |
| 252 #ifdef SK_DEBUG | 284 #ifdef SK_DEBUG |
| 253 fExclusiveList.remove(entry); | 285 fExclusiveList.remove(entry); |
| 254 #endif | 286 #endif |
| 255 | 287 |
| 256 if (entry->resource()->isValidOnGpu()) { | 288 if (entry->resource()->isValidOnGpu()) { |
| 257 // Since scratch textures still count against the cache budget even | 289 // Since scratch textures still count against the cache budget even |
| 258 // when they have been removed from the cache, re-adding them doesn't | 290 // when they have been removed from the cache, re-adding them doesn't |
| 259 // alter the budget information. | 291 // alter the budget information. |
| 260 attachToHead(entry, kIgnore_BudgetBehavior); | 292 attachToHead(entry, kIgnore_BudgetBehavior); |
| 261 fCache.insert(entry->key(), entry); | 293 fCache.insert(entry->key(), entry); |
| 294 | |
| 295 SkASSERT(entry->fIsExclusive); | |
| 296 entry->fIsExclusive = false; | |
| 262 } else { | 297 } else { |
| 263 this->removeInvalidResource(entry); | 298 this->removeInvalidResource(entry); |
| 264 } | 299 } |
| 265 } | 300 } |
| 266 | 301 |
| 302 void GrResourceCache::onResourceSizeIncreased(const GrResourceCacheEntry* entry, size_t amount) { | |
| 303 fEntryBytes += amount; | |
| 304 if (entry->fIsExclusive) { | |
| 305 fClientDetachedBytes += amount; | |
| 306 } | |
| 307 this->purgeAsNeeded(); | |
| 308 } | |
| 309 | |
| 310 void GrResourceCache::onResourceSizeDecreased(const GrResourceCacheEntry* entry, size_t amount) { | |
| 311 fEntryBytes -= amount; | |
| 312 if (entry->fIsExclusive) { | |
| 313 fClientDetachedBytes -= amount; | |
| 314 } | |
| 315 #ifdef SK_DEBUG | |
| 316 this->validate(); | |
| 317 #endif | |
| 318 } | |
| 319 | |
| 267 /** | 320 /** |
| 268 * Destroying a resource may potentially trigger the unlock of additional | 321 * Destroying a resource may potentially trigger the unlock of additional |
| 269 * resources which in turn will trigger a nested purge. We block the nested | 322 * resources which in turn will trigger a nested purge. We block the nested |
| 270 * purge using the fPurging variable. However, the initial purge will keep | 323 * purge using the fPurging variable. However, the initial purge will keep |
| 271 * looping until either all resources in the cache are unlocked or we've met | 324 * looping until either all resources in the cache are unlocked or we've met |
| 272 * the budget. There is an assertion in createAndLock to check against a | 325 * the budget. There is an assertion in createAndLock to check against a |
| 273 * resource's destructor inserting new resources into the cache. If these | 326 * resource's destructor inserting new resources into the cache. If these |
| 274 * new resources were unlocked before purgeAsNeeded completed it could | 327 * new resources were unlocked before purgeAsNeeded completed it could |
| 275 * potentially make purgeAsNeeded loop infinitely. | 328 * potentially make purgeAsNeeded loop infinitely. |
| 276 * | 329 * |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 483 fEntryBytes, fHighWaterEntryBytes); | 536 fEntryBytes, fHighWaterEntryBytes); |
| 484 SkDebugf("\t\tDetached Entry Count: current %d high %d\n", | 537 SkDebugf("\t\tDetached Entry Count: current %d high %d\n", |
| 485 fClientDetachedCount, fHighWaterClientDetachedCount); | 538 fClientDetachedCount, fHighWaterClientDetachedCount); |
| 486 SkDebugf("\t\tDetached Bytes: current %d high %d\n", | 539 SkDebugf("\t\tDetached Bytes: current %d high %d\n", |
| 487 fClientDetachedBytes, fHighWaterClientDetachedBytes); | 540 fClientDetachedBytes, fHighWaterClientDetachedBytes); |
| 488 } | 541 } |
| 489 | 542 |
| 490 #endif | 543 #endif |
| 491 | 544 |
| 492 /////////////////////////////////////////////////////////////////////////////// | 545 /////////////////////////////////////////////////////////////////////////////// |
| OLD | NEW |