blob: e73cb9a46dc927f9eaa54dc191a8916c0317cb68 [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() {
24 fResource->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +000025}
26
27#if GR_DEBUG
bsalomon@google.com50398bf2011-07-26 20:45:30 +000028void GrResourceEntry::validate() const {
reed@google.comac10a2d2010-12-22 21:39:39 +000029 GrAssert(fLockCount >= 0);
bsalomon@google.com50398bf2011-07-26 20:45:30 +000030 GrAssert(fResource);
31 fResource->validate();
reed@google.comac10a2d2010-12-22 21:39:39 +000032}
33#endif
34
35///////////////////////////////////////////////////////////////////////////////
36
bsalomon@google.com50398bf2011-07-26 20:45:30 +000037GrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) :
reed@google.comac10a2d2010-12-22 21:39:39 +000038 fMaxCount(maxCount),
39 fMaxBytes(maxBytes) {
40 fEntryCount = 0;
41 fEntryBytes = 0;
42 fClientDetachedCount = 0;
43 fClientDetachedBytes = 0;
44
45 fHead = fTail = NULL;
46}
47
bsalomon@google.com50398bf2011-07-26 20:45:30 +000048GrResourceCache::~GrResourceCache() {
49 GrAutoResourceCacheValidate atcv(this);
reed@google.com01804b42011-01-18 21:50:41 +000050
bsalomon@google.com8fe72472011-03-30 21:26:44 +000051 this->removeAll();
reed@google.comac10a2d2010-12-22 21:39:39 +000052}
53
bsalomon@google.com50398bf2011-07-26 20:45:30 +000054void GrResourceCache::getLimits(int* maxResources, size_t* maxResourceBytes) const{
55 if (maxResources) {
56 *maxResources = fMaxCount;
reed@google.com01804b42011-01-18 21:50:41 +000057 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +000058 if (maxResourceBytes) {
59 *maxResourceBytes = fMaxBytes;
reed@google.com01804b42011-01-18 21:50:41 +000060 }
61}
62
bsalomon@google.com50398bf2011-07-26 20:45:30 +000063void GrResourceCache::setLimits(int maxResources, size_t maxResourceBytes) {
64 bool smaller = (maxResources < fMaxCount) || (maxResourceBytes < fMaxBytes);
reed@google.com01804b42011-01-18 21:50:41 +000065
bsalomon@google.com50398bf2011-07-26 20:45:30 +000066 fMaxCount = maxResources;
67 fMaxBytes = maxResourceBytes;
reed@google.com01804b42011-01-18 21:50:41 +000068
69 if (smaller) {
70 this->purgeAsNeeded();
71 }
72}
73
bsalomon@google.com50398bf2011-07-26 20:45:30 +000074void GrResourceCache::internalDetach(GrResourceEntry* entry,
reed@google.comac10a2d2010-12-22 21:39:39 +000075 bool clientDetach) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +000076 GrResourceEntry* prev = entry->fPrev;
77 GrResourceEntry* next = entry->fNext;
reed@google.comac10a2d2010-12-22 21:39:39 +000078
79 if (prev) {
80 prev->fNext = next;
81 } else {
82 fHead = next;
83 }
84 if (next) {
85 next->fPrev = prev;
86 } else {
87 fTail = prev;
88 }
89
90 // update our stats
91 if (clientDetach) {
92 fClientDetachedCount += 1;
bsalomon@google.com50398bf2011-07-26 20:45:30 +000093 fClientDetachedBytes += entry->resource()->sizeInBytes();
reed@google.comac10a2d2010-12-22 21:39:39 +000094 } else {
95 fEntryCount -= 1;
bsalomon@google.com50398bf2011-07-26 20:45:30 +000096 fEntryBytes -= entry->resource()->sizeInBytes();
reed@google.comac10a2d2010-12-22 21:39:39 +000097 }
98}
99
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000100void GrResourceCache::attachToHead(GrResourceEntry* entry,
reed@google.comac10a2d2010-12-22 21:39:39 +0000101 bool clientReattach) {
102 entry->fPrev = NULL;
103 entry->fNext = fHead;
104 if (fHead) {
105 fHead->fPrev = entry;
106 }
107 fHead = entry;
108 if (NULL == fTail) {
109 fTail = entry;
110 }
111
112 // update our stats
113 if (clientReattach) {
114 fClientDetachedCount -= 1;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000115 fClientDetachedBytes -= entry->resource()->sizeInBytes();
reed@google.comac10a2d2010-12-22 21:39:39 +0000116 } else {
117 fEntryCount += 1;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000118 fEntryBytes += entry->resource()->sizeInBytes();
reed@google.comac10a2d2010-12-22 21:39:39 +0000119 }
120}
121
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000122class GrResourceCache::Key {
123 typedef GrResourceEntry T;
reed@google.comac10a2d2010-12-22 21:39:39 +0000124
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000125 const GrResourceKey& fKey;
reed@google.comac10a2d2010-12-22 21:39:39 +0000126public:
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000127 Key(const GrResourceKey& key) : fKey(key) {}
reed@google.comac10a2d2010-12-22 21:39:39 +0000128
129 uint32_t getHash() const { return fKey.hashIndex(); }
reed@google.com01804b42011-01-18 21:50:41 +0000130
reed@google.comac10a2d2010-12-22 21:39:39 +0000131 static bool LT(const T& entry, const Key& key) {
132 return entry.key() < key.fKey;
133 }
134 static bool EQ(const T& entry, const Key& key) {
135 return entry.key() == key.fKey;
136 }
137#if GR_DEBUG
138 static uint32_t GetHash(const T& entry) {
139 return entry.key().hashIndex();
140 }
141 static bool LT(const T& a, const T& b) {
142 return a.key() < b.key();
143 }
144 static bool EQ(const T& a, const T& b) {
145 return a.key() == b.key();
146 }
147#endif
148};
149
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000150GrResourceEntry* GrResourceCache::findAndLock(const GrResourceKey& key) {
151 GrAutoResourceCacheValidate atcv(this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000152
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000153 GrResourceEntry* entry = fCache.find(key);
reed@google.comac10a2d2010-12-22 21:39:39 +0000154 if (entry) {
155 this->internalDetach(entry, false);
156 this->attachToHead(entry, false);
157 // mark the entry as "busy" so it doesn't get purged
158 entry->lock();
159 }
160 return entry;
161}
162
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000163GrResourceEntry* GrResourceCache::createAndLock(const GrResourceKey& key,
164 GrResource* resource) {
165 GrAutoResourceCacheValidate atcv(this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000166
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000167 GrResourceEntry* entry = new GrResourceEntry(key, resource);
reed@google.comac10a2d2010-12-22 21:39:39 +0000168
169 this->attachToHead(entry, false);
170 fCache.insert(key, entry);
171
172#if GR_DUMP_TEXTURE_UPLOAD
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000173 GrPrintf("--- add resource to cache %p, count=%d bytes= %d %d\n",
174 entry, fEntryCount, resource->sizeInBytes(), fEntryBytes);
reed@google.comac10a2d2010-12-22 21:39:39 +0000175#endif
176
177 // mark the entry as "busy" so it doesn't get purged
178 entry->lock();
179 this->purgeAsNeeded();
180 return entry;
181}
182
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000183void GrResourceCache::detach(GrResourceEntry* entry) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000184 internalDetach(entry, true);
185 fCache.remove(entry->fKey, entry);
186}
187
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000188void GrResourceCache::reattachAndUnlock(GrResourceEntry* entry) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000189 attachToHead(entry, true);
190 fCache.insert(entry->key(), entry);
191 unlock(entry);
192}
193
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000194void GrResourceCache::unlock(GrResourceEntry* entry) {
195 GrAutoResourceCacheValidate atcv(this);
reed@google.com01804b42011-01-18 21:50:41 +0000196
reed@google.comac10a2d2010-12-22 21:39:39 +0000197 GrAssert(entry);
198 GrAssert(entry->isLocked());
199 GrAssert(fCache.find(entry->key()));
200
201 entry->unlock();
202 this->purgeAsNeeded();
203}
204
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000205void GrResourceCache::purgeAsNeeded() {
206 GrAutoResourceCacheValidate atcv(this);
reed@google.com01804b42011-01-18 21:50:41 +0000207
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000208 GrResourceEntry* entry = fTail;
reed@google.comac10a2d2010-12-22 21:39:39 +0000209 while (entry) {
210 if (fEntryCount <= fMaxCount && fEntryBytes <= fMaxBytes) {
211 break;
212 }
213
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000214 GrResourceEntry* prev = entry->fPrev;
reed@google.comac10a2d2010-12-22 21:39:39 +0000215 if (!entry->isLocked()) {
216 // remove from our cache
217 fCache.remove(entry->fKey, entry);
reed@google.com01804b42011-01-18 21:50:41 +0000218
reed@google.comac10a2d2010-12-22 21:39:39 +0000219 // remove from our llist
220 this->internalDetach(entry, false);
221
222#if GR_DUMP_TEXTURE_UPLOAD
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000223 GrPrintf("--- ~resource from cache %p [%d %d]\n", entry->resource(),
224 entry->resource()->width(),
225 entry->resource()->height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000226#endif
227 delete entry;
228 }
229 entry = prev;
230 }
231}
232
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000233void GrResourceCache::removeAll() {
reed@google.comac10a2d2010-12-22 21:39:39 +0000234 GrAssert(!fClientDetachedCount);
235 GrAssert(!fClientDetachedBytes);
reed@google.com01804b42011-01-18 21:50:41 +0000236
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000237 GrResourceEntry* entry = fHead;
reed@google.comac10a2d2010-12-22 21:39:39 +0000238 while (entry) {
239 GrAssert(!entry->isLocked());
240
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000241 GrResourceEntry* next = entry->fNext;
reed@google.comac10a2d2010-12-22 21:39:39 +0000242 delete entry;
243 entry = next;
244 }
245
246 fCache.removeAll();
247 fHead = fTail = NULL;
248 fEntryCount = 0;
249 fEntryBytes = 0;
250}
251
252///////////////////////////////////////////////////////////////////////////////
253
254#if GR_DEBUG
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000255static int countMatches(const GrResourceEntry* head, const GrResourceEntry* target) {
256 const GrResourceEntry* entry = head;
reed@google.comac10a2d2010-12-22 21:39:39 +0000257 int count = 0;
258 while (entry) {
259 if (target == entry) {
260 count += 1;
261 }
262 entry = entry->next();
263 }
264 return count;
265}
266
reed@google.comb89a6432011-02-07 13:20:30 +0000267#if GR_DEBUG
268static bool both_zero_or_nonzero(int count, size_t bytes) {
269 return (count == 0 && bytes == 0) || (count > 0 && bytes > 0);
270}
271#endif
272
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000273void GrResourceCache::validate() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000274 GrAssert(!fHead == !fTail);
reed@google.comb89a6432011-02-07 13:20:30 +0000275 GrAssert(both_zero_or_nonzero(fEntryCount, fEntryBytes));
276 GrAssert(both_zero_or_nonzero(fClientDetachedCount, fClientDetachedBytes));
reed@google.comac10a2d2010-12-22 21:39:39 +0000277 GrAssert(fClientDetachedBytes <= fEntryBytes);
278 GrAssert(fClientDetachedCount <= fEntryCount);
279 GrAssert((fEntryCount - fClientDetachedCount) == fCache.count());
reed@google.com01804b42011-01-18 21:50:41 +0000280
reed@google.comac10a2d2010-12-22 21:39:39 +0000281 fCache.validate();
282
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000283 GrResourceEntry* entry = fHead;
reed@google.comac10a2d2010-12-22 21:39:39 +0000284 int count = 0;
285 size_t bytes = 0;
286 while (entry) {
287 entry->validate();
288 GrAssert(fCache.find(entry->key()));
289 count += 1;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000290 bytes += entry->resource()->sizeInBytes();
reed@google.comac10a2d2010-12-22 21:39:39 +0000291 entry = entry->fNext;
292 }
293 GrAssert(count == fEntryCount - fClientDetachedCount);
294 GrAssert(bytes == fEntryBytes - fClientDetachedBytes);
295
296 count = 0;
297 for (entry = fTail; entry; entry = entry->fPrev) {
298 count += 1;
299 }
300 GrAssert(count == fEntryCount - fClientDetachedCount);
301
302 for (int i = 0; i < count; i++) {
303 int matches = countMatches(fHead, fCache.getArray()[i]);
304 GrAssert(1 == matches);
305 }
306}
307#endif
308
309