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 #include "GrResourceCache.h" | 9 #include "GrResourceCache.h" |
| 10 #include "GrGpuResource.h" | 10 #include "GrGpuResource.h" |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 28 int32_t type = sk_atomic_inc(&gNextType); | 28 int32_t type = sk_atomic_inc(&gNextType); |
| 29 if (type >= (1 << 8 * sizeof(ResourceType))) { | 29 if (type >= (1 << 8 * sizeof(ResourceType))) { |
| 30 SkFAIL("Too many Resource Types"); | 30 SkFAIL("Too many Resource Types"); |
| 31 } | 31 } |
| 32 | 32 |
| 33 return static_cast<ResourceType>(type); | 33 return static_cast<ResourceType>(type); |
| 34 } | 34 } |
| 35 | 35 |
| 36 /////////////////////////////////////////////////////////////////////////////// | 36 /////////////////////////////////////////////////////////////////////////////// |
| 37 | 37 |
| 38 GrResourceCacheEntry::GrResourceCacheEntry(GrResourceCache* resourceCache, | 38 GrResourceCacheEntry::GrResourceCacheEntry(GrResourceCache* resourceCache, GrGpu Resource* resource) |
| 39 const GrResourceKey& key, | |
| 40 GrGpuResource* resource) | |
| 41 : fResourceCache(resourceCache), | 39 : fResourceCache(resourceCache), |
| 42 fKey(key), | |
| 43 fResource(resource), | 40 fResource(resource), |
| 44 fCachedSize(resource->gpuMemorySize()), | 41 fCachedSize(resource->gpuMemorySize()) { |
| 45 fIsExclusive(false) { | |
| 46 // we assume ownership of the resource, and will unref it when we die | 42 // we assume ownership of the resource, and will unref it when we die |
| 47 SkASSERT(resource); | 43 SkASSERT(resource); |
| 48 resource->ref(); | 44 resource->ref(); |
| 49 } | 45 } |
| 50 | 46 |
| 51 GrResourceCacheEntry::~GrResourceCacheEntry() { | 47 GrResourceCacheEntry::~GrResourceCacheEntry() { |
| 52 // We're relying on having the cache entry to remove this from GrResourceCac he2's content hash. | 48 // We're relying on having the cache entry to remove this from GrResourceCac he2's content hash. |
| 53 // fResource->setCacheEntry(NULL); | 49 // fResource->setCacheEntry(NULL); |
| 54 fResource->unref(); | 50 fResource->unref(); |
| 55 } | 51 } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 96 | 92 |
| 97 GrResourceCache::~GrResourceCache() { | 93 GrResourceCache::~GrResourceCache() { |
| 98 GrAutoResourceCacheValidate atcv(this); | 94 GrAutoResourceCacheValidate atcv(this); |
| 99 | 95 |
| 100 EntryList::Iter iter; | 96 EntryList::Iter iter; |
| 101 | 97 |
| 102 // Unlike the removeAll, here we really remove everything, including locked resources. | 98 // Unlike the removeAll, here we really remove everything, including locked resources. |
| 103 while (GrResourceCacheEntry* entry = fList.head()) { | 99 while (GrResourceCacheEntry* entry = fList.head()) { |
| 104 GrAutoResourceCacheValidate atcv(this); | 100 GrAutoResourceCacheValidate atcv(this); |
| 105 | 101 |
| 106 // remove from our cache | |
| 107 fCache.remove(entry->fKey, entry); | |
| 108 | |
| 109 // remove from our llist | 102 // remove from our llist |
| 110 this->internalDetach(entry); | 103 this->internalDetach(entry); |
| 111 | 104 |
| 112 delete entry; | 105 delete entry; |
| 113 } | 106 } |
| 114 } | 107 } |
| 115 | 108 |
| 116 void GrResourceCache::getLimits(int* maxResources, size_t* maxResourceBytes) con st{ | 109 void GrResourceCache::getLimits(int* maxResources, size_t* maxResourceBytes) con st{ |
| 117 if (maxResources) { | 110 if (maxResources) { |
| 118 *maxResources = fMaxCount; | 111 *maxResources = fMaxCount; |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 148 #if GR_CACHE_STATS | 141 #if GR_CACHE_STATS |
| 149 if (fHighWaterEntryCount < fEntryCount) { | 142 if (fHighWaterEntryCount < fEntryCount) { |
| 150 fHighWaterEntryCount = fEntryCount; | 143 fHighWaterEntryCount = fEntryCount; |
| 151 } | 144 } |
| 152 if (fHighWaterEntryBytes < fEntryBytes) { | 145 if (fHighWaterEntryBytes < fEntryBytes) { |
| 153 fHighWaterEntryBytes = fEntryBytes; | 146 fHighWaterEntryBytes = fEntryBytes; |
| 154 } | 147 } |
| 155 #endif | 148 #endif |
| 156 } | 149 } |
| 157 | 150 |
| 158 // This functor just searches for an entry with only a single ref (from | |
| 159 // the texture cache itself). Presumably in this situation no one else | |
| 160 // is relying on the texture. | |
| 161 class GrTFindUnreffedFunctor { | |
| 162 public: | |
| 163 bool operator()(const GrResourceCacheEntry* entry) const { | |
| 164 return entry->resource()->isPurgable(); | |
| 165 } | |
| 166 }; | |
| 167 | |
| 168 | 151 |
| 169 void GrResourceCache::makeResourceMRU(GrGpuResource* resource) { | 152 void GrResourceCache::makeResourceMRU(GrGpuResource* resource) { |
| 170 GrResourceCacheEntry* entry = resource->getCacheEntry(); | 153 GrResourceCacheEntry* entry = resource->getCacheEntry(); |
| 171 if (entry) { | 154 if (entry) { |
| 172 this->internalDetach(entry); | 155 this->internalDetach(entry); |
| 173 this->attachToHead(entry); | 156 this->attachToHead(entry); |
| 174 } | 157 } |
| 175 } | 158 } |
| 176 | 159 |
| 177 void GrResourceCache::notifyPurgable(const GrGpuResource* resource) { | 160 void GrResourceCache::notifyPurgable(const GrGpuResource* resource) { |
| 178 // Remove scratch textures from the cache the moment they become purgeable i f | 161 // Remove scratch textures from the cache the moment they become purgeable i f |
| 179 // scratch texture reuse is turned off. | 162 // scratch texture reuse is turned off. |
| 180 SkASSERT(resource->getCacheEntry()); | 163 SkASSERT(resource->getCacheEntry()); |
| 181 if (resource->getCacheEntry()->key().getResourceType() == GrTexturePriv::Res ourceType() && | 164 if (resource->isScratch()) { |
| 182 resource->getCacheEntry()->key().isScratch() && | 165 const GrResourceKey& key = resource->getScratchKey(); |
| 183 !fCaps->reuseScratchTextures() && | 166 if (key.getResourceType() == GrTexturePriv::ResourceType() && |
| 184 !(static_cast<const GrSurface*>(resource)->desc().fFlags & kRenderTarget _GrSurfaceFlag)) { | 167 !fCaps->reuseScratchTextures() && |
| 185 this->deleteResource(resource->getCacheEntry()); | 168 !(static_cast<const GrSurface*>(resource)->desc().fFlags & kRenderTa rget_GrSurfaceFlag)) { |
| 169 this->deleteResource(resource->getCacheEntry()); | |
| 170 } | |
| 186 } | 171 } |
| 187 } | 172 } |
| 188 | 173 |
| 189 bool GrResourceCache::addResource(const GrResourceKey& key, GrGpuResource* resou rce) { | 174 bool GrResourceCache::addResource(const GrResourceKey& key, GrGpuResource* resou rce) { |
| 190 if (NULL != resource->getCacheEntry()) { | 175 if (NULL != resource->getCacheEntry()) { |
| 191 return false; | 176 return false; |
| 192 } | 177 } |
| 178 | |
| 179 if (key.isScratch()) { | |
| 180 SkASSERT(resource->isScratch() && key == resource->getScratchKey()); | |
| 181 } else { | |
| 182 if (!resource->setContentKey(key)) { | |
| 183 return false; | |
| 184 } | |
| 185 } | |
| 193 | 186 |
| 194 // we don't expect to create new resources during a purge. In theory | 187 // we don't expect to create new resources during a purge. In theory |
| 195 // this could cause purgeAsNeeded() into an infinite loop (e.g. | 188 // this could cause purgeAsNeeded() into an infinite loop (e.g. |
| 196 // each resource destroyed creates and locks 2 resources and | 189 // each resource destroyed creates and locks 2 resources and |
| 197 // unlocks 1 thereby causing a new purge). | 190 // unlocks 1 thereby causing a new purge). |
| 198 SkASSERT(!fPurging); | 191 SkASSERT(!fPurging); |
| 199 GrAutoResourceCacheValidate atcv(this); | 192 GrAutoResourceCacheValidate atcv(this); |
| 200 | 193 |
| 201 GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (this, key, r esource)); | 194 GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (this, resour ce)); |
| 202 if (!resource->setCacheEntry(entry)) { | 195 resource->setCacheEntry(entry); |
| 203 SkDELETE(entry); | |
| 204 this->purgeAsNeeded(); | |
| 205 return false; | |
| 206 } | |
| 207 | 196 |
| 208 this->attachToHead(entry); | 197 this->attachToHead(entry); |
| 209 fCache.insert(key, entry); | |
| 210 this->purgeAsNeeded(); | 198 this->purgeAsNeeded(); |
| 211 return true; | 199 return true; |
| 212 } | 200 } |
| 213 | 201 |
| 214 void GrResourceCache::didIncreaseResourceSize(const GrResourceCacheEntry* entry, size_t amountInc) { | 202 void GrResourceCache::didIncreaseResourceSize(const GrResourceCacheEntry* entry, size_t amountInc) { |
| 215 fEntryBytes += amountInc; | 203 fEntryBytes += amountInc; |
| 216 this->purgeAsNeeded(); | 204 this->purgeAsNeeded(); |
| 217 } | 205 } |
| 218 | 206 |
| 219 void GrResourceCache::didDecreaseResourceSize(const GrResourceCacheEntry* entry, size_t amountDec) { | 207 void GrResourceCache::didDecreaseResourceSize(const GrResourceCacheEntry* entry, size_t amountDec) { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 237 * for incoming resources (e.g., GrContext is about to add 10MB split between | 225 * for incoming resources (e.g., GrContext is about to add 10MB split between |
| 238 * 10 textures). | 226 * 10 textures). |
| 239 */ | 227 */ |
| 240 void GrResourceCache::purgeAsNeeded(int extraCount, size_t extraBytes) { | 228 void GrResourceCache::purgeAsNeeded(int extraCount, size_t extraBytes) { |
| 241 if (fPurging) { | 229 if (fPurging) { |
| 242 return; | 230 return; |
| 243 } | 231 } |
| 244 | 232 |
| 245 fPurging = true; | 233 fPurging = true; |
| 246 | 234 |
| 247 this->purgeInvalidated(); | |
| 248 | |
| 249 this->internalPurge(extraCount, extraBytes); | 235 this->internalPurge(extraCount, extraBytes); |
| 250 if (((fEntryCount+extraCount) > fMaxCount || | 236 if (((fEntryCount+extraCount) > fMaxCount || |
| 251 (fEntryBytes+extraBytes) > fMaxBytes) && | 237 (fEntryBytes+extraBytes) > fMaxBytes) && |
| 252 fOverbudgetCB) { | 238 fOverbudgetCB) { |
| 253 // Despite the purge we're still over budget. See if Ganesh can | 239 // Despite the purge we're still over budget. See if Ganesh can |
| 254 // release some resources and purge again. | 240 // release some resources and purge again. |
| 255 if ((*fOverbudgetCB)(fOverbudgetData)) { | 241 if ((*fOverbudgetCB)(fOverbudgetData)) { |
| 256 this->internalPurge(extraCount, extraBytes); | 242 this->internalPurge(extraCount, extraBytes); |
| 257 } | 243 } |
| 258 } | 244 } |
| 259 | 245 |
| 260 fPurging = false; | 246 fPurging = false; |
| 261 } | 247 } |
| 262 | 248 |
| 263 void GrResourceCache::purgeInvalidated() { | 249 void GrResourceCache::purgeInvalidated() { |
| 264 SkTDArray<GrResourceInvalidatedMessage> invalidated; | 250 // TODO: Implement this in GrResourceCache2. |
|
bsalomon
2014/11/10 18:38:51
I won't land this until there is a follow up CL re
| |
| 265 fInvalidationInbox.poll(&invalidated); | |
| 266 | |
| 267 for (int i = 0; i < invalidated.count(); i++) { | |
| 268 while (GrResourceCacheEntry* entry = fCache.find(invalidated[i].key, GrT FindUnreffedFunctor())) { | |
| 269 this->deleteResource(entry); | |
| 270 } | |
| 271 } | |
| 272 } | 251 } |
| 273 | 252 |
| 274 void GrResourceCache::deleteResource(GrResourceCacheEntry* entry) { | 253 void GrResourceCache::deleteResource(GrResourceCacheEntry* entry) { |
| 275 SkASSERT(entry->fResource->isPurgable()); | 254 SkASSERT(entry->fResource->isPurgable()); |
| 276 | |
| 277 // remove from our cache | |
| 278 fCache.remove(entry->key(), entry); | |
| 279 | |
| 280 // remove from our llist | 255 // remove from our llist |
| 281 this->internalDetach(entry); | 256 this->internalDetach(entry); |
| 282 delete entry; | 257 delete entry; |
| 283 } | 258 } |
| 284 | 259 |
| 285 void GrResourceCache::internalPurge(int extraCount, size_t extraBytes) { | 260 void GrResourceCache::internalPurge(int extraCount, size_t extraBytes) { |
| 286 SkASSERT(fPurging); | 261 SkASSERT(fPurging); |
| 287 | 262 |
| 288 bool withinBudget = false; | 263 bool withinBudget = false; |
| 289 bool changed = false; | 264 bool changed = false; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 326 // we can have one GrCacheable holding a lock on another | 301 // we can have one GrCacheable holding a lock on another |
| 327 // so we don't want to just do a simple loop kicking each | 302 // so we don't want to just do a simple loop kicking each |
| 328 // entry out. Instead change the budget and purge. | 303 // entry out. Instead change the budget and purge. |
| 329 | 304 |
| 330 size_t savedMaxBytes = fMaxBytes; | 305 size_t savedMaxBytes = fMaxBytes; |
| 331 int savedMaxCount = fMaxCount; | 306 int savedMaxCount = fMaxCount; |
| 332 fMaxBytes = (size_t) -1; | 307 fMaxBytes = (size_t) -1; |
| 333 fMaxCount = 0; | 308 fMaxCount = 0; |
| 334 this->purgeAsNeeded(); | 309 this->purgeAsNeeded(); |
| 335 | 310 |
| 336 #ifdef SK_DEBUG | |
| 337 if (!fCache.count()) { | |
| 338 SkASSERT(fList.isEmpty()); | |
| 339 } | |
| 340 #endif | |
| 341 | |
| 342 fMaxBytes = savedMaxBytes; | 311 fMaxBytes = savedMaxBytes; |
| 343 fMaxCount = savedMaxCount; | 312 fMaxCount = savedMaxCount; |
| 344 } | 313 } |
| 345 | 314 |
| 346 /////////////////////////////////////////////////////////////////////////////// | 315 /////////////////////////////////////////////////////////////////////////////// |
| 347 | 316 |
| 348 #ifdef SK_DEBUG | 317 #ifdef SK_DEBUG |
| 349 size_t GrResourceCache::countBytes(const EntryList& list) { | 318 size_t GrResourceCache::countBytes(const EntryList& list) { |
| 350 size_t bytes = 0; | 319 size_t bytes = 0; |
| 351 | 320 |
| 352 EntryList::Iter iter; | 321 EntryList::Iter iter; |
| 353 | 322 |
| 354 const GrResourceCacheEntry* entry = iter.init(const_cast<EntryList&>(list), | 323 const GrResourceCacheEntry* entry = iter.init(const_cast<EntryList&>(list), |
| 355 EntryList::Iter::kTail_IterSta rt); | 324 EntryList::Iter::kTail_IterSta rt); |
| 356 | 325 |
| 357 for ( ; entry; entry = iter.prev()) { | 326 for ( ; entry; entry = iter.prev()) { |
| 358 bytes += entry->resource()->gpuMemorySize(); | 327 bytes += entry->resource()->gpuMemorySize(); |
| 359 } | 328 } |
| 360 return bytes; | 329 return bytes; |
| 361 } | 330 } |
| 362 | 331 |
| 363 static bool both_zero_or_nonzero(int count, size_t bytes) { | 332 static bool both_zero_or_nonzero(int count, size_t bytes) { |
| 364 return (count == 0 && bytes == 0) || (count > 0 && bytes > 0); | 333 return (count == 0 && bytes == 0) || (count > 0 && bytes > 0); |
| 365 } | 334 } |
| 366 | 335 |
| 367 void GrResourceCache::validate() const { | 336 void GrResourceCache::validate() const { |
| 368 fList.validate(); | 337 fList.validate(); |
| 369 SkASSERT(both_zero_or_nonzero(fEntryCount, fEntryBytes)); | 338 SkASSERT(both_zero_or_nonzero(fEntryCount, fEntryBytes)); |
| 370 SkASSERT(fEntryCount == fCache.count()); | |
| 371 | 339 |
| 372 EntryList::Iter iter; | 340 EntryList::Iter iter; |
| 373 | 341 |
| 374 // check that the shareable entries are okay | 342 // check that the shareable entries are okay |
| 375 const GrResourceCacheEntry* entry = iter.init(const_cast<EntryList&>(fList), | 343 const GrResourceCacheEntry* entry = iter.init(const_cast<EntryList&>(fList), |
| 376 EntryList::Iter::kHead_IterSta rt); | 344 EntryList::Iter::kHead_IterSta rt); |
| 377 | 345 |
| 378 int count = 0; | 346 int count = 0; |
| 379 for ( ; entry; entry = iter.next()) { | 347 for ( ; entry; entry = iter.next()) { |
| 380 entry->validate(); | 348 entry->validate(); |
| 381 SkASSERT(fCache.find(entry->key())); | |
| 382 count += 1; | 349 count += 1; |
| 383 } | 350 } |
| 384 SkASSERT(count == fEntryCount); | 351 SkASSERT(count == fEntryCount); |
| 385 | 352 |
| 386 size_t bytes = this->countBytes(fList); | 353 size_t bytes = this->countBytes(fList); |
| 387 SkASSERT(bytes == fEntryBytes); | 354 SkASSERT(bytes == fEntryBytes); |
| 388 SkASSERT(fList.countEntries() == fEntryCount); | 355 SkASSERT(fList.countEntries() == fEntryCount); |
| 389 } | 356 } |
| 390 #endif // SK_DEBUG | 357 #endif // SK_DEBUG |
| 391 | 358 |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 414 SkDebugf("Budget: %d items %d bytes\n", fMaxCount, fMaxBytes); | 381 SkDebugf("Budget: %d items %d bytes\n", fMaxCount, fMaxBytes); |
| 415 SkDebugf("\t\tEntry Count: current %d (%d locked, %d scratch %.2g%% full), h igh %d\n", | 382 SkDebugf("\t\tEntry Count: current %d (%d locked, %d scratch %.2g%% full), h igh %d\n", |
| 416 fEntryCount, locked, scratch, countUtilization, fHighWaterEntryC ount); | 383 fEntryCount, locked, scratch, countUtilization, fHighWaterEntryC ount); |
| 417 SkDebugf("\t\tEntry Bytes: current %d (%.2g%% full) high %d\n", | 384 SkDebugf("\t\tEntry Bytes: current %d (%.2g%% full) high %d\n", |
| 418 fEntryBytes, byteUtilization, fHighWaterEntryBytes); | 385 fEntryBytes, byteUtilization, fHighWaterEntryBytes); |
| 419 } | 386 } |
| 420 | 387 |
| 421 #endif | 388 #endif |
| 422 | 389 |
| 423 /////////////////////////////////////////////////////////////////////////////// | 390 /////////////////////////////////////////////////////////////////////////////// |
| OLD | NEW |