| 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" |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 51 private: | 51 private: |
| 52 GrResourceCache* fCache; | 52 GrResourceCache* fCache; |
| 53 }; | 53 }; |
| 54 | 54 |
| 55 ////////////////////////////////////////////////////////////////////////////// | 55 ////////////////////////////////////////////////////////////////////////////// |
| 56 | 56 |
| 57 static const int kDefaultMaxCount = 2 * (1 << 10); | 57 static const int kDefaultMaxCount = 2 * (1 << 10); |
| 58 static const size_t kDefaultMaxSize = 96 * (1 << 20); | 58 static const size_t kDefaultMaxSize = 96 * (1 << 20); |
| 59 | 59 |
| 60 GrResourceCache::GrResourceCache() | 60 GrResourceCache::GrResourceCache() |
| 61 : fMaxCount(kDefaultMaxCount) | 61 : fTimestamp(0) |
| 62 , fMaxCount(kDefaultMaxCount) |
| 62 , fMaxBytes(kDefaultMaxSize) | 63 , fMaxBytes(kDefaultMaxSize) |
| 63 #if GR_CACHE_STATS | 64 #if GR_CACHE_STATS |
| 64 , fHighWaterCount(0) | 65 , fHighWaterCount(0) |
| 65 , fHighWaterBytes(0) | 66 , fHighWaterBytes(0) |
| 66 , fBudgetedHighWaterCount(0) | 67 , fBudgetedHighWaterCount(0) |
| 67 , fBudgetedHighWaterBytes(0) | 68 , fBudgetedHighWaterBytes(0) |
| 68 #endif | 69 #endif |
| 69 , fCount(0) | 70 , fCount(0) |
| 70 , fBytes(0) | 71 , fBytes(0) |
| 71 , fBudgetedCount(0) | 72 , fBudgetedCount(0) |
| 72 , fBudgetedBytes(0) | 73 , fBudgetedBytes(0) |
| 73 , fPurging(false) | |
| 74 , fNewlyPurgeableResourceWhilePurging(false) | |
| 75 , fOverBudgetCB(NULL) | 74 , fOverBudgetCB(NULL) |
| 76 , fOverBudgetData(NULL) { | 75 , fOverBudgetData(NULL) { |
| 77 } | 76 } |
| 78 | 77 |
| 79 GrResourceCache::~GrResourceCache() { | 78 GrResourceCache::~GrResourceCache() { |
| 80 this->releaseAll(); | 79 this->releaseAll(); |
| 81 } | 80 } |
| 82 | 81 |
| 83 void GrResourceCache::setLimits(int count, size_t bytes) { | 82 void GrResourceCache::setLimits(int count, size_t bytes) { |
| 84 fMaxCount = count; | 83 fMaxCount = count; |
| 85 fMaxBytes = bytes; | 84 fMaxBytes = bytes; |
| 86 this->purgeAsNeeded(); | 85 this->purgeAsNeeded(); |
| 87 } | 86 } |
| 88 | 87 |
| 89 void GrResourceCache::insertResource(GrGpuResource* resource) { | 88 void GrResourceCache::insertResource(GrGpuResource* resource) { |
| 90 SkASSERT(resource); | 89 SkASSERT(resource); |
| 91 SkASSERT(!resource->wasDestroyed()); | 90 SkASSERT(!resource->wasDestroyed()); |
| 92 SkASSERT(!this->isInCache(resource)); | 91 SkASSERT(!this->isInCache(resource)); |
| 93 SkASSERT(!fPurging); | |
| 94 fResources.addToHead(resource); | 92 fResources.addToHead(resource); |
| 95 | 93 |
| 96 size_t size = resource->gpuMemorySize(); | 94 size_t size = resource->gpuMemorySize(); |
| 97 ++fCount; | 95 ++fCount; |
| 98 fBytes += size; | 96 fBytes += size; |
| 99 #if GR_CACHE_STATS | 97 #if GR_CACHE_STATS |
| 100 fHighWaterCount = SkTMax(fCount, fHighWaterCount); | 98 fHighWaterCount = SkTMax(fCount, fHighWaterCount); |
| 101 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes); | 99 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes); |
| 102 #endif | 100 #endif |
| 103 if (resource->resourcePriv().isBudgeted()) { | 101 if (resource->resourcePriv().isBudgeted()) { |
| 104 ++fBudgetedCount; | 102 ++fBudgetedCount; |
| 105 fBudgetedBytes += size; | 103 fBudgetedBytes += size; |
| 106 #if GR_CACHE_STATS | 104 #if GR_CACHE_STATS |
| 107 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount
); | 105 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount
); |
| 108 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes
); | 106 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes
); |
| 109 #endif | 107 #endif |
| 110 } | 108 } |
| 111 if (resource->resourcePriv().getScratchKey().isValid()) { | 109 if (resource->resourcePriv().getScratchKey().isValid()) { |
| 112 SkASSERT(!resource->cacheAccess().isWrapped()); | 110 SkASSERT(!resource->cacheAccess().isWrapped()); |
| 113 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource); | 111 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource); |
| 114 } | 112 } |
| 115 | 113 |
| 114 resource->cacheAccess().setTimestamp(fTimestamp++); |
| 115 |
| 116 this->purgeAsNeeded(); | 116 this->purgeAsNeeded(); |
| 117 } | 117 } |
| 118 | 118 |
| 119 void GrResourceCache::removeResource(GrGpuResource* resource) { | 119 void GrResourceCache::removeResource(GrGpuResource* resource) { |
| 120 this->validate(); |
| 120 SkASSERT(this->isInCache(resource)); | 121 SkASSERT(this->isInCache(resource)); |
| 121 | 122 |
| 123 if (resource->isPurgeable()) { |
| 124 fPurgeableQueue.remove(resource); |
| 125 } |
| 126 |
| 122 size_t size = resource->gpuMemorySize(); | 127 size_t size = resource->gpuMemorySize(); |
| 123 --fCount; | 128 --fCount; |
| 124 fBytes -= size; | 129 fBytes -= size; |
| 125 if (resource->resourcePriv().isBudgeted()) { | 130 if (resource->resourcePriv().isBudgeted()) { |
| 126 --fBudgetedCount; | 131 --fBudgetedCount; |
| 127 fBudgetedBytes -= size; | 132 fBudgetedBytes -= size; |
| 128 } | 133 } |
| 129 | 134 |
| 130 fResources.remove(resource); | 135 fResources.remove(resource); |
| 131 if (resource->resourcePriv().getScratchKey().isValid()) { | 136 if (resource->resourcePriv().getScratchKey().isValid()) { |
| 132 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource); | 137 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource); |
| 133 } | 138 } |
| 134 if (resource->getContentKey().isValid()) { | 139 if (resource->getContentKey().isValid()) { |
| 135 fContentHash.remove(resource->getContentKey()); | 140 fContentHash.remove(resource->getContentKey()); |
| 136 } | 141 } |
| 137 this->validate(); | 142 this->validate(); |
| 138 } | 143 } |
| 139 | 144 |
| 140 void GrResourceCache::abandonAll() { | 145 void GrResourceCache::abandonAll() { |
| 141 AutoValidate av(this); | 146 AutoValidate av(this); |
| 142 | 147 |
| 143 SkASSERT(!fPurging); | |
| 144 while (GrGpuResource* head = fResources.head()) { | 148 while (GrGpuResource* head = fResources.head()) { |
| 145 SkASSERT(!head->wasDestroyed()); | 149 SkASSERT(!head->wasDestroyed()); |
| 146 head->cacheAccess().abandon(); | 150 head->cacheAccess().abandon(); |
| 147 // abandon should have already removed this from the list. | 151 // abandon should have already removed this from the list. |
| 148 SkASSERT(head != fResources.head()); | 152 SkASSERT(head != fResources.head()); |
| 149 } | 153 } |
| 150 SkASSERT(!fScratchMap.count()); | 154 SkASSERT(!fScratchMap.count()); |
| 151 SkASSERT(!fContentHash.count()); | 155 SkASSERT(!fContentHash.count()); |
| 152 SkASSERT(!fCount); | 156 SkASSERT(!fCount); |
| 153 SkASSERT(!fBytes); | 157 SkASSERT(!fBytes); |
| 154 SkASSERT(!fBudgetedCount); | 158 SkASSERT(!fBudgetedCount); |
| 155 SkASSERT(!fBudgetedBytes); | 159 SkASSERT(!fBudgetedBytes); |
| 156 } | 160 } |
| 157 | 161 |
| 158 void GrResourceCache::releaseAll() { | 162 void GrResourceCache::releaseAll() { |
| 159 AutoValidate av(this); | 163 AutoValidate av(this); |
| 160 | 164 |
| 161 SkASSERT(!fPurging); | |
| 162 while (GrGpuResource* head = fResources.head()) { | 165 while (GrGpuResource* head = fResources.head()) { |
| 163 SkASSERT(!head->wasDestroyed()); | 166 SkASSERT(!head->wasDestroyed()); |
| 164 head->cacheAccess().release(); | 167 head->cacheAccess().release(); |
| 165 // release should have already removed this from the list. | 168 // release should have already removed this from the list. |
| 166 SkASSERT(head != fResources.head()); | 169 SkASSERT(head != fResources.head()); |
| 167 } | 170 } |
| 168 SkASSERT(!fScratchMap.count()); | 171 SkASSERT(!fScratchMap.count()); |
| 169 SkASSERT(!fCount); | 172 SkASSERT(!fCount); |
| 170 SkASSERT(!fBytes); | 173 SkASSERT(!fBytes); |
| 171 SkASSERT(!fBudgetedCount); | 174 SkASSERT(!fBudgetedCount); |
| 172 SkASSERT(!fBudgetedBytes); | 175 SkASSERT(!fBudgetedBytes); |
| 173 } | 176 } |
| 174 | 177 |
| 175 class GrResourceCache::AvailableForScratchUse { | 178 class GrResourceCache::AvailableForScratchUse { |
| 176 public: | 179 public: |
| 177 AvailableForScratchUse(bool rejectPendingIO) : fRejectPendingIO(rejectPendin
gIO) { } | 180 AvailableForScratchUse(bool rejectPendingIO) : fRejectPendingIO(rejectPendin
gIO) { } |
| 178 | 181 |
| 179 bool operator()(const GrGpuResource* resource) const { | 182 bool operator()(const GrGpuResource* resource) const { |
| 180 if (resource->internalHasRef() || !resource->cacheAccess().isScratch())
{ | 183 if (resource->internalHasRef() || !resource->cacheAccess().isScratch())
{ |
| 181 return false; | 184 return false; |
| 182 } | 185 } |
| 183 return !fRejectPendingIO || !resource->internalHasPendingIO(); | 186 return !fRejectPendingIO || !resource->internalHasPendingIO(); |
| 184 } | 187 } |
| 185 | 188 |
| 186 private: | 189 private: |
| 187 bool fRejectPendingIO; | 190 bool fRejectPendingIO; |
| 188 }; | 191 }; |
| 189 | 192 |
| 190 GrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& sc
ratchKey, | 193 GrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& sc
ratchKey, |
| 191 uint32_t flags) { | 194 uint32_t flags) { |
| 192 SkASSERT(!fPurging); | |
| 193 SkASSERT(scratchKey.isValid()); | 195 SkASSERT(scratchKey.isValid()); |
| 194 | 196 |
| 195 GrGpuResource* resource; | 197 GrGpuResource* resource; |
| 196 if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFla
g)) { | 198 if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFla
g)) { |
| 197 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true)); | 199 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true)); |
| 198 if (resource) { | 200 if (resource) { |
| 199 resource->ref(); | 201 this->refAndMakeResourceMRU(resource); |
| 200 this->makeResourceMRU(resource); | |
| 201 this->validate(); | 202 this->validate(); |
| 202 return resource; | 203 return resource; |
| 203 } else if (flags & kRequireNoPendingIO_ScratchFlag) { | 204 } else if (flags & kRequireNoPendingIO_ScratchFlag) { |
| 204 return NULL; | 205 return NULL; |
| 205 } | 206 } |
| 206 // TODO: fail here when kPrefer is specified, we didn't find a resource
without pending io, | 207 // TODO: fail here when kPrefer is specified, we didn't find a resource
without pending io, |
| 207 // but there is still space in our budget for the resource. | 208 // but there is still space in our budget for the resource. |
| 208 } | 209 } |
| 209 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false)); | 210 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false)); |
| 210 if (resource) { | 211 if (resource) { |
| 211 resource->ref(); | 212 this->refAndMakeResourceMRU(resource); |
| 212 this->makeResourceMRU(resource); | |
| 213 this->validate(); | 213 this->validate(); |
| 214 } | 214 } |
| 215 return resource; | 215 return resource; |
| 216 } | 216 } |
| 217 | 217 |
| 218 void GrResourceCache::willRemoveScratchKey(const GrGpuResource* resource) { | 218 void GrResourceCache::willRemoveScratchKey(const GrGpuResource* resource) { |
| 219 SkASSERT(resource->resourcePriv().getScratchKey().isValid()); | 219 SkASSERT(resource->resourcePriv().getScratchKey().isValid()); |
| 220 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource); | 220 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource); |
| 221 } | 221 } |
| 222 | 222 |
| 223 void GrResourceCache::willRemoveContentKey(const GrGpuResource* resource) { | 223 void GrResourceCache::willRemoveContentKey(const GrGpuResource* resource) { |
| 224 // Someone has a ref to this resource in order to invalidate it. When the re
f count reaches | 224 // Someone has a ref to this resource in order to invalidate it. When the re
f count reaches |
| 225 // zero we will get a notifyPurgable() and figure out what to do with it. | 225 // zero we will get a notifyPurgable() and figure out what to do with it. |
| 226 SkASSERT(resource->getContentKey().isValid()); | 226 SkASSERT(resource->getContentKey().isValid()); |
| 227 fContentHash.remove(resource->getContentKey()); | 227 fContentHash.remove(resource->getContentKey()); |
| 228 } | 228 } |
| 229 | 229 |
| 230 bool GrResourceCache::didSetContentKey(GrGpuResource* resource) { | 230 bool GrResourceCache::didSetContentKey(GrGpuResource* resource) { |
| 231 SkASSERT(!fPurging); | |
| 232 SkASSERT(resource); | 231 SkASSERT(resource); |
| 233 SkASSERT(this->isInCache(resource)); | 232 SkASSERT(this->isInCache(resource)); |
| 234 SkASSERT(resource->getContentKey().isValid()); | 233 SkASSERT(resource->getContentKey().isValid()); |
| 235 | 234 |
| 236 GrGpuResource* res = fContentHash.find(resource->getContentKey()); | 235 GrGpuResource* res = fContentHash.find(resource->getContentKey()); |
| 237 if (NULL != res) { | 236 if (NULL != res) { |
| 238 return false; | 237 return false; |
| 239 } | 238 } |
| 240 | 239 |
| 241 fContentHash.add(resource); | 240 fContentHash.add(resource); |
| 242 this->validate(); | 241 this->validate(); |
| 243 return true; | 242 return true; |
| 244 } | 243 } |
| 245 | 244 |
| 246 void GrResourceCache::makeResourceMRU(GrGpuResource* resource) { | 245 void GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) { |
| 247 SkASSERT(!fPurging); | |
| 248 SkASSERT(resource); | 246 SkASSERT(resource); |
| 249 SkASSERT(this->isInCache(resource)); | 247 SkASSERT(this->isInCache(resource)); |
| 250 fResources.remove(resource); | 248 if (resource->isPurgeable()) { |
| 251 fResources.addToHead(resource); | 249 // It's about to become unpurgeable. |
| 250 fPurgeableQueue.remove(resource); |
| 251 } |
| 252 resource->ref(); |
| 253 resource->cacheAccess().setTimestamp(fTimestamp++); |
| 254 SkASSERT(!resource->isPurgeable()); |
| 252 } | 255 } |
| 253 | 256 |
| 254 void GrResourceCache::notifyPurgeable(GrGpuResource* resource) { | 257 void GrResourceCache::notifyPurgeable(GrGpuResource* resource) { |
| 255 SkASSERT(resource); | 258 SkASSERT(resource); |
| 256 SkASSERT(this->isInCache(resource)); | 259 SkASSERT(this->isInCache(resource)); |
| 257 SkASSERT(resource->isPurgeable()); | 260 SkASSERT(resource->isPurgeable()); |
| 258 | 261 |
| 259 // We can't purge if in the middle of purging because purge is iterating. In
stead record | 262 SkASSERT(-1 == *resource->cacheAccess().accessCacheIndex()); |
| 260 // that additional resources became purgeable. | 263 fPurgeableQueue.insert(resource); |
| 261 if (fPurging) { | |
| 262 fNewlyPurgeableResourceWhilePurging = true; | |
| 263 return; | |
| 264 } | |
| 265 | 264 |
| 266 bool release = false; | 265 if (!resource->resourcePriv().isBudgeted()) { |
| 267 | |
| 268 if (resource->cacheAccess().isWrapped()) { | |
| 269 release = true; | |
| 270 } else if (!resource->resourcePriv().isBudgeted()) { | |
| 271 // Check whether this resource could still be used as a scratch resource
. | 266 // Check whether this resource could still be used as a scratch resource
. |
| 272 if (resource->resourcePriv().getScratchKey().isValid()) { | 267 if (!resource->cacheAccess().isWrapped() && |
| 268 resource->resourcePriv().getScratchKey().isValid()) { |
| 273 // We won't purge an existing resource to make room for this one. | 269 // We won't purge an existing resource to make room for this one. |
| 274 bool underBudget = fBudgetedCount < fMaxCount && | 270 bool underBudget = fBudgetedCount < fMaxCount && |
| 275 fBudgetedBytes + resource->gpuMemorySize() <= fMa
xBytes; | 271 fBudgetedBytes + resource->gpuMemorySize() <= fMa
xBytes; |
| 276 if (underBudget) { | 272 if (underBudget) { |
| 277 resource->resourcePriv().makeBudgeted(); | 273 resource->resourcePriv().makeBudgeted(); |
| 278 } else { | 274 return; |
| 279 release = true; | |
| 280 } | 275 } |
| 281 } else { | |
| 282 release = true; | |
| 283 } | 276 } |
| 284 } else { | 277 } else { |
| 285 // Purge the resource if we're over budget | 278 // Purge the resource immediately if we're over budget |
| 286 bool overBudget = fBudgetedCount > fMaxCount || fBudgetedBytes > fMaxByt
es; | 279 bool overBudget = fBudgetedCount > fMaxCount || fBudgetedBytes > fMaxByt
es; |
| 287 | 280 |
| 288 // Also purge if the resource has neither a valid scratch key nor a cont
ent key. | 281 // Also purge if the resource has neither a valid scratch key nor a cont
ent key. |
| 289 bool noKey = !resource->resourcePriv().getScratchKey().isValid() && | 282 bool noKey = !resource->resourcePriv().getScratchKey().isValid() && |
| 290 !resource->getContentKey().isValid(); | 283 !resource->getContentKey().isValid(); |
| 291 if (overBudget || noKey) { | 284 if (!overBudget && !noKey) { |
| 292 release = true; | 285 return; |
| 293 } | 286 } |
| 294 } | 287 } |
| 295 | 288 |
| 296 if (release) { | 289 SkDEBUGCODE(int beforeCount = fCount;) |
| 297 SkDEBUGCODE(int beforeCount = fCount;) | 290 resource->cacheAccess().release(); |
| 298 resource->cacheAccess().release(); | 291 // We should at least free this resource, perhaps dependent resources as wel
l. |
| 299 // We should at least free this resource, perhaps dependent resources as
well. | 292 SkASSERT(fCount < beforeCount); |
| 300 SkASSERT(fCount < beforeCount); | |
| 301 } | |
| 302 this->validate(); | 293 this->validate(); |
| 303 } | 294 } |
| 304 | 295 |
| 305 void GrResourceCache::didChangeGpuMemorySize(const GrGpuResource* resource, size
_t oldSize) { | 296 void GrResourceCache::didChangeGpuMemorySize(const GrGpuResource* resource, size
_t oldSize) { |
| 306 // SkASSERT(!fPurging); GrPathRange increases size during flush. :( | 297 // SkASSERT(!fPurging); GrPathRange increases size during flush. :( |
| 307 SkASSERT(resource); | 298 SkASSERT(resource); |
| 308 SkASSERT(this->isInCache(resource)); | 299 SkASSERT(this->isInCache(resource)); |
| 309 | 300 |
| 310 ptrdiff_t delta = resource->gpuMemorySize() - oldSize; | 301 ptrdiff_t delta = resource->gpuMemorySize() - oldSize; |
| 311 | 302 |
| 312 fBytes += delta; | 303 fBytes += delta; |
| 313 #if GR_CACHE_STATS | 304 #if GR_CACHE_STATS |
| 314 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes); | 305 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes); |
| 315 #endif | 306 #endif |
| 316 if (resource->resourcePriv().isBudgeted()) { | 307 if (resource->resourcePriv().isBudgeted()) { |
| 317 fBudgetedBytes += delta; | 308 fBudgetedBytes += delta; |
| 318 #if GR_CACHE_STATS | 309 #if GR_CACHE_STATS |
| 319 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes
); | 310 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes
); |
| 320 #endif | 311 #endif |
| 321 } | 312 } |
| 322 | 313 |
| 323 this->purgeAsNeeded(); | 314 this->purgeAsNeeded(); |
| 324 this->validate(); | 315 this->validate(); |
| 325 } | 316 } |
| 326 | 317 |
| 327 void GrResourceCache::didChangeBudgetStatus(GrGpuResource* resource) { | 318 void GrResourceCache::didChangeBudgetStatus(GrGpuResource* resource) { |
| 328 SkASSERT(!fPurging); | |
| 329 SkASSERT(resource); | 319 SkASSERT(resource); |
| 330 SkASSERT(this->isInCache(resource)); | 320 SkASSERT(this->isInCache(resource)); |
| 331 | 321 |
| 332 size_t size = resource->gpuMemorySize(); | 322 size_t size = resource->gpuMemorySize(); |
| 333 | 323 |
| 334 if (resource->resourcePriv().isBudgeted()) { | 324 if (resource->resourcePriv().isBudgeted()) { |
| 335 ++fBudgetedCount; | 325 ++fBudgetedCount; |
| 336 fBudgetedBytes += size; | 326 fBudgetedBytes += size; |
| 337 #if GR_CACHE_STATS | 327 #if GR_CACHE_STATS |
| 338 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes
); | 328 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes
); |
| 339 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount
); | 329 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount
); |
| 340 #endif | 330 #endif |
| 341 this->purgeAsNeeded(); | 331 this->purgeAsNeeded(); |
| 342 } else { | 332 } else { |
| 343 --fBudgetedCount; | 333 --fBudgetedCount; |
| 344 fBudgetedBytes -= size; | 334 fBudgetedBytes -= size; |
| 345 } | 335 } |
| 346 | 336 |
| 347 this->validate(); | 337 this->validate(); |
| 348 } | 338 } |
| 349 | 339 |
| 350 void GrResourceCache::internalPurgeAsNeeded() { | 340 void GrResourceCache::internalPurgeAsNeeded() { |
| 351 SkASSERT(!fPurging); | |
| 352 SkASSERT(!fNewlyPurgeableResourceWhilePurging); | |
| 353 SkASSERT(fBudgetedCount > fMaxCount || fBudgetedBytes > fMaxBytes); | 341 SkASSERT(fBudgetedCount > fMaxCount || fBudgetedBytes > fMaxBytes); |
| 354 | 342 |
| 355 fPurging = true; | 343 bool stillOverbudget = true; |
| 344 while (fPurgeableQueue.count()) { |
| 345 GrGpuResource* resource = fPurgeableQueue.peek(); |
| 346 SkASSERT(resource->isPurgeable()); |
| 347 resource->cacheAccess().release(); |
| 348 if (fBudgetedCount <= fMaxCount && fBudgetedBytes <= fMaxBytes) { |
| 349 stillOverbudget = false; |
| 350 break; |
| 351 } |
| 352 } |
| 356 | 353 |
| 357 bool overBudget = true; | 354 this->validate(); |
| 358 do { | |
| 359 fNewlyPurgeableResourceWhilePurging = false; | |
| 360 ResourceList::Iter resourceIter; | |
| 361 GrGpuResource* resource = resourceIter.init(fResources, | |
| 362 ResourceList::Iter::kTail_It
erStart); | |
| 363 | 355 |
| 364 while (resource) { | 356 if (stillOverbudget) { |
| 365 GrGpuResource* prev = resourceIter.prev(); | 357 // Despite the purge we're still over budget. Call our over budget callb
ack. If this frees |
| 366 if (resource->isPurgeable()) { | 358 // any resources then we'll get notifyPurgeable() calls and take appropr
iate action. |
| 367 resource->cacheAccess().release(); | 359 (*fOverBudgetCB)(fOverBudgetData); |
| 368 } | 360 this->validate(); |
| 369 resource = prev; | 361 } |
| 370 if (fBudgetedCount <= fMaxCount && fBudgetedBytes <= fMaxBytes) { | 362 } |
| 371 overBudget = false; | |
| 372 resource = NULL; | |
| 373 } | |
| 374 } | |
| 375 | 363 |
| 376 if (!fNewlyPurgeableResourceWhilePurging && overBudget && fOverBudgetCB)
{ | 364 void GrResourceCache::purgeAllUnlocked() { |
| 377 // Despite the purge we're still over budget. Call our over budget c
allback. | 365 // We could disable maintaining the heap property here, but it would add a l
ot of complexity. |
| 378 (*fOverBudgetCB)(fOverBudgetData); | 366 // Moreover, this is rarely called. |
| 379 } | 367 while (fPurgeableQueue.count()) { |
| 380 } while (overBudget && fNewlyPurgeableResourceWhilePurging); | 368 GrGpuResource* resource = fPurgeableQueue.peek(); |
| 369 SkASSERT(resource->isPurgeable()); |
| 370 resource->cacheAccess().release(); |
| 371 } |
| 381 | 372 |
| 382 fNewlyPurgeableResourceWhilePurging = false; | |
| 383 fPurging = false; | |
| 384 this->validate(); | 373 this->validate(); |
| 385 } | 374 } |
| 386 | 375 |
| 387 void GrResourceCache::purgeAllUnlocked() { | |
| 388 SkASSERT(!fPurging); | |
| 389 SkASSERT(!fNewlyPurgeableResourceWhilePurging); | |
| 390 | |
| 391 fPurging = true; | |
| 392 | |
| 393 do { | |
| 394 fNewlyPurgeableResourceWhilePurging = false; | |
| 395 ResourceList::Iter resourceIter; | |
| 396 GrGpuResource* resource = | |
| 397 resourceIter.init(fResources, ResourceList::Iter::kTail_IterStart); | |
| 398 | |
| 399 while (resource) { | |
| 400 GrGpuResource* prev = resourceIter.prev(); | |
| 401 if (resource->isPurgeable()) { | |
| 402 resource->cacheAccess().release(); | |
| 403 } | |
| 404 resource = prev; | |
| 405 } | |
| 406 | |
| 407 if (!fNewlyPurgeableResourceWhilePurging && fCount && fOverBudgetCB) { | |
| 408 (*fOverBudgetCB)(fOverBudgetData); | |
| 409 } | |
| 410 } while (fNewlyPurgeableResourceWhilePurging); | |
| 411 fPurging = false; | |
| 412 this->validate(); | |
| 413 } | |
| 414 | |
| 415 void GrResourceCache::processInvalidContentKeys( | 376 void GrResourceCache::processInvalidContentKeys( |
| 416 const SkTArray<GrContentKeyInvalidatedMessage>& msgs) { | 377 const SkTArray<GrContentKeyInvalidatedMessage>& msgs) { |
| 417 for (int i = 0; i < msgs.count(); ++i) { | 378 for (int i = 0; i < msgs.count(); ++i) { |
| 418 GrGpuResource* resource = this->findAndRefContentResource(msgs[i].key())
; | 379 GrGpuResource* resource = this->findAndRefContentResource(msgs[i].key())
; |
| 419 if (resource) { | 380 if (resource) { |
| 420 resource->resourcePriv().removeContentKey(); | 381 resource->resourcePriv().removeContentKey(); |
| 421 resource->unref(); // will call notifyPurgeable, if it is indeed now
purgeable. | 382 resource->unref(); // will call notifyPurgeable, if it is indeed now
purgeable. |
| 422 } | 383 } |
| 423 } | 384 } |
| 424 } | 385 } |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 468 ++content; | 429 ++content; |
| 469 SkASSERT(fContentHash.find(contentKey) == resource); | 430 SkASSERT(fContentHash.find(contentKey) == resource); |
| 470 SkASSERT(!resource->cacheAccess().isWrapped()); | 431 SkASSERT(!resource->cacheAccess().isWrapped()); |
| 471 SkASSERT(resource->resourcePriv().isBudgeted()); | 432 SkASSERT(resource->resourcePriv().isBudgeted()); |
| 472 } | 433 } |
| 473 | 434 |
| 474 if (resource->resourcePriv().isBudgeted()) { | 435 if (resource->resourcePriv().isBudgeted()) { |
| 475 ++budgetedCount; | 436 ++budgetedCount; |
| 476 budgetedBytes += resource->gpuMemorySize(); | 437 budgetedBytes += resource->gpuMemorySize(); |
| 477 } | 438 } |
| 439 |
| 440 if (!resource->isPurgeable()) { |
| 441 SkASSERT(-1 == *resource->cacheAccess().accessCacheIndex()); |
| 442 } |
| 478 } | 443 } |
| 479 | 444 |
| 445 for (int i = 0; i < fPurgeableQueue.count(); ++i) { |
| 446 SkASSERT(fPurgeableQueue.at(i)->isPurgeable()); |
| 447 } |
| 448 |
| 449 SkASSERT(fCount - locked == fPurgeableQueue.count()); |
| 480 SkASSERT(fBudgetedCount <= fCount); | 450 SkASSERT(fBudgetedCount <= fCount); |
| 481 SkASSERT(fBudgetedBytes <= fBudgetedBytes); | 451 SkASSERT(fBudgetedBytes <= fBudgetedBytes); |
| 482 SkASSERT(bytes == fBytes); | 452 SkASSERT(bytes == fBytes); |
| 483 SkASSERT(count == fCount); | 453 SkASSERT(count == fCount); |
| 484 SkASSERT(budgetedBytes == fBudgetedBytes); | 454 SkASSERT(budgetedBytes == fBudgetedBytes); |
| 485 SkASSERT(budgetedCount == fBudgetedCount); | 455 SkASSERT(budgetedCount == fBudgetedCount); |
| 486 #if GR_CACHE_STATS | 456 #if GR_CACHE_STATS |
| 487 SkASSERT(fBudgetedHighWaterCount <= fHighWaterCount); | 457 SkASSERT(fBudgetedHighWaterCount <= fHighWaterCount); |
| 488 SkASSERT(fBudgetedHighWaterBytes <= fHighWaterBytes); | 458 SkASSERT(fBudgetedHighWaterBytes <= fHighWaterBytes); |
| 489 SkASSERT(bytes <= fHighWaterBytes); | 459 SkASSERT(bytes <= fHighWaterBytes); |
| 490 SkASSERT(count <= fHighWaterCount); | 460 SkASSERT(count <= fHighWaterCount); |
| 491 SkASSERT(budgetedBytes <= fBudgetedHighWaterBytes); | 461 SkASSERT(budgetedBytes <= fBudgetedHighWaterBytes); |
| 492 SkASSERT(budgetedCount <= fBudgetedHighWaterCount); | 462 SkASSERT(budgetedCount <= fBudgetedHighWaterCount); |
| 493 #endif | 463 #endif |
| 494 SkASSERT(content == fContentHash.count()); | 464 SkASSERT(content == fContentHash.count()); |
| 495 SkASSERT(scratch + couldBeScratch == fScratchMap.count()); | 465 SkASSERT(scratch + couldBeScratch == fScratchMap.count()); |
| 496 | 466 |
| 497 // This assertion is not currently valid because we can be in recursive noti
fyIsPurgeable() | 467 // This assertion is not currently valid because we can be in recursive noti
fyIsPurgeable() |
| 498 // calls. This will be fixed when subresource registration is explicit. | 468 // calls. This will be fixed when subresource registration is explicit. |
| 499 // bool overBudget = budgetedBytes > fMaxBytes || budgetedCount > fMaxCount; | 469 // bool overBudget = budgetedBytes > fMaxBytes || budgetedCount > fMaxCount; |
| 500 // SkASSERT(!overBudget || locked == count || fPurging); | 470 // SkASSERT(!overBudget || locked == count || fPurging); |
| 501 } | 471 } |
| 502 #endif | 472 #endif |
| OLD | NEW |