blob: 15f9817026969d519f8f3a2fb742505bd12dc6e1 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
2 Copyright 2010 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
bsalomon@google.com50398bf2011-07-26 20:45:30 +000018#include "GrResourceCache.h"
19#include "GrResource.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000020
bsalomon@google.com50398bf2011-07-26 20:45:30 +000021GrResourceEntry::GrResourceEntry(const GrResourceKey& key, GrResource* resource)
22 : fKey(key), fResource(resource) {
reed@google.comac10a2d2010-12-22 21:39:39 +000023 fLockCount = 0;
24 fPrev = fNext = NULL;
25
bsalomon@google.com50398bf2011-07-26 20:45:30 +000026 // we assume ownership of the resource, and will unref it when we die
27 GrAssert(resource);
reed@google.comac10a2d2010-12-22 21:39:39 +000028}
29
bsalomon@google.com50398bf2011-07-26 20:45:30 +000030GrResourceEntry::~GrResourceEntry() {
31 fResource->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +000032}
33
34#if GR_DEBUG
bsalomon@google.com50398bf2011-07-26 20:45:30 +000035void GrResourceEntry::validate() const {
reed@google.comac10a2d2010-12-22 21:39:39 +000036 GrAssert(fLockCount >= 0);
bsalomon@google.com50398bf2011-07-26 20:45:30 +000037 GrAssert(fResource);
38 fResource->validate();
reed@google.comac10a2d2010-12-22 21:39:39 +000039}
40#endif
41
42///////////////////////////////////////////////////////////////////////////////
43
bsalomon@google.com50398bf2011-07-26 20:45:30 +000044GrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) :
reed@google.comac10a2d2010-12-22 21:39:39 +000045 fMaxCount(maxCount),
46 fMaxBytes(maxBytes) {
47 fEntryCount = 0;
48 fEntryBytes = 0;
49 fClientDetachedCount = 0;
50 fClientDetachedBytes = 0;
51
52 fHead = fTail = NULL;
53}
54
bsalomon@google.com50398bf2011-07-26 20:45:30 +000055GrResourceCache::~GrResourceCache() {
56 GrAutoResourceCacheValidate atcv(this);
reed@google.com01804b42011-01-18 21:50:41 +000057
bsalomon@google.com8fe72472011-03-30 21:26:44 +000058 this->removeAll();
reed@google.comac10a2d2010-12-22 21:39:39 +000059}
60
bsalomon@google.com50398bf2011-07-26 20:45:30 +000061void GrResourceCache::getLimits(int* maxResources, size_t* maxResourceBytes) const{
62 if (maxResources) {
63 *maxResources = fMaxCount;
reed@google.com01804b42011-01-18 21:50:41 +000064 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +000065 if (maxResourceBytes) {
66 *maxResourceBytes = fMaxBytes;
reed@google.com01804b42011-01-18 21:50:41 +000067 }
68}
69
bsalomon@google.com50398bf2011-07-26 20:45:30 +000070void GrResourceCache::setLimits(int maxResources, size_t maxResourceBytes) {
71 bool smaller = (maxResources < fMaxCount) || (maxResourceBytes < fMaxBytes);
reed@google.com01804b42011-01-18 21:50:41 +000072
bsalomon@google.com50398bf2011-07-26 20:45:30 +000073 fMaxCount = maxResources;
74 fMaxBytes = maxResourceBytes;
reed@google.com01804b42011-01-18 21:50:41 +000075
76 if (smaller) {
77 this->purgeAsNeeded();
78 }
79}
80
bsalomon@google.com50398bf2011-07-26 20:45:30 +000081void GrResourceCache::internalDetach(GrResourceEntry* entry,
reed@google.comac10a2d2010-12-22 21:39:39 +000082 bool clientDetach) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +000083 GrResourceEntry* prev = entry->fPrev;
84 GrResourceEntry* next = entry->fNext;
reed@google.comac10a2d2010-12-22 21:39:39 +000085
86 if (prev) {
87 prev->fNext = next;
88 } else {
89 fHead = next;
90 }
91 if (next) {
92 next->fPrev = prev;
93 } else {
94 fTail = prev;
95 }
96
97 // update our stats
98 if (clientDetach) {
99 fClientDetachedCount += 1;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000100 fClientDetachedBytes += entry->resource()->sizeInBytes();
reed@google.comac10a2d2010-12-22 21:39:39 +0000101 } else {
102 fEntryCount -= 1;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000103 fEntryBytes -= entry->resource()->sizeInBytes();
reed@google.comac10a2d2010-12-22 21:39:39 +0000104 }
105}
106
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000107void GrResourceCache::attachToHead(GrResourceEntry* entry,
reed@google.comac10a2d2010-12-22 21:39:39 +0000108 bool clientReattach) {
109 entry->fPrev = NULL;
110 entry->fNext = fHead;
111 if (fHead) {
112 fHead->fPrev = entry;
113 }
114 fHead = entry;
115 if (NULL == fTail) {
116 fTail = entry;
117 }
118
119 // update our stats
120 if (clientReattach) {
121 fClientDetachedCount -= 1;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000122 fClientDetachedBytes -= entry->resource()->sizeInBytes();
reed@google.comac10a2d2010-12-22 21:39:39 +0000123 } else {
124 fEntryCount += 1;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000125 fEntryBytes += entry->resource()->sizeInBytes();
reed@google.comac10a2d2010-12-22 21:39:39 +0000126 }
127}
128
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000129class GrResourceCache::Key {
130 typedef GrResourceEntry T;
reed@google.comac10a2d2010-12-22 21:39:39 +0000131
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000132 const GrResourceKey& fKey;
reed@google.comac10a2d2010-12-22 21:39:39 +0000133public:
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000134 Key(const GrResourceKey& key) : fKey(key) {}
reed@google.comac10a2d2010-12-22 21:39:39 +0000135
136 uint32_t getHash() const { return fKey.hashIndex(); }
reed@google.com01804b42011-01-18 21:50:41 +0000137
reed@google.comac10a2d2010-12-22 21:39:39 +0000138 static bool LT(const T& entry, const Key& key) {
139 return entry.key() < key.fKey;
140 }
141 static bool EQ(const T& entry, const Key& key) {
142 return entry.key() == key.fKey;
143 }
144#if GR_DEBUG
145 static uint32_t GetHash(const T& entry) {
146 return entry.key().hashIndex();
147 }
148 static bool LT(const T& a, const T& b) {
149 return a.key() < b.key();
150 }
151 static bool EQ(const T& a, const T& b) {
152 return a.key() == b.key();
153 }
154#endif
155};
156
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000157GrResourceEntry* GrResourceCache::findAndLock(const GrResourceKey& key) {
158 GrAutoResourceCacheValidate atcv(this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000159
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000160 GrResourceEntry* entry = fCache.find(key);
reed@google.comac10a2d2010-12-22 21:39:39 +0000161 if (entry) {
162 this->internalDetach(entry, false);
163 this->attachToHead(entry, false);
164 // mark the entry as "busy" so it doesn't get purged
165 entry->lock();
166 }
167 return entry;
168}
169
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000170GrResourceEntry* GrResourceCache::createAndLock(const GrResourceKey& key,
171 GrResource* resource) {
172 GrAutoResourceCacheValidate atcv(this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000173
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000174 GrResourceEntry* entry = new GrResourceEntry(key, resource);
reed@google.comac10a2d2010-12-22 21:39:39 +0000175
176 this->attachToHead(entry, false);
177 fCache.insert(key, entry);
178
179#if GR_DUMP_TEXTURE_UPLOAD
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000180 GrPrintf("--- add resource to cache %p, count=%d bytes= %d %d\n",
181 entry, fEntryCount, resource->sizeInBytes(), fEntryBytes);
reed@google.comac10a2d2010-12-22 21:39:39 +0000182#endif
183
184 // mark the entry as "busy" so it doesn't get purged
185 entry->lock();
186 this->purgeAsNeeded();
187 return entry;
188}
189
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000190void GrResourceCache::detach(GrResourceEntry* entry) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000191 internalDetach(entry, true);
192 fCache.remove(entry->fKey, entry);
193}
194
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000195void GrResourceCache::reattachAndUnlock(GrResourceEntry* entry) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000196 attachToHead(entry, true);
197 fCache.insert(entry->key(), entry);
198 unlock(entry);
199}
200
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000201void GrResourceCache::unlock(GrResourceEntry* entry) {
202 GrAutoResourceCacheValidate atcv(this);
reed@google.com01804b42011-01-18 21:50:41 +0000203
reed@google.comac10a2d2010-12-22 21:39:39 +0000204 GrAssert(entry);
205 GrAssert(entry->isLocked());
206 GrAssert(fCache.find(entry->key()));
207
208 entry->unlock();
209 this->purgeAsNeeded();
210}
211
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000212void GrResourceCache::purgeAsNeeded() {
213 GrAutoResourceCacheValidate atcv(this);
reed@google.com01804b42011-01-18 21:50:41 +0000214
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000215 GrResourceEntry* entry = fTail;
reed@google.comac10a2d2010-12-22 21:39:39 +0000216 while (entry) {
217 if (fEntryCount <= fMaxCount && fEntryBytes <= fMaxBytes) {
218 break;
219 }
220
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000221 GrResourceEntry* prev = entry->fPrev;
reed@google.comac10a2d2010-12-22 21:39:39 +0000222 if (!entry->isLocked()) {
223 // remove from our cache
224 fCache.remove(entry->fKey, entry);
reed@google.com01804b42011-01-18 21:50:41 +0000225
reed@google.comac10a2d2010-12-22 21:39:39 +0000226 // remove from our llist
227 this->internalDetach(entry, false);
228
229#if GR_DUMP_TEXTURE_UPLOAD
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000230 GrPrintf("--- ~resource from cache %p [%d %d]\n", entry->resource(),
231 entry->resource()->width(),
232 entry->resource()->height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000233#endif
234 delete entry;
235 }
236 entry = prev;
237 }
238}
239
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000240void GrResourceCache::removeAll() {
reed@google.comac10a2d2010-12-22 21:39:39 +0000241 GrAssert(!fClientDetachedCount);
242 GrAssert(!fClientDetachedBytes);
reed@google.com01804b42011-01-18 21:50:41 +0000243
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000244 GrResourceEntry* entry = fHead;
reed@google.comac10a2d2010-12-22 21:39:39 +0000245 while (entry) {
246 GrAssert(!entry->isLocked());
247
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000248 GrResourceEntry* next = entry->fNext;
reed@google.comac10a2d2010-12-22 21:39:39 +0000249 delete entry;
250 entry = next;
251 }
252
253 fCache.removeAll();
254 fHead = fTail = NULL;
255 fEntryCount = 0;
256 fEntryBytes = 0;
257}
258
259///////////////////////////////////////////////////////////////////////////////
260
261#if GR_DEBUG
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000262static int countMatches(const GrResourceEntry* head, const GrResourceEntry* target) {
263 const GrResourceEntry* entry = head;
reed@google.comac10a2d2010-12-22 21:39:39 +0000264 int count = 0;
265 while (entry) {
266 if (target == entry) {
267 count += 1;
268 }
269 entry = entry->next();
270 }
271 return count;
272}
273
reed@google.comb89a6432011-02-07 13:20:30 +0000274#if GR_DEBUG
275static bool both_zero_or_nonzero(int count, size_t bytes) {
276 return (count == 0 && bytes == 0) || (count > 0 && bytes > 0);
277}
278#endif
279
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000280void GrResourceCache::validate() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000281 GrAssert(!fHead == !fTail);
reed@google.comb89a6432011-02-07 13:20:30 +0000282 GrAssert(both_zero_or_nonzero(fEntryCount, fEntryBytes));
283 GrAssert(both_zero_or_nonzero(fClientDetachedCount, fClientDetachedBytes));
reed@google.comac10a2d2010-12-22 21:39:39 +0000284 GrAssert(fClientDetachedBytes <= fEntryBytes);
285 GrAssert(fClientDetachedCount <= fEntryCount);
286 GrAssert((fEntryCount - fClientDetachedCount) == fCache.count());
reed@google.com01804b42011-01-18 21:50:41 +0000287
reed@google.comac10a2d2010-12-22 21:39:39 +0000288 fCache.validate();
289
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000290 GrResourceEntry* entry = fHead;
reed@google.comac10a2d2010-12-22 21:39:39 +0000291 int count = 0;
292 size_t bytes = 0;
293 while (entry) {
294 entry->validate();
295 GrAssert(fCache.find(entry->key()));
296 count += 1;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000297 bytes += entry->resource()->sizeInBytes();
reed@google.comac10a2d2010-12-22 21:39:39 +0000298 entry = entry->fNext;
299 }
300 GrAssert(count == fEntryCount - fClientDetachedCount);
301 GrAssert(bytes == fEntryBytes - fClientDetachedBytes);
302
303 count = 0;
304 for (entry = fTail; entry; entry = entry->fPrev) {
305 count += 1;
306 }
307 GrAssert(count == fEntryCount - fClientDetachedCount);
308
309 for (int i = 0; i < count; i++) {
310 int matches = countMatches(fHead, fCache.getArray()[i]);
311 GrAssert(1 == matches);
312 }
313}
314#endif
315
316