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 |