| 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::didChangeGpuMemorySize() const { |
| 19 if (this->isInCache()) { |
| 20 fCacheEntry->didChangeResourceSize(); |
| 21 } |
| 22 } |
| 23 |
| 24 /////////////////////////////////////////////////////////////////////////////// |
| 25 |
| 16 GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() { | 26 GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() { |
| 17 static int32_t gNextType = 0; | 27 static int32_t gNextType = 0; |
| 18 | 28 |
| 19 int32_t type = sk_atomic_inc(&gNextType); | 29 int32_t type = sk_atomic_inc(&gNextType); |
| 20 if (type >= (1 << 8 * sizeof(ResourceType))) { | 30 if (type >= (1 << 8 * sizeof(ResourceType))) { |
| 21 SkFAIL("Too many Resource Types"); | 31 SkFAIL("Too many Resource Types"); |
| 22 } | 32 } |
| 23 | 33 |
| 24 return static_cast<ResourceType>(type); | 34 return static_cast<ResourceType>(type); |
| 25 } | 35 } |
| 26 | 36 |
| 27 /////////////////////////////////////////////////////////////////////////////// | 37 /////////////////////////////////////////////////////////////////////////////// |
| 28 | 38 |
| 29 GrResourceCacheEntry::GrResourceCacheEntry(const GrResourceKey& key, GrCacheable
* resource) | 39 GrResourceCacheEntry::GrResourceCacheEntry(GrResourceCache* resourceCache, |
| 30 : fKey(key), fResource(resource) { | 40 const GrResourceKey& key, |
| 41 GrCacheable* resource) |
| 42 : fResourceCache(resourceCache), |
| 43 fKey(key), |
| 44 fResource(resource), |
| 45 fCachedSize(resource->gpuMemorySize()), |
| 46 fIsExclusive(false) { |
| 31 // we assume ownership of the resource, and will unref it when we die | 47 // we assume ownership of the resource, and will unref it when we die |
| 32 SkASSERT(resource); | 48 SkASSERT(resource); |
| 33 resource->ref(); | 49 resource->ref(); |
| 34 } | 50 } |
| 35 | 51 |
| 36 GrResourceCacheEntry::~GrResourceCacheEntry() { | 52 GrResourceCacheEntry::~GrResourceCacheEntry() { |
| 37 fResource->setCacheEntry(NULL); | 53 fResource->setCacheEntry(NULL); |
| 38 fResource->unref(); | 54 fResource->unref(); |
| 39 } | 55 } |
| 40 | 56 |
| 41 #ifdef SK_DEBUG | 57 #ifdef SK_DEBUG |
| 42 void GrResourceCacheEntry::validate() const { | 58 void GrResourceCacheEntry::validate() const { |
| 59 SkASSERT(fResourceCache); |
| 43 SkASSERT(fResource); | 60 SkASSERT(fResource); |
| 44 SkASSERT(fResource->getCacheEntry() == this); | 61 SkASSERT(fResource->getCacheEntry() == this); |
| 62 SkASSERT(fResource->gpuMemorySize() == fCachedSize); |
| 45 fResource->validate(); | 63 fResource->validate(); |
| 46 } | 64 } |
| 47 #endif | 65 #endif |
| 48 | 66 |
| 67 void GrResourceCacheEntry::didChangeResourceSize() { |
| 68 size_t oldSize = fCachedSize; |
| 69 fCachedSize = fResource->gpuMemorySize(); |
| 70 if (fCachedSize > oldSize) { |
| 71 fResourceCache->didIncreaseResourceSize(this, fCachedSize - oldSize); |
| 72 } else if (fCachedSize < oldSize) { |
| 73 fResourceCache->didDecreaseResourceSize(this, oldSize - fCachedSize); |
| 74 } |
| 75 } |
| 76 |
| 49 /////////////////////////////////////////////////////////////////////////////// | 77 /////////////////////////////////////////////////////////////////////////////// |
| 50 | 78 |
| 51 GrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) : | 79 GrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) : |
| 52 fMaxCount(maxCount), | 80 fMaxCount(maxCount), |
| 53 fMaxBytes(maxBytes) { | 81 fMaxBytes(maxBytes) { |
| 54 #if GR_CACHE_STATS | 82 #if GR_CACHE_STATS |
| 55 fHighWaterEntryCount = 0; | 83 fHighWaterEntryCount = 0; |
| 56 fHighWaterEntryBytes = 0; | 84 fHighWaterEntryBytes = 0; |
| 57 fHighWaterClientDetachedCount = 0; | 85 fHighWaterClientDetachedCount = 0; |
| 58 fHighWaterClientDetachedBytes = 0; | 86 fHighWaterClientDetachedBytes = 0; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 108 } | 136 } |
| 109 } | 137 } |
| 110 | 138 |
| 111 void GrResourceCache::internalDetach(GrResourceCacheEntry* entry, | 139 void GrResourceCache::internalDetach(GrResourceCacheEntry* entry, |
| 112 BudgetBehaviors behavior) { | 140 BudgetBehaviors behavior) { |
| 113 fList.remove(entry); | 141 fList.remove(entry); |
| 114 | 142 |
| 115 // update our stats | 143 // update our stats |
| 116 if (kIgnore_BudgetBehavior == behavior) { | 144 if (kIgnore_BudgetBehavior == behavior) { |
| 117 fClientDetachedCount += 1; | 145 fClientDetachedCount += 1; |
| 118 fClientDetachedBytes += entry->resource()->gpuMemorySize(); | 146 fClientDetachedBytes += entry->fCachedSize; |
| 119 | 147 |
| 120 #if GR_CACHE_STATS | 148 #if GR_CACHE_STATS |
| 121 if (fHighWaterClientDetachedCount < fClientDetachedCount) { | 149 if (fHighWaterClientDetachedCount < fClientDetachedCount) { |
| 122 fHighWaterClientDetachedCount = fClientDetachedCount; | 150 fHighWaterClientDetachedCount = fClientDetachedCount; |
| 123 } | 151 } |
| 124 if (fHighWaterClientDetachedBytes < fClientDetachedBytes) { | 152 if (fHighWaterClientDetachedBytes < fClientDetachedBytes) { |
| 125 fHighWaterClientDetachedBytes = fClientDetachedBytes; | 153 fHighWaterClientDetachedBytes = fClientDetachedBytes; |
| 126 } | 154 } |
| 127 #endif | 155 #endif |
| 128 | 156 |
| 129 } else { | 157 } else { |
| 130 SkASSERT(kAccountFor_BudgetBehavior == behavior); | 158 SkASSERT(kAccountFor_BudgetBehavior == behavior); |
| 131 | 159 |
| 132 fEntryCount -= 1; | 160 fEntryCount -= 1; |
| 133 fEntryBytes -= entry->resource()->gpuMemorySize(); | 161 fEntryBytes -= entry->fCachedSize; |
| 134 } | 162 } |
| 135 } | 163 } |
| 136 | 164 |
| 137 void GrResourceCache::attachToHead(GrResourceCacheEntry* entry, | 165 void GrResourceCache::attachToHead(GrResourceCacheEntry* entry, |
| 138 BudgetBehaviors behavior) { | 166 BudgetBehaviors behavior) { |
| 139 fList.addToHead(entry); | 167 fList.addToHead(entry); |
| 140 | 168 |
| 141 // update our stats | 169 // update our stats |
| 142 if (kIgnore_BudgetBehavior == behavior) { | 170 if (kIgnore_BudgetBehavior == behavior) { |
| 143 fClientDetachedCount -= 1; | 171 fClientDetachedCount -= 1; |
| 144 fClientDetachedBytes -= entry->resource()->gpuMemorySize(); | 172 fClientDetachedBytes -= entry->fCachedSize; |
| 145 } else { | 173 } else { |
| 146 SkASSERT(kAccountFor_BudgetBehavior == behavior); | 174 SkASSERT(kAccountFor_BudgetBehavior == behavior); |
| 147 | 175 |
| 148 fEntryCount += 1; | 176 fEntryCount += 1; |
| 149 fEntryBytes += entry->resource()->gpuMemorySize(); | 177 fEntryBytes += entry->fCachedSize; |
| 150 | 178 |
| 151 #if GR_CACHE_STATS | 179 #if GR_CACHE_STATS |
| 152 if (fHighWaterEntryCount < fEntryCount) { | 180 if (fHighWaterEntryCount < fEntryCount) { |
| 153 fHighWaterEntryCount = fEntryCount; | 181 fHighWaterEntryCount = fEntryCount; |
| 154 } | 182 } |
| 155 if (fHighWaterEntryBytes < fEntryBytes) { | 183 if (fHighWaterEntryBytes < fEntryBytes) { |
| 156 fHighWaterEntryBytes = fEntryBytes; | 184 fHighWaterEntryBytes = fEntryBytes; |
| 157 } | 185 } |
| 158 #endif | 186 #endif |
| 159 } | 187 } |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 GrCacheable* resource, | 229 GrCacheable* resource, |
| 202 uint32_t ownershipFlags) { | 230 uint32_t ownershipFlags) { |
| 203 SkASSERT(NULL == resource->getCacheEntry()); | 231 SkASSERT(NULL == resource->getCacheEntry()); |
| 204 // we don't expect to create new resources during a purge. In theory | 232 // we don't expect to create new resources during a purge. In theory |
| 205 // this could cause purgeAsNeeded() into an infinite loop (e.g. | 233 // this could cause purgeAsNeeded() into an infinite loop (e.g. |
| 206 // each resource destroyed creates and locks 2 resources and | 234 // each resource destroyed creates and locks 2 resources and |
| 207 // unlocks 1 thereby causing a new purge). | 235 // unlocks 1 thereby causing a new purge). |
| 208 SkASSERT(!fPurging); | 236 SkASSERT(!fPurging); |
| 209 GrAutoResourceCacheValidate atcv(this); | 237 GrAutoResourceCacheValidate atcv(this); |
| 210 | 238 |
| 211 GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (key, resourc
e)); | 239 GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (this, key, r
esource)); |
| 212 resource->setCacheEntry(entry); | 240 resource->setCacheEntry(entry); |
| 213 | 241 |
| 214 this->attachToHead(entry); | 242 this->attachToHead(entry); |
| 215 fCache.insert(key, entry); | 243 fCache.insert(key, entry); |
| 216 | 244 |
| 217 if (ownershipFlags & kHide_OwnershipFlag) { | 245 if (ownershipFlags & kHide_OwnershipFlag) { |
| 218 this->makeExclusive(entry); | 246 this->makeExclusive(entry); |
| 219 } | 247 } |
| 220 | 248 |
| 221 } | 249 } |
| 222 | 250 |
| 223 void GrResourceCache::makeExclusive(GrResourceCacheEntry* entry) { | 251 void GrResourceCache::makeExclusive(GrResourceCacheEntry* entry) { |
| 224 GrAutoResourceCacheValidate atcv(this); | 252 GrAutoResourceCacheValidate atcv(this); |
| 225 | 253 |
| 254 SkASSERT(!entry->fIsExclusive); |
| 255 entry->fIsExclusive = true; |
| 256 |
| 226 // When scratch textures are detached (to hide them from future finds) they | 257 // When scratch textures are detached (to hide them from future finds) they |
| 227 // still count against the resource budget | 258 // still count against the resource budget |
| 228 this->internalDetach(entry, kIgnore_BudgetBehavior); | 259 this->internalDetach(entry, kIgnore_BudgetBehavior); |
| 229 fCache.remove(entry->key(), entry); | 260 fCache.remove(entry->key(), entry); |
| 230 | 261 |
| 231 #ifdef SK_DEBUG | 262 #ifdef SK_DEBUG |
| 232 fExclusiveList.addToHead(entry); | 263 fExclusiveList.addToHead(entry); |
| 233 #endif | 264 #endif |
| 234 } | 265 } |
| 235 | 266 |
| 236 void GrResourceCache::removeInvalidResource(GrResourceCacheEntry* entry) { | 267 void GrResourceCache::removeInvalidResource(GrResourceCacheEntry* entry) { |
| 237 // If the resource went invalid while it was detached then purge it | 268 // If the resource went invalid while it was detached then purge it |
| 238 // This can happen when a 3D context was lost, | 269 // This can happen when a 3D context was lost, |
| 239 // the client called GrContext::contextDestroyed() to notify Gr, | 270 // the client called GrContext::contextDestroyed() to notify Gr, |
| 240 // and then later an SkGpuDevice's destructor releases its backing | 271 // and then later an SkGpuDevice's destructor releases its backing |
| 241 // texture (which was invalidated at contextDestroyed time). | 272 // texture (which was invalidated at contextDestroyed time). |
| 273 // TODO: Safely delete the GrResourceCacheEntry as well. |
| 242 fClientDetachedCount -= 1; | 274 fClientDetachedCount -= 1; |
| 243 fEntryCount -= 1; | 275 fEntryCount -= 1; |
| 244 size_t size = entry->resource()->gpuMemorySize(); | 276 fClientDetachedBytes -= entry->fCachedSize; |
| 245 fClientDetachedBytes -= size; | 277 fEntryBytes -= entry->fCachedSize; |
| 246 fEntryBytes -= size; | 278 entry->fCachedSize = 0; |
| 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::didIncreaseResourceSize(const GrResourceCacheEntry* entry,
size_t amountInc) { |
| 303 fEntryBytes += amountInc; |
| 304 if (entry->fIsExclusive) { |
| 305 fClientDetachedBytes += amountInc; |
| 306 } |
| 307 this->purgeAsNeeded(); |
| 308 } |
| 309 |
| 310 void GrResourceCache::didDecreaseResourceSize(const GrResourceCacheEntry* entry,
size_t amountDec) { |
| 311 fEntryBytes -= amountDec; |
| 312 if (entry->fIsExclusive) { |
| 313 fClientDetachedBytes -= amountDec; |
| 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 |