blob: be796247abb769ce0c30648876c4923e8aa3fd81 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.comac10a2d2010-12-22 21:39:39 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2010 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@google.comac10a2d2010-12-22 21:39:39 +00007 */
8
9
epoger@google.comec3ed6a2011-07-28 14:26:00 +000010
bsalomon@google.com50398bf2011-07-26 20:45:30 +000011#include "GrResourceCache.h"
12#include "GrResource.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000013
bsalomon@google.com50398bf2011-07-26 20:45:30 +000014GrResourceEntry::GrResourceEntry(const GrResourceKey& key, GrResource* resource)
15 : fKey(key), fResource(resource) {
reed@google.comac10a2d2010-12-22 21:39:39 +000016 fLockCount = 0;
17 fPrev = fNext = NULL;
18
bsalomon@google.com50398bf2011-07-26 20:45:30 +000019 // we assume ownership of the resource, and will unref it when we die
20 GrAssert(resource);
reed@google.comac10a2d2010-12-22 21:39:39 +000021}
22
bsalomon@google.com50398bf2011-07-26 20:45:30 +000023GrResourceEntry::~GrResourceEntry() {
robertphillips@google.com521eaf82012-08-22 11:03:19 +000024 fResource->setCacheEntry(NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +000025 fResource->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +000026}
27
28#if GR_DEBUG
bsalomon@google.com50398bf2011-07-26 20:45:30 +000029void GrResourceEntry::validate() const {
reed@google.comac10a2d2010-12-22 21:39:39 +000030 GrAssert(fLockCount >= 0);
bsalomon@google.com50398bf2011-07-26 20:45:30 +000031 GrAssert(fResource);
robertphillips@google.com1f47f4f2012-08-16 14:49:16 +000032 GrAssert(fResource->getCacheEntry() == this);
bsalomon@google.com50398bf2011-07-26 20:45:30 +000033 fResource->validate();
reed@google.comac10a2d2010-12-22 21:39:39 +000034}
35#endif
36
37///////////////////////////////////////////////////////////////////////////////
38
bsalomon@google.com07fc0d12012-06-22 15:15:59 +000039GrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) :
40 fMaxCount(maxCount),
41 fMaxBytes(maxBytes) {
robertphillips@google.com5f9f2f52012-08-22 10:57:05 +000042#if GR_DEBUG
43 fHighWaterEntryCount = 0;
44 fHighWaterUnlockedEntryCount = 0;
45 fHighWaterEntryBytes = 0;
46 fHighWaterClientDetachedCount = 0;
47 fHighWaterClientDetachedBytes = 0;
48#endif
49
50 fEntryCount = 0;
51 fUnlockedEntryCount = 0;
52 fEntryBytes = 0;
53 fClientDetachedCount = 0;
54 fClientDetachedBytes = 0;
reed@google.comac10a2d2010-12-22 21:39:39 +000055
bsalomon@google.coma5a1da82011-08-05 14:02:41 +000056 fPurging = false;
reed@google.comac10a2d2010-12-22 21:39:39 +000057}
58
bsalomon@google.com50398bf2011-07-26 20:45:30 +000059GrResourceCache::~GrResourceCache() {
60 GrAutoResourceCacheValidate atcv(this);
reed@google.com01804b42011-01-18 21:50:41 +000061
bsalomon@google.com8fe72472011-03-30 21:26:44 +000062 this->removeAll();
reed@google.comac10a2d2010-12-22 21:39:39 +000063}
64
bsalomon@google.com07fc0d12012-06-22 15:15:59 +000065void GrResourceCache::getLimits(int* maxResources, size_t* maxResourceBytes) const{
66 if (maxResources) {
67 *maxResources = fMaxCount;
68 }
69 if (maxResourceBytes) {
70 *maxResourceBytes = fMaxBytes;
71 }
72}
reed@google.com01804b42011-01-18 21:50:41 +000073
bsalomon@google.com07fc0d12012-06-22 15:15:59 +000074void GrResourceCache::setLimits(int maxResources, size_t maxResourceBytes) {
75 bool smaller = (maxResources < fMaxCount) || (maxResourceBytes < fMaxBytes);
76
77 fMaxCount = maxResources;
bsalomon@google.com50398bf2011-07-26 20:45:30 +000078 fMaxBytes = maxResourceBytes;
reed@google.com01804b42011-01-18 21:50:41 +000079
80 if (smaller) {
81 this->purgeAsNeeded();
82 }
83}
84
bsalomon@google.com50398bf2011-07-26 20:45:30 +000085void GrResourceCache::internalDetach(GrResourceEntry* entry,
reed@google.comac10a2d2010-12-22 21:39:39 +000086 bool clientDetach) {
robertphillips@google.com521eaf82012-08-22 11:03:19 +000087 fList.remove(entry);
reed@google.comac10a2d2010-12-22 21:39:39 +000088
bsalomon@google.coma5a1da82011-08-05 14:02:41 +000089 if (!entry->isLocked()) {
90 --fUnlockedEntryCount;
91 }
reed@google.comac10a2d2010-12-22 21:39:39 +000092
93 // update our stats
94 if (clientDetach) {
95 fClientDetachedCount += 1;
bsalomon@google.com50398bf2011-07-26 20:45:30 +000096 fClientDetachedBytes += entry->resource()->sizeInBytes();
robertphillips@google.com5f9f2f52012-08-22 10:57:05 +000097
98#if GR_DEBUG
99 if (fHighWaterClientDetachedCount < fClientDetachedCount) {
100 fHighWaterClientDetachedCount = fClientDetachedCount;
101 }
102 if (fHighWaterClientDetachedBytes < fClientDetachedBytes) {
103 fHighWaterClientDetachedBytes = fClientDetachedBytes;
104 }
105#endif
106
reed@google.comac10a2d2010-12-22 21:39:39 +0000107 } else {
108 fEntryCount -= 1;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000109 fEntryBytes -= entry->resource()->sizeInBytes();
reed@google.comac10a2d2010-12-22 21:39:39 +0000110 }
111}
112
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000113void GrResourceCache::attachToHead(GrResourceEntry* entry,
reed@google.comac10a2d2010-12-22 21:39:39 +0000114 bool clientReattach) {
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000115 fList.addToHead(entry);
116
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000117 if (!entry->isLocked()) {
118 ++fUnlockedEntryCount;
robertphillips@google.com5f9f2f52012-08-22 10:57:05 +0000119#if GR_DEBUG
120 if (fHighWaterUnlockedEntryCount < fUnlockedEntryCount) {
121 fHighWaterUnlockedEntryCount = fUnlockedEntryCount;
122 }
123#endif
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000124 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000125
126 // update our stats
127 if (clientReattach) {
128 fClientDetachedCount -= 1;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000129 fClientDetachedBytes -= entry->resource()->sizeInBytes();
reed@google.comac10a2d2010-12-22 21:39:39 +0000130 } else {
131 fEntryCount += 1;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000132 fEntryBytes += entry->resource()->sizeInBytes();
robertphillips@google.com5f9f2f52012-08-22 10:57:05 +0000133
134#if GR_DEBUG
135 if (fHighWaterEntryCount < fEntryCount) {
136 fHighWaterEntryCount = fEntryCount;
137 }
138 if (fHighWaterEntryBytes < fEntryBytes) {
139 fHighWaterEntryBytes = fEntryBytes;
140 }
141#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000142 }
143}
144
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000145class GrResourceCache::Key {
146 typedef GrResourceEntry T;
reed@google.comac10a2d2010-12-22 21:39:39 +0000147
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000148 const GrResourceKey& fKey;
reed@google.comac10a2d2010-12-22 21:39:39 +0000149public:
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000150 Key(const GrResourceKey& key) : fKey(key) {}
reed@google.comac10a2d2010-12-22 21:39:39 +0000151
152 uint32_t getHash() const { return fKey.hashIndex(); }
reed@google.com01804b42011-01-18 21:50:41 +0000153
reed@google.comac10a2d2010-12-22 21:39:39 +0000154 static bool LT(const T& entry, const Key& key) {
155 return entry.key() < key.fKey;
156 }
157 static bool EQ(const T& entry, const Key& key) {
158 return entry.key() == key.fKey;
159 }
160#if GR_DEBUG
161 static uint32_t GetHash(const T& entry) {
162 return entry.key().hashIndex();
163 }
164 static bool LT(const T& a, const T& b) {
165 return a.key() < b.key();
166 }
167 static bool EQ(const T& a, const T& b) {
168 return a.key() == b.key();
169 }
170#endif
171};
172
robertphillips@google.com1f47f4f2012-08-16 14:49:16 +0000173GrResource* GrResourceCache::findAndLock(const GrResourceKey& key,
174 LockType type) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000175 GrAutoResourceCacheValidate atcv(this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000176
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000177 GrResourceEntry* entry = fCache.find(key);
robertphillips@google.com1f47f4f2012-08-16 14:49:16 +0000178 if (NULL == entry) {
179 return NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000180 }
robertphillips@google.com1f47f4f2012-08-16 14:49:16 +0000181
182 this->internalDetach(entry, false);
183 // mark the entry as "busy" so it doesn't get purged
184 // do this between detach and attach for locked count tracking
185 if (kNested_LockType == type || !entry->isLocked()) {
186 entry->lock();
187 }
188 this->attachToHead(entry, false);
189
190 return entry->fResource;
reed@google.comac10a2d2010-12-22 21:39:39 +0000191}
192
bsalomon@google.comfb309512011-11-30 14:13:48 +0000193bool GrResourceCache::hasKey(const GrResourceKey& key) const {
194 return NULL != fCache.find(key);
195}
196
robertphillips@google.com15c0fea2012-06-22 12:41:43 +0000197GrResourceEntry* GrResourceCache::create(const GrResourceKey& key,
198 GrResource* resource,
robertphillips@google.com386319e2012-06-27 14:59:18 +0000199 bool lock,
200 bool clientReattach) {
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000201 // we don't expect to create new resources during a purge. In theory
202 // this could cause purgeAsNeeded() into an infinite loop (e.g.
203 // each resource destroyed creates and locks 2 resources and
204 // unlocks 1 thereby causing a new purge).
205 GrAssert(!fPurging);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000206 GrAutoResourceCacheValidate atcv(this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000207
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000208 GrResourceEntry* entry = SkNEW_ARGS(GrResourceEntry, (key, resource));
robertphillips@google.com1f47f4f2012-08-16 14:49:16 +0000209 resource->setCacheEntry(entry);
210
robertphillips@google.com15c0fea2012-06-22 12:41:43 +0000211 if (lock) {
212 // mark the entry as "busy" so it doesn't get purged
213 // do this before attach for locked count tracking
214 entry->lock();
215 }
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000216
robertphillips@google.com386319e2012-06-27 14:59:18 +0000217 this->attachToHead(entry, clientReattach);
reed@google.comac10a2d2010-12-22 21:39:39 +0000218 fCache.insert(key, entry);
219
220#if GR_DUMP_TEXTURE_UPLOAD
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000221 GrPrintf("--- add resource to cache %p, count=%d bytes= %d %d\n",
222 entry, fEntryCount, resource->sizeInBytes(), fEntryBytes);
reed@google.comac10a2d2010-12-22 21:39:39 +0000223#endif
224
reed@google.comac10a2d2010-12-22 21:39:39 +0000225 this->purgeAsNeeded();
226 return entry;
227}
228
robertphillips@google.com1f47f4f2012-08-16 14:49:16 +0000229void GrResourceCache::createAndLock(const GrResourceKey& key,
230 GrResource* resource) {
231 GrAssert(NULL == resource->getCacheEntry());
232 this->create(key, resource, true, false);
robertphillips@google.com15c0fea2012-06-22 12:41:43 +0000233}
234
235void GrResourceCache::attach(const GrResourceKey& key,
236 GrResource* resource) {
robertphillips@google.com1f47f4f2012-08-16 14:49:16 +0000237 GrAssert(NULL == resource->getCacheEntry());
robertphillips@google.com386319e2012-06-27 14:59:18 +0000238 this->create(key, resource, false, true);
robertphillips@google.com15c0fea2012-06-22 12:41:43 +0000239}
240
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000241void GrResourceCache::makeExclusive(GrResourceEntry* entry) {
bsalomon@google.come9a98942011-08-22 17:06:16 +0000242 GrAutoResourceCacheValidate atcv(this);
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000243
robertphillips@google.com15c0fea2012-06-22 12:41:43 +0000244 this->internalDetach(entry, true);
reed@google.comac10a2d2010-12-22 21:39:39 +0000245 fCache.remove(entry->fKey, entry);
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000246
247#if GR_DEBUG
248 fExclusiveList.addToHead(entry);
249#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000250}
251
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000252void GrResourceCache::removeInvalidResource(GrResourceEntry* entry) {
253 // If the resource went invalid while it was detached then purge it
254 // This can happen when a 3D context was lost,
255 // the client called GrContext::contextDestroyed() to notify Gr,
256 // and then later an SkGpuDevice's destructor releases its backing
257 // texture (which was invalidated at contextDestroyed time).
258 fClientDetachedCount -= 1;
259 fEntryCount -= 1;
260 size_t size = entry->resource()->sizeInBytes();
261 fClientDetachedBytes -= size;
262 fEntryBytes -= size;
robertphillips@google.com15c0fea2012-06-22 12:41:43 +0000263}
264
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000265void GrResourceCache::makeNonExclusive(GrResourceEntry* entry) {
bsalomon@google.com60879752011-09-15 20:43:53 +0000266 GrAutoResourceCacheValidate atcv(this);
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000267
268#if GR_DEBUG
269 fExclusiveList.remove(entry);
270#endif
271
bsalomon@google.com60879752011-09-15 20:43:53 +0000272 if (entry->resource()->isValid()) {
273 attachToHead(entry, true);
274 fCache.insert(entry->key(), entry);
275 } else {
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000276 this->removeInvalidResource(entry);
bsalomon@google.com60879752011-09-15 20:43:53 +0000277 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000278}
279
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000280void GrResourceCache::unlock(GrResourceEntry* entry) {
281 GrAutoResourceCacheValidate atcv(this);
reed@google.com01804b42011-01-18 21:50:41 +0000282
reed@google.comac10a2d2010-12-22 21:39:39 +0000283 GrAssert(entry);
284 GrAssert(entry->isLocked());
285 GrAssert(fCache.find(entry->key()));
286
287 entry->unlock();
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000288 if (!entry->isLocked()) {
289 ++fUnlockedEntryCount;
robertphillips@google.com5f9f2f52012-08-22 10:57:05 +0000290#if GR_DEBUG
291 if (fHighWaterUnlockedEntryCount < fUnlockedEntryCount) {
292 fHighWaterUnlockedEntryCount = fUnlockedEntryCount;
293 }
294#endif
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000295 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000296 this->purgeAsNeeded();
297}
298
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000299/**
300 * Destroying a resource may potentially trigger the unlock of additional
301 * resources which in turn will trigger a nested purge. We block the nested
302 * purge using the fPurging variable. However, the initial purge will keep
303 * looping until either all resources in the cache are unlocked or we've met
304 * the budget. There is an assertion in createAndLock to check against a
305 * resource's destructor inserting new resources into the cache. If these
306 * new resources were unlocked before purgeAsNeeded completed it could
307 * potentially make purgeAsNeeded loop infinitely.
308 */
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000309void GrResourceCache::purgeAsNeeded() {
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000310 if (!fPurging) {
311 fPurging = true;
312 bool withinBudget = false;
313 do {
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000314 GrResourceEntry* entry = fList.fTail;
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000315 while (entry && fUnlockedEntryCount) {
bsalomon@google.come9a98942011-08-22 17:06:16 +0000316 GrAutoResourceCacheValidate atcv(this);
bsalomon@google.com07fc0d12012-06-22 15:15:59 +0000317 if (fEntryCount <= fMaxCount && fEntryBytes <= fMaxBytes) {
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000318 withinBudget = true;
319 break;
320 }
reed@google.com01804b42011-01-18 21:50:41 +0000321
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000322 GrResourceEntry* prev = entry->fPrev;
323 if (!entry->isLocked()) {
324 // remove from our cache
325 fCache.remove(entry->fKey, entry);
reed@google.comac10a2d2010-12-22 21:39:39 +0000326
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000327 // remove from our llist
328 this->internalDetach(entry, false);
reed@google.com01804b42011-01-18 21:50:41 +0000329
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000330 #if GR_DUMP_TEXTURE_UPLOAD
331 GrPrintf("--- ~resource from cache %p [%d %d]\n",
332 entry->resource(),
333 entry->resource()->width(),
334 entry->resource()->height());
335 #endif
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000336
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000337 delete entry;
338 }
339 entry = prev;
340 }
341 } while (!withinBudget && fUnlockedEntryCount);
342 fPurging = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000343 }
344}
345
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000346void GrResourceCache::removeAll() {
bsalomon@google.come9a98942011-08-22 17:06:16 +0000347 GrAutoResourceCacheValidate atcv(this);
reed@google.com01804b42011-01-18 21:50:41 +0000348
bsalomon@google.come9a98942011-08-22 17:06:16 +0000349 // we can have one GrResource holding a lock on another
350 // so we don't want to just do a simple loop kicking each
351 // entry out. Instead change the budget and purge.
reed@google.comac10a2d2010-12-22 21:39:39 +0000352
bsalomon@google.come9a98942011-08-22 17:06:16 +0000353 int savedMaxBytes = fMaxBytes;
bsalomon@google.com07fc0d12012-06-22 15:15:59 +0000354 int savedMaxCount = fMaxCount;
355 fMaxBytes = (size_t) -1;
356 fMaxCount = 0;
bsalomon@google.come9a98942011-08-22 17:06:16 +0000357 this->purgeAsNeeded();
358
twiz@google.com0ec107f2012-02-21 19:15:53 +0000359#if GR_DEBUG
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000360 GrAssert(fExclusiveList.countEntries() == fClientDetachedCount);
361 GrAssert(fExclusiveList.countBytes() == fClientDetachedBytes);
bsalomon@google.come9a98942011-08-22 17:06:16 +0000362 GrAssert(!fUnlockedEntryCount);
twiz@google.com0ec107f2012-02-21 19:15:53 +0000363 if (!fCache.count()) {
364 // Items may have been detached from the cache (such as the backing
365 // texture for an SkGpuDevice). The above purge would not have removed
366 // them.
367 GrAssert(fEntryCount == fClientDetachedCount);
368 GrAssert(fEntryBytes == fClientDetachedBytes);
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000369 GrAssert(fList.isEmpty());
twiz@google.com0ec107f2012-02-21 19:15:53 +0000370 }
371#endif
bsalomon@google.come9a98942011-08-22 17:06:16 +0000372
373 fMaxBytes = savedMaxBytes;
bsalomon@google.com07fc0d12012-06-22 15:15:59 +0000374 fMaxCount = savedMaxCount;
reed@google.comac10a2d2010-12-22 21:39:39 +0000375}
376
377///////////////////////////////////////////////////////////////////////////////
378
379#if GR_DEBUG
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000380static int countMatches(const GrResourceEntry* head, const GrResourceEntry* target) {
381 const GrResourceEntry* entry = head;
reed@google.comac10a2d2010-12-22 21:39:39 +0000382 int count = 0;
383 while (entry) {
384 if (target == entry) {
385 count += 1;
386 }
387 entry = entry->next();
388 }
389 return count;
390}
391
reed@google.comb89a6432011-02-07 13:20:30 +0000392static bool both_zero_or_nonzero(int count, size_t bytes) {
393 return (count == 0 && bytes == 0) || (count > 0 && bytes > 0);
394}
reed@google.comb89a6432011-02-07 13:20:30 +0000395
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000396void GrResourceCache::validate() const {
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000397 GrAssert(!fList.fHead == !fList.fTail);
reed@google.comb89a6432011-02-07 13:20:30 +0000398 GrAssert(both_zero_or_nonzero(fEntryCount, fEntryBytes));
399 GrAssert(both_zero_or_nonzero(fClientDetachedCount, fClientDetachedBytes));
reed@google.comac10a2d2010-12-22 21:39:39 +0000400 GrAssert(fClientDetachedBytes <= fEntryBytes);
401 GrAssert(fClientDetachedCount <= fEntryCount);
402 GrAssert((fEntryCount - fClientDetachedCount) == fCache.count());
reed@google.com01804b42011-01-18 21:50:41 +0000403
reed@google.comac10a2d2010-12-22 21:39:39 +0000404 fCache.validate();
405
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000406 GrResourceEntry* entry = fList.fHead;
reed@google.comac10a2d2010-12-22 21:39:39 +0000407 int count = 0;
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000408 int unlockCount = 0;
reed@google.comac10a2d2010-12-22 21:39:39 +0000409 while (entry) {
410 entry->validate();
411 GrAssert(fCache.find(entry->key()));
412 count += 1;
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000413 if (!entry->isLocked()) {
414 unlockCount += 1;
415 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000416 entry = entry->fNext;
417 }
418 GrAssert(count == fEntryCount - fClientDetachedCount);
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000419
420 size_t bytes = fList.countBytes();
reed@google.comac10a2d2010-12-22 21:39:39 +0000421 GrAssert(bytes == fEntryBytes - fClientDetachedBytes);
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000422
423 bytes = fExclusiveList.countBytes();
424 GrAssert(bytes == fClientDetachedBytes);
425
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000426 GrAssert(unlockCount == fUnlockedEntryCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000427
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000428 GrAssert(fList.countEntries() == fEntryCount - fClientDetachedCount);
429
430 GrAssert(fExclusiveList.countEntries() == fClientDetachedCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000431
432 for (int i = 0; i < count; i++) {
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000433 int matches = countMatches(fList.fHead, fCache.getArray()[i]);
reed@google.comac10a2d2010-12-22 21:39:39 +0000434 GrAssert(1 == matches);
435 }
436}
robertphillips@google.com5f9f2f52012-08-22 10:57:05 +0000437
438void GrResourceCache::printStats() const {
439 SkDebugf("Budget: %d items %d bytes\n", fMaxCount, fMaxBytes);
440 SkDebugf("\t\tEntry Count: current %d high %d\n",
441 fEntryCount, fHighWaterEntryCount);
442 SkDebugf("\t\tUnlocked Entry Count: current %d high %d\n",
443 fUnlockedEntryCount, fHighWaterUnlockedEntryCount);
444 SkDebugf("\t\tEntry Bytes: current %d high %d\n",
445 fEntryBytes, fHighWaterEntryBytes);
446 SkDebugf("\t\tDetached Entry Count: current %d high %d\n",
447 fClientDetachedCount, fHighWaterClientDetachedCount);
448 SkDebugf("\t\tDetached Bytes: current %d high %d\n",
449 fClientDetachedBytes, fHighWaterClientDetachedBytes);
450}
451
reed@google.comac10a2d2010-12-22 21:39:39 +0000452#endif
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000453
454///////////////////////////////////////////////////////////////////////////////
455void GrDLinkedList::remove(GrResourceEntry* entry) {
456 GrAssert(this->isInList(entry));
457
458 GrResourceEntry* prev = entry->fPrev;
459 GrResourceEntry* next = entry->fNext;
460
461 if (prev) {
462 prev->fNext = next;
463 } else {
464 fHead = next;
465 }
466 if (next) {
467 next->fPrev = prev;
468 } else {
469 fTail = prev;
470 }
471
472 entry->fPrev = NULL;
473 entry->fNext = NULL;
474}
475
476void GrDLinkedList::addToHead(GrResourceEntry* entry) {
477 GrAssert(NULL == entry->fPrev && NULL == entry->fNext);
478
479 entry->fPrev = NULL;
480 entry->fNext = fHead;
481 if (fHead) {
482 fHead->fPrev = entry;
483 }
484 fHead = entry;
485 if (NULL == fTail) {
486 fTail = entry;
487 }
488}
489
490#if GR_DEBUG
491
492bool GrDLinkedList::isInList(const GrResourceEntry* entry) const {
493
494 for (GrResourceEntry* cur = fHead; NULL != cur; cur = cur->fNext) {
495 if (entry == cur) {
496 return true;
497 }
498 }
499
500 return false;
501}
502
503int GrDLinkedList::countEntries() const {
504 int count = 0;
505 for (GrResourceEntry* entry = fTail; NULL != entry; entry = entry->fPrev) {
506 ++count;
507 }
508 return count;
509}
510
511size_t GrDLinkedList::countBytes() const {
512 size_t bytes = 0;
513 for (GrResourceEntry* entry = fTail; NULL != entry; entry = entry->fPrev) {
514 bytes += entry->resource()->sizeInBytes();
515 }
516 return bytes;
517}
518
519#endif // GR_DEBUG