| 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 "GrGpuResource.h" | 12 #include "GrGpuResource.h" |
| 13 #include "GrTexturePriv.h" |
| 14 |
| 13 | 15 |
| 14 DECLARE_SKMESSAGEBUS_MESSAGE(GrResourceInvalidatedMessage); | 16 DECLARE_SKMESSAGEBUS_MESSAGE(GrResourceInvalidatedMessage); |
| 15 | 17 |
| 16 /////////////////////////////////////////////////////////////////////////////// | 18 /////////////////////////////////////////////////////////////////////////////// |
| 17 | 19 |
| 18 void GrGpuResource::didChangeGpuMemorySize() const { | 20 void GrGpuResource::didChangeGpuMemorySize() const { |
| 19 if (this->isInCache()) { | 21 if (this->isInCache()) { |
| 20 fCacheEntry->didChangeResourceSize(); | 22 fCacheEntry->didChangeResourceSize(); |
| 21 } | 23 } |
| 22 } | 24 } |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 69 fCachedSize = fResource->gpuMemorySize(); | 71 fCachedSize = fResource->gpuMemorySize(); |
| 70 if (fCachedSize > oldSize) { | 72 if (fCachedSize > oldSize) { |
| 71 fResourceCache->didIncreaseResourceSize(this, fCachedSize - oldSize); | 73 fResourceCache->didIncreaseResourceSize(this, fCachedSize - oldSize); |
| 72 } else if (fCachedSize < oldSize) { | 74 } else if (fCachedSize < oldSize) { |
| 73 fResourceCache->didDecreaseResourceSize(this, oldSize - fCachedSize); | 75 fResourceCache->didDecreaseResourceSize(this, oldSize - fCachedSize); |
| 74 } | 76 } |
| 75 } | 77 } |
| 76 | 78 |
| 77 /////////////////////////////////////////////////////////////////////////////// | 79 /////////////////////////////////////////////////////////////////////////////// |
| 78 | 80 |
| 79 GrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) : | 81 GrResourceCache::GrResourceCache(const GrDrawTargetCaps* caps, int maxCount, siz
e_t maxBytes) |
| 80 fMaxCount(maxCount), | 82 : fMaxCount(maxCount) |
| 81 fMaxBytes(maxBytes) { | 83 , fMaxBytes(maxBytes) |
| 84 , fCaps(SkRef(caps)) { |
| 82 #if GR_CACHE_STATS | 85 #if GR_CACHE_STATS |
| 83 fHighWaterEntryCount = 0; | 86 fHighWaterEntryCount = 0; |
| 84 fHighWaterEntryBytes = 0; | 87 fHighWaterEntryBytes = 0; |
| 85 fHighWaterClientDetachedCount = 0; | |
| 86 fHighWaterClientDetachedBytes = 0; | |
| 87 #endif | 88 #endif |
| 88 | 89 |
| 89 fEntryCount = 0; | 90 fEntryCount = 0; |
| 90 fEntryBytes = 0; | 91 fEntryBytes = 0; |
| 91 fClientDetachedCount = 0; | |
| 92 fClientDetachedBytes = 0; | |
| 93 | 92 |
| 94 fPurging = false; | 93 fPurging = false; |
| 95 | 94 |
| 96 fOverbudgetCB = NULL; | 95 fOverbudgetCB = NULL; |
| 97 fOverbudgetData = NULL; | 96 fOverbudgetData = NULL; |
| 98 } | 97 } |
| 99 | 98 |
| 100 GrResourceCache::~GrResourceCache() { | 99 GrResourceCache::~GrResourceCache() { |
| 101 GrAutoResourceCacheValidate atcv(this); | 100 GrAutoResourceCacheValidate atcv(this); |
| 102 | 101 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 129 bool smaller = (maxResources < fMaxCount) || (maxResourceBytes < fMaxBytes); | 128 bool smaller = (maxResources < fMaxCount) || (maxResourceBytes < fMaxBytes); |
| 130 | 129 |
| 131 fMaxCount = maxResources; | 130 fMaxCount = maxResources; |
| 132 fMaxBytes = maxResourceBytes; | 131 fMaxBytes = maxResourceBytes; |
| 133 | 132 |
| 134 if (smaller) { | 133 if (smaller) { |
| 135 this->purgeAsNeeded(); | 134 this->purgeAsNeeded(); |
| 136 } | 135 } |
| 137 } | 136 } |
| 138 | 137 |
| 139 void GrResourceCache::internalDetach(GrResourceCacheEntry* entry, | 138 void GrResourceCache::internalDetach(GrResourceCacheEntry* entry) { |
| 140 BudgetBehaviors behavior) { | |
| 141 fList.remove(entry); | 139 fList.remove(entry); |
| 140 fEntryCount -= 1; |
| 141 fEntryBytes -= entry->fCachedSize; |
| 142 } |
| 142 | 143 |
| 143 // update our stats | 144 void GrResourceCache::attachToHead(GrResourceCacheEntry* entry) { |
| 144 if (kIgnore_BudgetBehavior == behavior) { | 145 fList.addToHead(entry); |
| 145 fClientDetachedCount += 1; | 146 |
| 146 fClientDetachedBytes += entry->fCachedSize; | 147 fEntryCount += 1; |
| 148 fEntryBytes += entry->fCachedSize; |
| 147 | 149 |
| 148 #if GR_CACHE_STATS | 150 #if GR_CACHE_STATS |
| 149 if (fHighWaterClientDetachedCount < fClientDetachedCount) { | 151 if (fHighWaterEntryCount < fEntryCount) { |
| 150 fHighWaterClientDetachedCount = fClientDetachedCount; | 152 fHighWaterEntryCount = fEntryCount; |
| 151 } | 153 } |
| 152 if (fHighWaterClientDetachedBytes < fClientDetachedBytes) { | 154 if (fHighWaterEntryBytes < fEntryBytes) { |
| 153 fHighWaterClientDetachedBytes = fClientDetachedBytes; | 155 fHighWaterEntryBytes = fEntryBytes; |
| 154 } | 156 } |
| 155 #endif | 157 #endif |
| 156 | |
| 157 } else { | |
| 158 SkASSERT(kAccountFor_BudgetBehavior == behavior); | |
| 159 | |
| 160 fEntryCount -= 1; | |
| 161 fEntryBytes -= entry->fCachedSize; | |
| 162 } | |
| 163 } | |
| 164 | |
| 165 void GrResourceCache::attachToHead(GrResourceCacheEntry* entry, | |
| 166 BudgetBehaviors behavior) { | |
| 167 fList.addToHead(entry); | |
| 168 | |
| 169 // update our stats | |
| 170 if (kIgnore_BudgetBehavior == behavior) { | |
| 171 fClientDetachedCount -= 1; | |
| 172 fClientDetachedBytes -= entry->fCachedSize; | |
| 173 } else { | |
| 174 SkASSERT(kAccountFor_BudgetBehavior == behavior); | |
| 175 | |
| 176 fEntryCount += 1; | |
| 177 fEntryBytes += entry->fCachedSize; | |
| 178 | |
| 179 #if GR_CACHE_STATS | |
| 180 if (fHighWaterEntryCount < fEntryCount) { | |
| 181 fHighWaterEntryCount = fEntryCount; | |
| 182 } | |
| 183 if (fHighWaterEntryBytes < fEntryBytes) { | |
| 184 fHighWaterEntryBytes = fEntryBytes; | |
| 185 } | |
| 186 #endif | |
| 187 } | |
| 188 } | 158 } |
| 189 | 159 |
| 190 // This functor just searches for an entry with only a single ref (from | 160 // This functor just searches for an entry with only a single ref (from |
| 191 // the texture cache itself). Presumably in this situation no one else | 161 // the texture cache itself). Presumably in this situation no one else |
| 192 // is relying on the texture. | 162 // is relying on the texture. |
| 193 class GrTFindUnreffedFunctor { | 163 class GrTFindUnreffedFunctor { |
| 194 public: | 164 public: |
| 195 bool operator()(const GrResourceCacheEntry* entry) const { | 165 bool operator()(const GrResourceCacheEntry* entry) const { |
| 196 return entry->resource()->unique(); | 166 return entry->resource()->isPurgable(); |
| 197 } | 167 } |
| 198 }; | 168 }; |
| 199 | 169 |
| 200 GrGpuResource* GrResourceCache::find(const GrResourceKey& key, uint32_t ownershi
pFlags) { | 170 |
| 171 void GrResourceCache::makeResourceMRU(GrGpuResource* resource) { |
| 172 GrResourceCacheEntry* entry = resource->getCacheEntry(); |
| 173 if (entry) { |
| 174 this->internalDetach(entry); |
| 175 this->attachToHead(entry); |
| 176 } |
| 177 } |
| 178 |
| 179 void GrResourceCache::notifyPurgable(const GrGpuResource* resource) { |
| 180 // Remove scratch textures from the cache the moment they become purgeable i
f |
| 181 // scratch texture reuse is turned off. |
| 182 SkASSERT(resource->getCacheEntry()); |
| 183 if (resource->getCacheEntry()->key().getResourceType() == GrTexturePriv::Res
ourceType() && |
| 184 resource->fIsScratch && |
| 185 !fCaps->reuseScratchTextures() && |
| 186 !(static_cast<const GrTexture*>(resource)->desc().fFlags & |
| 187 kRenderTarget_GrTextureFlagBit)) { |
| 188 this->deleteResource(resource->getCacheEntry()); |
| 189 } |
| 190 } |
| 191 |
| 192 GrGpuResource* GrResourceCache::find(const GrResourceKey& key) { |
| 201 GrAutoResourceCacheValidate atcv(this); | 193 GrAutoResourceCacheValidate atcv(this); |
| 202 | 194 |
| 203 GrResourceCacheEntry* entry = NULL; | 195 GrResourceCacheEntry* entry = NULL; |
| 204 | 196 |
| 205 if (ownershipFlags & kNoOtherOwners_OwnershipFlag) { | 197 entry = fCache.find(key); |
| 206 GrTFindUnreffedFunctor functor; | |
| 207 | |
| 208 entry = fCache.find<GrTFindUnreffedFunctor>(key, functor); | |
| 209 } else { | |
| 210 entry = fCache.find(key); | |
| 211 } | |
| 212 | 198 |
| 213 if (NULL == entry) { | 199 if (NULL == entry) { |
| 214 return NULL; | 200 return NULL; |
| 215 } | 201 } |
| 216 | 202 |
| 217 if (ownershipFlags & kHide_OwnershipFlag) { | 203 // Make this resource MRU |
| 218 this->makeExclusive(entry); | 204 this->internalDetach(entry); |
| 219 } else { | 205 this->attachToHead(entry); |
| 220 // Make this resource MRU | |
| 221 this->internalDetach(entry); | |
| 222 this->attachToHead(entry); | |
| 223 } | |
| 224 | 206 |
| 207 // GrResourceCache2 is responsible for scratch resources. |
| 208 SkASSERT(GrGpuResource::kNo_IsScratch == entry->resource()->fIsScratch); |
| 225 return entry->fResource; | 209 return entry->fResource; |
| 226 } | 210 } |
| 227 | 211 |
| 228 void GrResourceCache::addResource(const GrResourceKey& key, | 212 void GrResourceCache::addResource(const GrResourceKey& key, GrGpuResource* resou
rce) { |
| 229 GrGpuResource* resource, | |
| 230 uint32_t ownershipFlags) { | |
| 231 SkASSERT(NULL == resource->getCacheEntry()); | 213 SkASSERT(NULL == resource->getCacheEntry()); |
| 232 // we don't expect to create new resources during a purge. In theory | 214 // we don't expect to create new resources during a purge. In theory |
| 233 // this could cause purgeAsNeeded() into an infinite loop (e.g. | 215 // this could cause purgeAsNeeded() into an infinite loop (e.g. |
| 234 // each resource destroyed creates and locks 2 resources and | 216 // each resource destroyed creates and locks 2 resources and |
| 235 // unlocks 1 thereby causing a new purge). | 217 // unlocks 1 thereby causing a new purge). |
| 236 SkASSERT(!fPurging); | 218 SkASSERT(!fPurging); |
| 237 GrAutoResourceCacheValidate atcv(this); | 219 GrAutoResourceCacheValidate atcv(this); |
| 238 | 220 |
| 239 GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (this, key, r
esource)); | 221 GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (this, key, r
esource)); |
| 240 resource->setCacheEntry(entry); | 222 resource->setCacheEntry(entry); |
| 241 | 223 |
| 242 this->attachToHead(entry); | 224 this->attachToHead(entry); |
| 243 fCache.insert(key, entry); | 225 fCache.insert(key, entry); |
| 244 | 226 |
| 245 if (ownershipFlags & kHide_OwnershipFlag) { | 227 this->purgeAsNeeded(); |
| 246 this->makeExclusive(entry); | |
| 247 } | |
| 248 | |
| 249 } | |
| 250 | |
| 251 void GrResourceCache::makeExclusive(GrResourceCacheEntry* entry) { | |
| 252 GrAutoResourceCacheValidate atcv(this); | |
| 253 | |
| 254 SkASSERT(!entry->fIsExclusive); | |
| 255 entry->fIsExclusive = true; | |
| 256 | |
| 257 // When scratch textures are detached (to hide them from future finds) they | |
| 258 // still count against the resource budget | |
| 259 this->internalDetach(entry, kIgnore_BudgetBehavior); | |
| 260 fCache.remove(entry->key(), entry); | |
| 261 | |
| 262 #ifdef SK_DEBUG | |
| 263 fExclusiveList.addToHead(entry); | |
| 264 #endif | |
| 265 } | |
| 266 | |
| 267 void GrResourceCache::removeInvalidResource(GrResourceCacheEntry* entry) { | |
| 268 // If the resource went invalid while it was detached then purge it | |
| 269 // This can happen when a 3D context was lost, | |
| 270 // the client called GrContext::abandonContext() to notify Gr, | |
| 271 // and then later an SkGpuDevice's destructor releases its backing | |
| 272 // texture (which was invalidated at contextDestroyed time). | |
| 273 // TODO: Safely delete the GrResourceCacheEntry as well. | |
| 274 fClientDetachedCount -= 1; | |
| 275 fEntryCount -= 1; | |
| 276 fClientDetachedBytes -= entry->fCachedSize; | |
| 277 fEntryBytes -= entry->fCachedSize; | |
| 278 entry->fCachedSize = 0; | |
| 279 } | |
| 280 | |
| 281 void GrResourceCache::makeNonExclusive(GrResourceCacheEntry* entry) { | |
| 282 GrAutoResourceCacheValidate atcv(this); | |
| 283 | |
| 284 #ifdef SK_DEBUG | |
| 285 fExclusiveList.remove(entry); | |
| 286 #endif | |
| 287 | |
| 288 if (!entry->resource()->wasDestroyed()) { | |
| 289 // Since scratch textures still count against the cache budget even | |
| 290 // when they have been removed from the cache, re-adding them doesn't | |
| 291 // alter the budget information. | |
| 292 attachToHead(entry, kIgnore_BudgetBehavior); | |
| 293 fCache.insert(entry->key(), entry); | |
| 294 | |
| 295 SkASSERT(entry->fIsExclusive); | |
| 296 entry->fIsExclusive = false; | |
| 297 } else { | |
| 298 this->removeInvalidResource(entry); | |
| 299 } | |
| 300 } | 228 } |
| 301 | 229 |
| 302 void GrResourceCache::didIncreaseResourceSize(const GrResourceCacheEntry* entry,
size_t amountInc) { | 230 void GrResourceCache::didIncreaseResourceSize(const GrResourceCacheEntry* entry,
size_t amountInc) { |
| 303 fEntryBytes += amountInc; | 231 fEntryBytes += amountInc; |
| 304 if (entry->fIsExclusive) { | |
| 305 fClientDetachedBytes += amountInc; | |
| 306 } | |
| 307 this->purgeAsNeeded(); | 232 this->purgeAsNeeded(); |
| 308 } | 233 } |
| 309 | 234 |
| 310 void GrResourceCache::didDecreaseResourceSize(const GrResourceCacheEntry* entry,
size_t amountDec) { | 235 void GrResourceCache::didDecreaseResourceSize(const GrResourceCacheEntry* entry,
size_t amountDec) { |
| 311 fEntryBytes -= amountDec; | 236 fEntryBytes -= amountDec; |
| 312 if (entry->fIsExclusive) { | |
| 313 fClientDetachedBytes -= amountDec; | |
| 314 } | |
| 315 #ifdef SK_DEBUG | 237 #ifdef SK_DEBUG |
| 316 this->validate(); | 238 this->validate(); |
| 317 #endif | 239 #endif |
| 318 } | 240 } |
| 319 | 241 |
| 320 /** | 242 /** |
| 321 * Destroying a resource may potentially trigger the unlock of additional | 243 * Destroying a resource may potentially trigger the unlock of additional |
| 322 * resources which in turn will trigger a nested purge. We block the nested | 244 * resources which in turn will trigger a nested purge. We block the nested |
| 323 * purge using the fPurging variable. However, the initial purge will keep | 245 * purge using the fPurging variable. However, the initial purge will keep |
| 324 * looping until either all resources in the cache are unlocked or we've met | 246 * looping until either all resources in the cache are unlocked or we've met |
| (...skipping 27 matching lines...) Expand all Loading... |
| 352 } | 274 } |
| 353 | 275 |
| 354 fPurging = false; | 276 fPurging = false; |
| 355 } | 277 } |
| 356 | 278 |
| 357 void GrResourceCache::purgeInvalidated() { | 279 void GrResourceCache::purgeInvalidated() { |
| 358 SkTDArray<GrResourceInvalidatedMessage> invalidated; | 280 SkTDArray<GrResourceInvalidatedMessage> invalidated; |
| 359 fInvalidationInbox.poll(&invalidated); | 281 fInvalidationInbox.poll(&invalidated); |
| 360 | 282 |
| 361 for (int i = 0; i < invalidated.count(); i++) { | 283 for (int i = 0; i < invalidated.count(); i++) { |
| 362 // We're somewhat missing an opportunity here. We could use the | |
| 363 // default find functor that gives us back resources whether we own | |
| 364 // them exclusively or not, and when they're not exclusively owned mark | |
| 365 // them for purging later when they do become exclusively owned. | |
| 366 // | |
| 367 // This is complicated and confusing. May try this in the future. For | |
| 368 // now, these resources are just LRU'd as if we never got the message. | |
| 369 while (GrResourceCacheEntry* entry = fCache.find(invalidated[i].key, GrT
FindUnreffedFunctor())) { | 284 while (GrResourceCacheEntry* entry = fCache.find(invalidated[i].key, GrT
FindUnreffedFunctor())) { |
| 370 this->deleteResource(entry); | 285 this->deleteResource(entry); |
| 371 } | 286 } |
| 372 } | 287 } |
| 373 } | 288 } |
| 374 | 289 |
| 375 void GrResourceCache::deleteResource(GrResourceCacheEntry* entry) { | 290 void GrResourceCache::deleteResource(GrResourceCacheEntry* entry) { |
| 376 SkASSERT(entry->fResource->unique()); | 291 SkASSERT(entry->fResource->isPurgable()); |
| 377 | 292 |
| 378 // remove from our cache | 293 // remove from our cache |
| 379 fCache.remove(entry->key(), entry); | 294 fCache.remove(entry->key(), entry); |
| 380 | 295 |
| 381 // remove from our llist | 296 // remove from our llist |
| 382 this->internalDetach(entry); | 297 this->internalDetach(entry); |
| 383 delete entry; | 298 delete entry; |
| 384 } | 299 } |
| 385 | 300 |
| 386 void GrResourceCache::internalPurge(int extraCount, size_t extraBytes) { | 301 void GrResourceCache::internalPurge(int extraCount, size_t extraBytes) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 405 while (entry) { | 320 while (entry) { |
| 406 GrAutoResourceCacheValidate atcv(this); | 321 GrAutoResourceCacheValidate atcv(this); |
| 407 | 322 |
| 408 if ((fEntryCount+extraCount) <= fMaxCount && | 323 if ((fEntryCount+extraCount) <= fMaxCount && |
| 409 (fEntryBytes+extraBytes) <= fMaxBytes) { | 324 (fEntryBytes+extraBytes) <= fMaxBytes) { |
| 410 withinBudget = true; | 325 withinBudget = true; |
| 411 break; | 326 break; |
| 412 } | 327 } |
| 413 | 328 |
| 414 GrResourceCacheEntry* prev = iter.prev(); | 329 GrResourceCacheEntry* prev = iter.prev(); |
| 415 if (entry->fResource->unique()) { | 330 if (entry->fResource->isPurgable()) { |
| 416 changed = true; | 331 changed = true; |
| 417 this->deleteResource(entry); | 332 this->deleteResource(entry); |
| 418 } | 333 } |
| 419 entry = prev; | 334 entry = prev; |
| 420 } | 335 } |
| 421 } while (!withinBudget && changed); | 336 } while (!withinBudget && changed); |
| 422 } | 337 } |
| 423 | 338 |
| 424 void GrResourceCache::purgeAllUnlocked() { | 339 void GrResourceCache::purgeAllUnlocked() { |
| 425 GrAutoResourceCacheValidate atcv(this); | 340 GrAutoResourceCacheValidate atcv(this); |
| 426 | 341 |
| 427 // we can have one GrCacheable holding a lock on another | 342 // we can have one GrCacheable holding a lock on another |
| 428 // so we don't want to just do a simple loop kicking each | 343 // so we don't want to just do a simple loop kicking each |
| 429 // entry out. Instead change the budget and purge. | 344 // entry out. Instead change the budget and purge. |
| 430 | 345 |
| 431 size_t savedMaxBytes = fMaxBytes; | 346 size_t savedMaxBytes = fMaxBytes; |
| 432 int savedMaxCount = fMaxCount; | 347 int savedMaxCount = fMaxCount; |
| 433 fMaxBytes = (size_t) -1; | 348 fMaxBytes = (size_t) -1; |
| 434 fMaxCount = 0; | 349 fMaxCount = 0; |
| 435 this->purgeAsNeeded(); | 350 this->purgeAsNeeded(); |
| 436 | 351 |
| 437 #ifdef SK_DEBUG | 352 #ifdef SK_DEBUG |
| 438 SkASSERT(fExclusiveList.countEntries() == fClientDetachedCount); | |
| 439 SkASSERT(countBytes(fExclusiveList) == fClientDetachedBytes); | |
| 440 if (!fCache.count()) { | 353 if (!fCache.count()) { |
| 441 // Items may have been detached from the cache (such as the backing | |
| 442 // texture for an SkGpuDevice). The above purge would not have removed | |
| 443 // them. | |
| 444 SkASSERT(fEntryCount == fClientDetachedCount); | |
| 445 SkASSERT(fEntryBytes == fClientDetachedBytes); | |
| 446 SkASSERT(fList.isEmpty()); | 354 SkASSERT(fList.isEmpty()); |
| 447 } | 355 } |
| 448 #endif | 356 #endif |
| 449 | 357 |
| 450 fMaxBytes = savedMaxBytes; | 358 fMaxBytes = savedMaxBytes; |
| 451 fMaxCount = savedMaxCount; | 359 fMaxCount = savedMaxCount; |
| 452 } | 360 } |
| 453 | 361 |
| 454 /////////////////////////////////////////////////////////////////////////////// | 362 /////////////////////////////////////////////////////////////////////////////// |
| 455 | 363 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 467 } | 375 } |
| 468 return bytes; | 376 return bytes; |
| 469 } | 377 } |
| 470 | 378 |
| 471 static bool both_zero_or_nonzero(int count, size_t bytes) { | 379 static bool both_zero_or_nonzero(int count, size_t bytes) { |
| 472 return (count == 0 && bytes == 0) || (count > 0 && bytes > 0); | 380 return (count == 0 && bytes == 0) || (count > 0 && bytes > 0); |
| 473 } | 381 } |
| 474 | 382 |
| 475 void GrResourceCache::validate() const { | 383 void GrResourceCache::validate() const { |
| 476 fList.validate(); | 384 fList.validate(); |
| 477 fExclusiveList.validate(); | |
| 478 SkASSERT(both_zero_or_nonzero(fEntryCount, fEntryBytes)); | 385 SkASSERT(both_zero_or_nonzero(fEntryCount, fEntryBytes)); |
| 479 SkASSERT(both_zero_or_nonzero(fClientDetachedCount, fClientDetachedBytes)); | 386 SkASSERT(fEntryCount == fCache.count()); |
| 480 SkASSERT(fClientDetachedBytes <= fEntryBytes); | |
| 481 SkASSERT(fClientDetachedCount <= fEntryCount); | |
| 482 SkASSERT((fEntryCount - fClientDetachedCount) == fCache.count()); | |
| 483 | 387 |
| 484 EntryList::Iter iter; | 388 EntryList::Iter iter; |
| 485 | 389 |
| 486 // check that the exclusively held entries are okay | 390 // check that the shareable entries are okay |
| 487 const GrResourceCacheEntry* entry = iter.init(const_cast<EntryList&>(fExclus
iveList), | 391 const GrResourceCacheEntry* entry = iter.init(const_cast<EntryList&>(fList), |
| 488 EntryList::Iter::kHead_IterSta
rt); | 392 EntryList::Iter::kHead_IterSta
rt); |
| 489 | 393 |
| 490 for ( ; entry; entry = iter.next()) { | |
| 491 entry->validate(); | |
| 492 } | |
| 493 | |
| 494 // check that the shareable entries are okay | |
| 495 entry = iter.init(const_cast<EntryList&>(fList), EntryList::Iter::kHead_Iter
Start); | |
| 496 | |
| 497 int count = 0; | 394 int count = 0; |
| 498 for ( ; entry; entry = iter.next()) { | 395 for ( ; entry; entry = iter.next()) { |
| 499 entry->validate(); | 396 entry->validate(); |
| 500 SkASSERT(fCache.find(entry->key())); | 397 SkASSERT(fCache.find(entry->key())); |
| 501 count += 1; | 398 count += 1; |
| 502 } | 399 } |
| 503 SkASSERT(count == fEntryCount - fClientDetachedCount); | 400 SkASSERT(count == fEntryCount); |
| 504 | 401 |
| 505 size_t bytes = countBytes(fList); | 402 size_t bytes = this->countBytes(fList); |
| 506 SkASSERT(bytes == fEntryBytes - fClientDetachedBytes); | 403 SkASSERT(bytes == fEntryBytes); |
| 507 | 404 SkASSERT(fList.countEntries() == fEntryCount); |
| 508 bytes = countBytes(fExclusiveList); | |
| 509 SkASSERT(bytes == fClientDetachedBytes); | |
| 510 | |
| 511 SkASSERT(fList.countEntries() == fEntryCount - fClientDetachedCount); | |
| 512 | |
| 513 SkASSERT(fExclusiveList.countEntries() == fClientDetachedCount); | |
| 514 } | 405 } |
| 515 #endif // SK_DEBUG | 406 #endif // SK_DEBUG |
| 516 | 407 |
| 517 #if GR_CACHE_STATS | 408 #if GR_CACHE_STATS |
| 518 | 409 |
| 519 void GrResourceCache::printStats() { | 410 void GrResourceCache::printStats() { |
| 520 int locked = 0; | 411 int locked = 0; |
| 521 | 412 |
| 522 EntryList::Iter iter; | 413 EntryList::Iter iter; |
| 523 | 414 |
| 524 GrResourceCacheEntry* entry = iter.init(fList, EntryList::Iter::kTail_IterSt
art); | 415 GrResourceCacheEntry* entry = iter.init(fList, EntryList::Iter::kTail_IterSt
art); |
| 525 | 416 |
| 526 for ( ; entry; entry = iter.prev()) { | 417 for ( ; entry; entry = iter.prev()) { |
| 527 if (entry->fResource->getRefCnt() > 1) { | 418 if (entry->fResource->getRefCnt() > 1) { |
| 528 ++locked; | 419 ++locked; |
| 529 } | 420 } |
| 530 } | 421 } |
| 531 | 422 |
| 532 SkDebugf("Budget: %d items %d bytes\n", fMaxCount, fMaxBytes); | 423 SkDebugf("Budget: %d items %d bytes\n", fMaxCount, fMaxBytes); |
| 533 SkDebugf("\t\tEntry Count: current %d (%d locked) high %d\n", | 424 SkDebugf("\t\tEntry Count: current %d (%d locked) high %d\n", |
| 534 fEntryCount, locked, fHighWaterEntryCount); | 425 fEntryCount, locked, fHighWaterEntryCount); |
| 535 SkDebugf("\t\tEntry Bytes: current %d high %d\n", | 426 SkDebugf("\t\tEntry Bytes: current %d high %d\n", |
| 536 fEntryBytes, fHighWaterEntryBytes); | 427 fEntryBytes, fHighWaterEntryBytes); |
| 537 SkDebugf("\t\tDetached Entry Count: current %d high %d\n", | |
| 538 fClientDetachedCount, fHighWaterClientDetachedCount); | |
| 539 SkDebugf("\t\tDetached Bytes: current %d high %d\n", | |
| 540 fClientDetachedBytes, fHighWaterClientDetachedBytes); | |
| 541 } | 428 } |
| 542 | 429 |
| 543 #endif | 430 #endif |
| 544 | 431 |
| 545 /////////////////////////////////////////////////////////////////////////////// | 432 /////////////////////////////////////////////////////////////////////////////// |
| OLD | NEW |