Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(60)

Side by Side Diff: src/gpu/GrResourceCache.cpp

Issue 91453002: Speed up GrResourceCache add and lookup by using TDynamicHash (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 "GrResource.h" 12 #include "GrResource.h"
13 13
14 14
15 GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() { 15 GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() {
16 static int32_t gNextType = 0; 16 static int32_t gNextType = 0;
17 17
18 int32_t type = sk_atomic_inc(&gNextType); 18 int32_t type = sk_atomic_inc(&gNextType);
19 if (type >= (1 << 8 * sizeof(ResourceType))) { 19 if (type >= (1 << 8 * sizeof(ResourceType))) {
20 GrCrash("Too many Resource Types"); 20 GrCrash("Too many Resource Types");
21 } 21 }
22 22
23 return static_cast<ResourceType>(type); 23 return static_cast<ResourceType>(type);
24 } 24 }
25 25
26 /////////////////////////////////////////////////////////////////////////////// 26 ///////////////////////////////////////////////////////////////////////////////
27 27
28 GrResourceEntry::GrResourceEntry(const GrResourceKey& key, GrResource* resource) 28 GrResourceEntry::GrResourceEntry(const GrResourceKey& key, GrResource* firstReso urce)
29 : fKey(key), fResource(resource) { 29 : fKey(key)
30 // we assume ownership of the resource, and will unref it when we die 30 , fExclusiveCount(0) {
31 SkASSERT(resource); 31 addResource(firstResource);
mtklein 2013/12/03 19:02:02 this->
32 resource->ref();
33 } 32 }
34 33
35 GrResourceEntry::~GrResourceEntry() { 34 GrResourceEntry::~GrResourceEntry() {
mtklein 2013/12/03 19:02:02 The responsibility for resource ownership here see
36 fResource->setCacheEntry(NULL); 35 SkASSERT(isEmpty());
37 fResource->unref(); 36 }
37
38 void GrResourceEntry::addResource(GrResource* resource) {
39 // We assume ownership of the resource, and will unref it when resource is
40 // removed from the entry.
41 resource->ref();
42 resource->setCacheEntry(this);
43 fResources.addToHead(resource);
38 } 44 }
39 45
40 #ifdef SK_DEBUG 46 bool GrResourceEntry::removeResource(GrResource* resource) {
41 void GrResourceEntry::validate() const { 47 fResources.remove(resource);
42 SkASSERT(fResource); 48
43 SkASSERT(fResource->getCacheEntry() == this); 49 // The unref() might run destructor which would remove other resources from this entry and delete the
44 fResource->validate(); 50 // entry. Temporarily increase exclusive count, so that entry stays alive.
51 ++fExclusiveCount;
52
53 resource->setCacheEntry(NULL);
54 resource->unref();
55
56 --fExclusiveCount;
57
58 return isEmpty();
45 } 59 }
46 #endif 60
61 bool GrResourceEntry::removeExclusiveResource(GrResource* resource) {
62 resource->setCacheEntry(NULL);
63 resource->unref();
64
65 // Decrease the count after unref(). See removeResource.
66 --fExclusiveCount;
67
68 return isEmpty();
69 }
70
71 void GrResourceEntry::makeExclusive(GrResource* resource) {
72 fResources.remove(resource);
73 fExclusiveCount++;
74 }
75
76 void GrResourceEntry::makeNonExclusive(GrResource* resource) {
77 fResources.addToHead(resource);
78 fExclusiveCount--;
79 }
47 80
48 /////////////////////////////////////////////////////////////////////////////// 81 ///////////////////////////////////////////////////////////////////////////////
49 82
50 GrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) : 83 GrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) :
51 fMaxCount(maxCount), 84 fMaxCount(maxCount),
52 fMaxBytes(maxBytes) { 85 fMaxBytes(maxBytes) {
53 #if GR_CACHE_STATS 86 #if GR_CACHE_STATS
54 fHighWaterEntryCount = 0; 87 fHighWaterEntryCount = 0;
55 fHighWaterEntryBytes = 0; 88 fHighWaterEntryBytes = 0;
56 fHighWaterClientDetachedCount = 0; 89 fHighWaterClientDetachedCount = 0;
57 fHighWaterClientDetachedBytes = 0; 90 fHighWaterClientDetachedBytes = 0;
58 #endif 91 #endif
59 92
60 fEntryCount = 0; 93 fEntryCount = 0;
61 fEntryBytes = 0; 94 fEntryBytes = 0;
62 fClientDetachedCount = 0; 95 fClientDetachedCount = 0;
63 fClientDetachedBytes = 0; 96 fClientDetachedBytes = 0;
64 97
65 fPurging = false; 98 fPurging = false;
66 99
67 fOverbudgetCB = NULL; 100 fOverbudgetCB = NULL;
68 fOverbudgetData = NULL; 101 fOverbudgetData = NULL;
69 } 102 }
70 103
71 GrResourceCache::~GrResourceCache() { 104 GrResourceCache::~GrResourceCache() {
72 GrAutoResourceCacheValidate atcv(this); 105 GrAutoResourceCacheValidate atcv(this);
73 106
74 EntryList::Iter iter; 107 while (GrResource* resource = fList.head()) {
108 GrAutoResourceCacheValidate atcv(this);
109 this->removeResource(resource);
110 }
75 111
76 // Unlike the removeAll, here we really remove everything, including locked resources. 112 SkASSERT(fCache.count() == 0);
77 while (GrResourceEntry* entry = fList.head()) {
78 GrAutoResourceCacheValidate atcv(this);
79
80 // remove from our cache
81 fCache.remove(entry->fKey, entry);
82
83 // remove from our llist
84 this->internalDetach(entry);
85
86 delete entry;
87 }
88 } 113 }
89 114
90 void GrResourceCache::getLimits(int* maxResources, size_t* maxResourceBytes) con st{ 115 void GrResourceCache::getLimits(int* maxResources, size_t* maxResourceBytes) con st{
91 if (NULL != maxResources) { 116 if (NULL != maxResources) {
92 *maxResources = fMaxCount; 117 *maxResources = fMaxCount;
93 } 118 }
94 if (NULL != maxResourceBytes) { 119 if (NULL != maxResourceBytes) {
95 *maxResourceBytes = fMaxBytes; 120 *maxResourceBytes = fMaxBytes;
96 } 121 }
97 } 122 }
98 123
99 void GrResourceCache::setLimits(int maxResources, size_t maxResourceBytes) { 124 void GrResourceCache::setLimits(int maxResources, size_t maxResourceBytes) {
100 bool smaller = (maxResources < fMaxCount) || (maxResourceBytes < fMaxBytes); 125 bool smaller = (maxResources < fMaxCount) || (maxResourceBytes < fMaxBytes);
101 126
102 fMaxCount = maxResources; 127 fMaxCount = maxResources;
103 fMaxBytes = maxResourceBytes; 128 fMaxBytes = maxResourceBytes;
104 129
105 if (smaller) { 130 if (smaller) {
106 this->purgeAsNeeded(); 131 this->purgeAsNeeded();
107 } 132 }
108 } 133 }
109 134
110 void GrResourceCache::internalDetach(GrResourceEntry* entry, 135 void GrResourceCache::internalDetach(GrResource* resource,
111 BudgetBehaviors behavior) { 136 BudgetBehaviors behavior) {
112 fList.remove(entry); 137 fList.remove(resource);
113 138
114 // update our stats 139 // update our stats
115 if (kIgnore_BudgetBehavior == behavior) { 140 if (kIgnore_BudgetBehavior == behavior) {
116 fClientDetachedCount += 1; 141 fClientDetachedCount += 1;
117 fClientDetachedBytes += entry->resource()->sizeInBytes(); 142 fClientDetachedBytes += resource->sizeInBytes();
118 143
119 #if GR_CACHE_STATS 144 #if GR_CACHE_STATS
120 if (fHighWaterClientDetachedCount < fClientDetachedCount) { 145 if (fHighWaterClientDetachedCount < fClientDetachedCount) {
121 fHighWaterClientDetachedCount = fClientDetachedCount; 146 fHighWaterClientDetachedCount = fClientDetachedCount;
122 } 147 }
123 if (fHighWaterClientDetachedBytes < fClientDetachedBytes) { 148 if (fHighWaterClientDetachedBytes < fClientDetachedBytes) {
124 fHighWaterClientDetachedBytes = fClientDetachedBytes; 149 fHighWaterClientDetachedBytes = fClientDetachedBytes;
125 } 150 }
126 #endif 151 #endif
127 152
128 } else { 153 } else {
129 SkASSERT(kAccountFor_BudgetBehavior == behavior); 154 SkASSERT(kAccountFor_BudgetBehavior == behavior);
130 155
131 fEntryCount -= 1; 156 fEntryCount -= 1;
132 fEntryBytes -= entry->resource()->sizeInBytes(); 157 fEntryBytes -= resource->sizeInBytes();
133 } 158 }
134 } 159 }
135 160
136 void GrResourceCache::attachToHead(GrResourceEntry* entry, 161 void GrResourceCache::attachToHead(GrResource* resource,
137 BudgetBehaviors behavior) { 162 BudgetBehaviors behavior) {
138 fList.addToHead(entry); 163 fList.addToHead(resource);
139 164
140 // update our stats 165 // update our stats
141 if (kIgnore_BudgetBehavior == behavior) { 166 if (kIgnore_BudgetBehavior == behavior) {
142 fClientDetachedCount -= 1; 167 fClientDetachedCount -= 1;
143 fClientDetachedBytes -= entry->resource()->sizeInBytes(); 168 fClientDetachedBytes -= resource->sizeInBytes();
144 } else { 169 } else {
145 SkASSERT(kAccountFor_BudgetBehavior == behavior); 170 SkASSERT(kAccountFor_BudgetBehavior == behavior);
146 171
147 fEntryCount += 1; 172 fEntryCount += 1;
148 fEntryBytes += entry->resource()->sizeInBytes(); 173 fEntryBytes += resource->sizeInBytes();
149 174
150 #if GR_CACHE_STATS 175 #if GR_CACHE_STATS
151 if (fHighWaterEntryCount < fEntryCount) { 176 if (fHighWaterEntryCount < fEntryCount) {
152 fHighWaterEntryCount = fEntryCount; 177 fHighWaterEntryCount = fEntryCount;
153 } 178 }
154 if (fHighWaterEntryBytes < fEntryBytes) { 179 if (fHighWaterEntryBytes < fEntryBytes) {
155 fHighWaterEntryBytes = fEntryBytes; 180 fHighWaterEntryBytes = fEntryBytes;
156 } 181 }
157 #endif 182 #endif
158 } 183 }
159 } 184 }
160 185
161 // This functor just searches for an entry with only a single ref (from 186 // This functor just searches for an entry with only a single ref (from
162 // the texture cache itself). Presumably in this situation no one else 187 // the texture cache itself). Presumably in this situation no one else
163 // is relying on the texture. 188 // is relying on the texture.
164 class GrTFindUnreffedFunctor { 189 class GrTFindUnreffedFunctor {
165 public: 190 public:
166 bool operator()(const GrResourceEntry* entry) const { 191 bool operator()(const GrResource* resource) const {
167 return entry->resource()->unique(); 192 return resource->unique();
168 } 193 }
169 }; 194 };
170 195
171 GrResource* GrResourceCache::find(const GrResourceKey& key, uint32_t ownershipFl ags) { 196 GrResource* GrResourceCache::find(const GrResourceKey& key, uint32_t ownershipFl ags) {
172 GrAutoResourceCacheValidate atcv(this); 197 GrAutoResourceCacheValidate atcv(this);
173 198
174 GrResourceEntry* entry = NULL; 199 GrResourceEntry* entry = fCache.find(key);
175
176 if (ownershipFlags & kNoOtherOwners_OwnershipFlag) {
177 GrTFindUnreffedFunctor functor;
178
179 entry = fCache.find<GrTFindUnreffedFunctor>(key, functor);
180 } else {
181 entry = fCache.find(key);
182 }
183
184 if (NULL == entry) { 200 if (NULL == entry) {
185 return NULL; 201 return NULL;
186 } 202 }
187 203
204 GrResource* resource;
205 if (ownershipFlags & kNoOtherOwners_OwnershipFlag) {
206 GrTFindUnreffedFunctor functor;
207 resource = entry->resources().find(functor);
208 } else {
209 // Find a resource not referenced outside cache, or the least referenced one.
210 typedef GrResourceEntry::CacheEntryResourcesInternalLListType::Iter Entr yResourcesIter;
211
212 EntryResourcesIter iter;
213 resource = iter.init(entry->resources(), EntryResourcesIter::kTail_IterS tart);
mtklein 2013/12/03 19:02:02 If we don't need to iterate both ways down the lis
214 if (NULL != resource && resource->getRefCnt() > 1) {
mtklein 2013/12/03 19:02:02 Oooh, calls to getRefCnt() make me super scared.
215 int refCount = resource->getRefCnt();
216 for (GrResource* nextResource = iter.next();
217 NULL != nextResource && refCount > 1;
218 nextResource = iter.next()) {
219 if (nextResource->getRefCnt() > refCount) {
220 resource = nextResource;
221 refCount = nextResource->getRefCnt();
222 }
223 }
224 }
225 }
226
227 if (NULL == resource) {
228 return NULL;
229 }
230
188 if (ownershipFlags & kHide_OwnershipFlag) { 231 if (ownershipFlags & kHide_OwnershipFlag) {
189 this->makeExclusive(entry); 232 this->makeExclusive(resource);
190 } else { 233 } else {
191 // Make this resource MRU 234 // Make this resource MRU
192 this->internalDetach(entry); 235 this->internalDetach(resource);
193 this->attachToHead(entry); 236 this->attachToHead(resource);
194 } 237 }
195 238
196 return entry->fResource; 239 return resource;
197 } 240 }
198 241
199 void GrResourceCache::addResource(const GrResourceKey& key, 242 void GrResourceCache::addResource(const GrResourceKey& key,
200 GrResource* resource, 243 GrResource* resource,
201 uint32_t ownershipFlags) { 244 uint32_t ownershipFlags) {
202 SkASSERT(NULL == resource->getCacheEntry()); 245 SkASSERT(NULL == resource->getCacheEntry());
203 // we don't expect to create new resources during a purge. In theory 246 // we don't expect to create new resources during a purge. In theory
204 // this could cause purgeAsNeeded() into an infinite loop (e.g. 247 // this could cause purgeAsNeeded() into an infinite loop (e.g.
205 // each resource destroyed creates and locks 2 resources and 248 // each resource destroyed creates and locks 2 resources and
206 // unlocks 1 thereby causing a new purge). 249 // unlocks 1 thereby causing a new purge).
207 SkASSERT(!fPurging); 250 SkASSERT(!fPurging);
208 GrAutoResourceCacheValidate atcv(this); 251 GrAutoResourceCacheValidate atcv(this);
209 252
210 GrResourceEntry* entry = SkNEW_ARGS(GrResourceEntry, (key, resource)); 253 GrResourceEntry* entry = fCache.find(key);
211 resource->setCacheEntry(entry); 254 if (NULL == entry) {
255 entry = SkNEW_ARGS(GrResourceEntry, (key, resource));
256 fCache.add(entry);
257 } else {
258 entry->addResource(resource);
259 }
212 260
213 this->attachToHead(entry); 261 this->attachToHead(resource);
214 fCache.insert(key, entry);
215 262
216 if (ownershipFlags & kHide_OwnershipFlag) { 263 if (ownershipFlags & kHide_OwnershipFlag) {
217 this->makeExclusive(entry); 264 this->makeExclusive(resource);
218 } 265 }
219
220 } 266 }
221 267
222 void GrResourceCache::makeExclusive(GrResourceEntry* entry) { 268 void GrResourceCache::makeExclusive(GrResource* resource) {
223 GrAutoResourceCacheValidate atcv(this); 269 GrAutoResourceCacheValidate atcv(this);
224
225 // When scratch textures are detached (to hide them from future finds) they 270 // When scratch textures are detached (to hide them from future finds) they
226 // still count against the resource budget 271 // still count against the resource budget
227 this->internalDetach(entry, kIgnore_BudgetBehavior); 272 this->internalDetach(resource, kIgnore_BudgetBehavior);
228 fCache.remove(entry->key(), entry); 273 resource->getCacheEntry()->makeExclusive(resource);
229 274
230 #ifdef SK_DEBUG 275 #ifdef SK_DEBUG
231 fExclusiveList.addToHead(entry); 276 fExclusiveList.addToHead(resource);
232 #endif 277 #endif
233 } 278 }
234 279
235 void GrResourceCache::removeInvalidResource(GrResourceEntry* entry) { 280 void GrResourceCache::removeInvalidResource(GrResource* resource) {
236 // If the resource went invalid while it was detached then purge it 281 // If the resource went invalid while it was detached then purge it
237 // This can happen when a 3D context was lost, 282 // This can happen when a 3D context was lost,
238 // the client called GrContext::contextDestroyed() to notify Gr, 283 // the client called GrContext::contextDestroyed() to notify Gr,
239 // and then later an SkGpuDevice's destructor releases its backing 284 // and then later an SkGpuDevice's destructor releases its backing
240 // texture (which was invalidated at contextDestroyed time). 285 // texture (which was invalidated at contextDestroyed time).
241 fClientDetachedCount -= 1; 286 fClientDetachedCount -= 1;
242 fEntryCount -= 1; 287 fEntryCount -= 1;
243 size_t size = entry->resource()->sizeInBytes(); 288 size_t size = resource->sizeInBytes();
244 fClientDetachedBytes -= size; 289 fClientDetachedBytes -= size;
245 fEntryBytes -= size; 290 fEntryBytes -= size;
246 } 291 }
247 292
248 void GrResourceCache::makeNonExclusive(GrResourceEntry* entry) { 293 void GrResourceCache::makeNonExclusive(GrResource* resource) {
249 GrAutoResourceCacheValidate atcv(this); 294 GrAutoResourceCacheValidate atcv(this);
250 295
251 #ifdef SK_DEBUG 296 #ifdef SK_DEBUG
252 fExclusiveList.remove(entry); 297 fExclusiveList.remove(resource);
253 #endif 298 #endif
254 299
255 if (entry->resource()->isValid()) { 300 if (resource->isValid()) {
256 // Since scratch textures still count against the cache budget even 301 // Since scratch textures still count against the cache budget even
257 // when they have been removed from the cache, re-adding them doesn't 302 // when they have been removed from the cache, re-adding them doesn't
258 // alter the budget information. 303 // alter the budget information.
259 attachToHead(entry, kIgnore_BudgetBehavior); 304 attachToHead(resource, kIgnore_BudgetBehavior);
260 fCache.insert(entry->key(), entry); 305 resource->getCacheEntry()->makeNonExclusive(resource);
261 } else { 306 } else {
262 this->removeInvalidResource(entry); 307 this->removeInvalidResource(resource);
308 GrResourceEntry* entry = resource->getCacheEntry();
309 if (entry->removeExclusiveResource(resource)) {
310 fCache.remove(entry->key());
311 delete entry;
312 }
263 } 313 }
264 } 314 }
265 315
266 /** 316 /**
267 * Destroying a resource may potentially trigger the unlock of additional 317 * Destroying a resource may potentially trigger the unlock of additional
268 * resources which in turn will trigger a nested purge. We block the nested 318 * resources which in turn will trigger a nested purge. We block the nested
269 * purge using the fPurging variable. However, the initial purge will keep 319 * purge using the fPurging variable. However, the initial purge will keep
270 * looping until either all resources in the cache are unlocked or we've met 320 * looping until either all resources in the cache are unlocked or we've met
271 * the budget. There is an assertion in createAndLock to check against a 321 * the budget. There is an assertion in createAndLock to check against a
272 * resource's destructor inserting new resources into the cache. If these 322 * resource's destructor inserting new resources into the cache. If these
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 fInvalidationInbox.poll(&invalidated); 355 fInvalidationInbox.poll(&invalidated);
306 356
307 for (int i = 0; i < invalidated.count(); i++) { 357 for (int i = 0; i < invalidated.count(); i++) {
308 // We're somewhat missing an opportunity here. We could use the 358 // We're somewhat missing an opportunity here. We could use the
309 // default find functor that gives us back resources whether we own 359 // default find functor that gives us back resources whether we own
310 // them exclusively or not, and when they're not exclusively owned mark 360 // them exclusively or not, and when they're not exclusively owned mark
311 // them for purging later when they do become exclusively owned. 361 // them for purging later when they do become exclusively owned.
312 // 362 //
313 // This is complicated and confusing. May try this in the future. For 363 // This is complicated and confusing. May try this in the future. For
314 // now, these resources are just LRU'd as if we never got the message. 364 // now, these resources are just LRU'd as if we never got the message.
315 GrResourceEntry* entry = fCache.find(invalidated[i].key, GrTFindUnreffed Functor()); 365 GrResourceEntry* entry = fCache.find(invalidated[i].key);
316 if (entry) { 366 if (entry) {
317 this->deleteResource(entry); 367 GrTFindUnreffedFunctor functor;
368 GrResource* resource;
369 do {
370 resource = entry->resources().find(functor);
371 } while (resource != NULL && this->removeResource(resource));
mtklein 2013/12/03 19:02:02 Hmm, won't this be O(N^2)? This is a case where u
318 } 372 }
319 } 373 }
320 } 374 }
321 375
322 void GrResourceCache::deleteResource(GrResourceEntry* entry) { 376 bool GrResourceCache::removeResource(GrResource* resource) {
323 SkASSERT(1 == entry->fResource->getRefCnt()); 377 GrResourceEntry* entry = resource->getCacheEntry();
378 this->internalDetach(resource);
379 if (entry->removeResource(resource)) {
380 fCache.remove(entry->key());
381 delete entry;
382 return false;
383 }
324 384
325 // remove from our cache 385 return true;
326 fCache.remove(entry->key(), entry);
327
328 // remove from our llist
329 this->internalDetach(entry);
330 delete entry;
331 } 386 }
332 387
333 void GrResourceCache::internalPurge(int extraCount, size_t extraBytes) { 388 void GrResourceCache::internalPurge(int extraCount, size_t extraBytes) {
334 SkASSERT(fPurging); 389 SkASSERT(fPurging);
335 390
336 bool withinBudget = false; 391 bool withinBudget = false;
337 bool changed = false; 392 bool changed = false;
338 393
339 // The purging process is repeated several times since one pass 394 // The purging process is repeated several times since one pass
340 // may free up other resources 395 // may free up other resources
341 do { 396 do {
342 EntryList::Iter iter; 397 CacheLRUInternalLListType::Iter iter;
343 398
344 changed = false; 399 changed = false;
345 400
346 // Note: the following code relies on the fact that the 401 // Note: the following code relies on the fact that the
347 // doubly linked list doesn't invalidate its data/pointers 402 // doubly linked list doesn't invalidate its data/pointers
348 // outside of the specific area where a deletion occurs (e.g., 403 // outside of the specific area where a deletion occurs (e.g.,
349 // in internalDetach) 404 // in internalDetach)
350 GrResourceEntry* entry = iter.init(fList, EntryList::Iter::kTail_IterSta rt); 405 GrResource* resource = iter.init(fList, CacheLRUInternalLListType::Iter: :kTail_IterStart);
351 406
352 while (NULL != entry) { 407 while (NULL != resource) {
353 GrAutoResourceCacheValidate atcv(this); 408 GrAutoResourceCacheValidate atcv(this);
354 409
355 if ((fEntryCount+extraCount) <= fMaxCount && 410 if ((fEntryCount+extraCount) <= fMaxCount &&
356 (fEntryBytes+extraBytes) <= fMaxBytes) { 411 (fEntryBytes+extraBytes) <= fMaxBytes) {
357 withinBudget = true; 412 withinBudget = true;
358 break; 413 break;
359 } 414 }
360 415
361 GrResourceEntry* prev = iter.prev(); 416 GrResource* prev = iter.prev();
362 if (entry->fResource->unique()) { 417 if (resource->unique()) {
363 changed = true; 418 changed = true;
364 this->deleteResource(entry); 419 this->deleteResource(resource);
365 } 420 }
366 entry = prev; 421 resource = prev;
367 } 422 }
368 } while (!withinBudget && changed); 423 } while (!withinBudget && changed);
369 } 424 }
370 425
371 void GrResourceCache::purgeAllUnlocked() { 426 void GrResourceCache::purgeAllUnlocked() {
372 GrAutoResourceCacheValidate atcv(this); 427 GrAutoResourceCacheValidate atcv(this);
373 428
374 // we can have one GrResource holding a lock on another 429 // we can have one GrResource holding a lock on another
375 // so we don't want to just do a simple loop kicking each 430 // so we don't want to just do a simple loop kicking each
376 // entry out. Instead change the budget and purge. 431 // entry out. Instead change the budget and purge.
377 432
378 size_t savedMaxBytes = fMaxBytes; 433 size_t savedMaxBytes = fMaxBytes;
379 int savedMaxCount = fMaxCount; 434 int savedMaxCount = fMaxCount;
380 fMaxBytes = (size_t) -1; 435 fMaxBytes = (size_t) -1;
381 fMaxCount = 0; 436 fMaxCount = 0;
382 this->purgeAsNeeded(); 437 this->purgeAsNeeded();
383 438
384 #ifdef SK_DEBUG 439 #ifdef SK_DEBUG
385 SkASSERT(fExclusiveList.countEntries() == fClientDetachedCount); 440 SkASSERT(fExclusiveList.countEntries() == fClientDetachedCount);
386 SkASSERT(countBytes(fExclusiveList) == fClientDetachedBytes); 441 SkASSERT(countBytes(fExclusiveList) == fClientDetachedBytes);
387 if (!fCache.count()) { 442 // Items may have been detached from the cache (such as the backing
388 // Items may have been detached from the cache (such as the backing 443 // texture for an SkGpuDevice). The above purge would not have removed
389 // texture for an SkGpuDevice). The above purge would not have removed 444 // them.
390 // them. 445 SkASSERT(fEntryCount == fClientDetachedCount);
391 SkASSERT(fEntryCount == fClientDetachedCount); 446 SkASSERT(fEntryBytes == fClientDetachedBytes);
392 SkASSERT(fEntryBytes == fClientDetachedBytes); 447 SkASSERT(fList.isEmpty());
393 SkASSERT(fList.isEmpty());
394 }
395 #endif 448 #endif
396 449
397 fMaxBytes = savedMaxBytes; 450 fMaxBytes = savedMaxBytes;
398 fMaxCount = savedMaxCount; 451 fMaxCount = savedMaxCount;
399 } 452 }
400 453
401 /////////////////////////////////////////////////////////////////////////////// 454 ///////////////////////////////////////////////////////////////////////////////
402 455
403 #ifdef SK_DEBUG 456 #ifdef SK_DEBUG
404 size_t GrResourceCache::countBytes(const EntryList& list) { 457 size_t GrResourceCache::countBytes(const CacheLRUInternalLListType& list) {
405 size_t bytes = 0; 458 size_t bytes = 0;
406 459
407 EntryList::Iter iter; 460 CacheLRUInternalLListType::Iter iter;
461 const GrResource* resource = iter.init(const_cast<CacheLRUInternalLListType& >(list),
462 CacheLRUInternalLListType::Iter::kTai l_IterStart);
408 463
409 const GrResourceEntry* entry = iter.init(const_cast<EntryList&>(list), 464 for ( ; NULL != resource; resource = iter.prev()) {
410 EntryList::Iter::kTail_IterStart); 465 bytes += resource->sizeInBytes();
411
412 for ( ; NULL != entry; entry = iter.prev()) {
413 bytes += entry->resource()->sizeInBytes();
414 } 466 }
415 return bytes; 467 return bytes;
416 } 468 }
417 469
418 static bool both_zero_or_nonzero(int count, size_t bytes) { 470 static bool both_zero_or_nonzero(int count, size_t bytes) {
419 return (count == 0 && bytes == 0) || (count > 0 && bytes > 0); 471 return (count == 0 && bytes == 0) || (count > 0 && bytes > 0);
420 } 472 }
421 473
422 void GrResourceCache::validate() const { 474 void GrResourceCache::validate() const {
423 fList.validate(); 475 fList.validate();
424 fExclusiveList.validate(); 476 fExclusiveList.validate();
425 SkASSERT(both_zero_or_nonzero(fEntryCount, fEntryBytes)); 477 SkASSERT(both_zero_or_nonzero(fEntryCount, fEntryBytes));
426 SkASSERT(both_zero_or_nonzero(fClientDetachedCount, fClientDetachedBytes)); 478 SkASSERT(both_zero_or_nonzero(fClientDetachedCount, fClientDetachedBytes));
427 SkASSERT(fClientDetachedBytes <= fEntryBytes); 479 SkASSERT(fClientDetachedBytes <= fEntryBytes);
428 SkASSERT(fClientDetachedCount <= fEntryCount); 480 SkASSERT(fClientDetachedCount <= fEntryCount);
429 SkASSERT((fEntryCount - fClientDetachedCount) == fCache.count());
430 481
431 fCache.validate(); 482 CacheLRUInternalLListType::Iter iter;
432
433
434 EntryList::Iter iter;
435 483
436 // check that the exclusively held entries are okay 484 // check that the exclusively held entries are okay
437 const GrResourceEntry* entry = iter.init(const_cast<EntryList&>(fExclusiveLi st), 485 GrResource* resource = iter.init(const_cast<CacheLRUInternalLListType&>(fExc lusiveList),
438 EntryList::Iter::kHead_IterStart); 486 CacheLRUInternalLListType::Iter::kHead_Iter Start);
439 487
440 for ( ; NULL != entry; entry = iter.next()) { 488 for ( ; NULL != resource; resource = iter.next()) {
441 entry->validate(); 489 resource->validate();
442 } 490 }
443 491
444 // check that the shareable entries are okay 492 // check that the shareable entries are okay
445 entry = iter.init(const_cast<EntryList&>(fList), EntryList::Iter::kHead_Iter Start); 493 resource = iter.init(const_cast<CacheLRUInternalLListType&>(fList),
494 CacheLRUInternalLListType::Iter::kHead_IterStart);
446 495
447 int count = 0; 496 int count = 0;
448 for ( ; NULL != entry; entry = iter.next()) { 497 for ( ; NULL != resource; resource = iter.next()) {
449 entry->validate(); 498 resource->validate();
450 SkASSERT(fCache.find(entry->key())); 499 SkASSERT(fCache.find(resource->getCacheEntry()->key()));
451 count += 1; 500 count += 1;
452 } 501 }
453 SkASSERT(count == fEntryCount - fClientDetachedCount); 502 SkASSERT(count == fEntryCount - fClientDetachedCount);
454 503
455 size_t bytes = countBytes(fList); 504 size_t bytes = countBytes(fList);
456 SkASSERT(bytes == fEntryBytes - fClientDetachedBytes); 505 SkASSERT(bytes == fEntryBytes - fClientDetachedBytes);
457 506
458 bytes = countBytes(fExclusiveList); 507 bytes = countBytes(fExclusiveList);
459 SkASSERT(bytes == fClientDetachedBytes); 508 SkASSERT(bytes == fClientDetachedBytes);
460 509
461 SkASSERT(fList.countEntries() == fEntryCount - fClientDetachedCount); 510 SkASSERT(fList.countEntries() == fEntryCount - fClientDetachedCount);
462 511
463 SkASSERT(fExclusiveList.countEntries() == fClientDetachedCount); 512 SkASSERT(fExclusiveList.countEntries() == fClientDetachedCount);
464 } 513 }
465 #endif // SK_DEBUG 514 #endif // SK_DEBUG
466 515
467 #if GR_CACHE_STATS 516 #if GR_CACHE_STATS
468 517
469 void GrResourceCache::printStats() { 518 void GrResourceCache::printStats() {
470 int locked = 0; 519 int locked = 0;
471 520
472 EntryList::Iter iter; 521 CacheLRUInternalLListType::Iter iter;
473 522
474 GrResourceEntry* entry = iter.init(fList, EntryList::Iter::kTail_IterStart); 523 GrResource* resource = iter.init(fList, CacheLRUInternalLListType::Iter::kTa il_IterStart);
475 524
476 for ( ; NULL != entry; entry = iter.prev()) { 525 for ( ; NULL != resource; resource = iter.prev()) {
477 if (entry->fResource->getRefCnt() > 1) { 526 if (resource->getRefCnt() > 1) {
478 ++locked; 527 ++locked;
479 } 528 }
480 } 529 }
481 530
482 SkDebugf("Budget: %d items %d bytes\n", fMaxCount, fMaxBytes); 531 SkDebugf("Budget: %d items %d bytes\n", fMaxCount, fMaxBytes);
483 SkDebugf("\t\tEntry Count: current %d (%d locked) high %d\n", 532 SkDebugf("\t\tEntry Count: current %d (%d locked) high %d\n",
484 fEntryCount, locked, fHighWaterEntryCount); 533 fEntryCount, locked, fHighWaterEntryCount);
485 SkDebugf("\t\tEntry Bytes: current %d high %d\n", 534 SkDebugf("\t\tEntry Bytes: current %d high %d\n",
486 fEntryBytes, fHighWaterEntryBytes); 535 fEntryBytes, fHighWaterEntryBytes);
487 SkDebugf("\t\tDetached Entry Count: current %d high %d\n", 536 SkDebugf("\t\tDetached Entry Count: current %d high %d\n",
488 fClientDetachedCount, fHighWaterClientDetachedCount); 537 fClientDetachedCount, fHighWaterClientDetachedCount);
489 SkDebugf("\t\tDetached Bytes: current %d high %d\n", 538 SkDebugf("\t\tDetached Bytes: current %d high %d\n",
490 fClientDetachedBytes, fHighWaterClientDetachedBytes); 539 fClientDetachedBytes, fHighWaterClientDetachedBytes);
491 } 540 }
492 541
493 #endif 542 #endif
494 543
495 /////////////////////////////////////////////////////////////////////////////// 544 ///////////////////////////////////////////////////////////////////////////////
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698