| OLD | NEW |
| 1 #include "SkTextureCache.h" | 1 #include "SkTextureCache.h" |
| 2 | 2 |
| 3 //#define TRACE_HASH_HITS | 3 //#define TRACE_HASH_HITS |
| 4 //#define TRACE_TEXTURE_CACHE_PURGE | 4 //#define TRACE_TEXTURE_CACHE_PURGE |
| 5 | 5 |
| 6 SkTextureCache::Entry::Entry(const SkBitmap& bitmap) | 6 SkTextureCache::Entry::Entry(const SkBitmap& bitmap) |
| 7 : fName(0), fKey(bitmap), fPrev(NULL), fNext(NULL) { | 7 : fName(0), fKey(bitmap), fPrev(NULL), fNext(NULL) { |
| 8 | 8 |
| 9 fMemSize = SkGL::ComputeTextureMemorySize(bitmap); | 9 fMemSize = SkGL::ComputeTextureMemorySize(bitmap); |
| 10 fLockCount = 0; | 10 fLockCount = 0; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 while (entry) { | 33 while (entry) { |
| 34 SkASSERT(entry->lockCount() == 0); | 34 SkASSERT(entry->lockCount() == 0); |
| 35 entry = entry->fNext; | 35 entry = entry->fNext; |
| 36 } | 36 } |
| 37 #endif | 37 #endif |
| 38 this->validate(); | 38 this->validate(); |
| 39 } | 39 } |
| 40 | 40 |
| 41 void SkTextureCache::deleteAllCaches(bool texturesAreValid) { | 41 void SkTextureCache::deleteAllCaches(bool texturesAreValid) { |
| 42 this->validate(); | 42 this->validate(); |
| 43 | 43 |
| 44 Entry* entry = fHead; | 44 Entry* entry = fHead; |
| 45 while (entry) { | 45 while (entry) { |
| 46 Entry* next = entry->fNext; | 46 Entry* next = entry->fNext; |
| 47 if (!texturesAreValid) { | 47 if (!texturesAreValid) { |
| 48 entry->abandonTexture(); | 48 entry->abandonTexture(); |
| 49 } | 49 } |
| 50 SkDELETE(entry); | 50 SkDELETE(entry); |
| 51 entry = next; | 51 entry = next; |
| 52 } | 52 } |
| 53 | 53 |
| 54 fSorted.reset(); | 54 fSorted.reset(); |
| 55 sk_bzero(fHash, sizeof(fHash)); | 55 sk_bzero(fHash, sizeof(fHash)); |
| 56 | 56 |
| 57 fTexCount = 0; | 57 fTexCount = 0; |
| 58 fTexSize = 0; | 58 fTexSize = 0; |
| 59 | 59 |
| 60 fTail = fHead = NULL; | 60 fTail = fHead = NULL; |
| 61 | 61 |
| 62 this->validate(); | 62 this->validate(); |
| 63 } | 63 } |
| 64 | 64 |
| 65 /////////////////////////////////////////////////////////////////////////////// | 65 /////////////////////////////////////////////////////////////////////////////// |
| 66 | 66 |
| 67 int SkTextureCache::findInSorted(const Key& key) const { | 67 int SkTextureCache::findInSorted(const Key& key) const { |
| 68 int count = fSorted.count(); | 68 int count = fSorted.count(); |
| 69 if (count == 0) { | 69 if (count == 0) { |
| 70 return ~0; | 70 return ~0; |
| 71 } | 71 } |
| 72 | 72 |
| 73 Entry** sorted = fSorted.begin(); | 73 Entry** sorted = fSorted.begin(); |
| 74 int lo = 0; | 74 int lo = 0; |
| 75 int hi = count - 1; | 75 int hi = count - 1; |
| 76 while (lo < hi) { | 76 while (lo < hi) { |
| 77 int mid = (hi + lo) >> 1; | 77 int mid = (hi + lo) >> 1; |
| 78 if (sorted[mid]->getKey() < key) { | 78 if (sorted[mid]->getKey() < key) { |
| 79 lo = mid + 1; | 79 lo = mid + 1; |
| 80 } else { | 80 } else { |
| 81 hi = mid; | 81 hi = mid; |
| 82 } | 82 } |
| 83 } | 83 } |
| 84 | 84 |
| 85 // hi is now our best guess | 85 // hi is now our best guess |
| 86 const Entry* entry = sorted[hi]; | 86 const Entry* entry = sorted[hi]; |
| 87 if (entry->getKey() == key) { | 87 if (entry->getKey() == key) { |
| 88 return hi; | 88 return hi; |
| 89 } | 89 } |
| 90 | 90 |
| 91 // return where to insert it | 91 // return where to insert it |
| 92 if (entry->getKey() < key) { | 92 if (entry->getKey() < key) { |
| 93 hi += 1; | 93 hi += 1; |
| 94 } | 94 } |
| 95 return ~hi; // we twiddle to indicate not-found | 95 return ~hi; // we twiddle to indicate not-found |
| 96 } | 96 } |
| 97 | 97 |
| 98 #ifdef TRACE_HASH_HITS | 98 #ifdef TRACE_HASH_HITS |
| 99 static int gHashHits; | 99 static int gHashHits; |
| 100 static int gSortedHits; | 100 static int gSortedHits; |
| 101 #endif | 101 #endif |
| 102 | 102 |
| 103 SkTextureCache::Entry* SkTextureCache::find(const Key& key, int* insert) const { | 103 SkTextureCache::Entry* SkTextureCache::find(const Key& key, int* insert) const { |
| 104 int count = fSorted.count(); | 104 int count = fSorted.count(); |
| 105 if (count == 0) { | 105 if (count == 0) { |
| 106 *insert = 0; | 106 *insert = 0; |
| 107 return NULL; | 107 return NULL; |
| 108 } | 108 } |
| 109 | 109 |
| 110 // check the hash first | 110 // check the hash first |
| 111 int hashIndex = key.getHashIndex(); | 111 int hashIndex = key.getHashIndex(); |
| 112 Entry* entry = fHash[hashIndex]; | 112 Entry* entry = fHash[hashIndex]; |
| 113 if (NULL != entry && entry->getKey() == key) { | 113 if (NULL != entry && entry->getKey() == key) { |
| 114 #ifdef TRACE_HASH_HITS | 114 #ifdef TRACE_HASH_HITS |
| 115 gHashHits += 1; | 115 gHashHits += 1; |
| 116 #endif | 116 #endif |
| 117 return entry; | 117 return entry; |
| 118 } | 118 } |
| 119 | 119 |
| 120 int index = this->findInSorted(key); | 120 int index = this->findInSorted(key); |
| 121 if (index >= 0) { | 121 if (index >= 0) { |
| 122 #ifdef TRACE_HASH_HITS | 122 #ifdef TRACE_HASH_HITS |
| 123 gSortedHits += 1; | 123 gSortedHits += 1; |
| 124 #endif | 124 #endif |
| 125 entry = fSorted[index]; | 125 entry = fSorted[index]; |
| 126 fHash[hashIndex] = entry; | 126 fHash[hashIndex] = entry; |
| 127 return entry; | 127 return entry; |
| 128 } | 128 } |
| 129 | 129 |
| 130 // ~index is where to insert the entry | 130 // ~index is where to insert the entry |
| 131 *insert = ~index; | 131 *insert = ~index; |
| 132 return NULL; | 132 return NULL; |
| 133 } | 133 } |
| 134 | 134 |
| 135 SkTextureCache::Entry* SkTextureCache::lock(const SkBitmap& bitmap) { | 135 SkTextureCache::Entry* SkTextureCache::lock(const SkBitmap& bitmap) { |
| 136 this->validate(); | 136 this->validate(); |
| 137 | 137 |
| 138 // call this before we call find(), so we don't reorder after find() and | 138 // call this before we call find(), so we don't reorder after find() and |
| 139 // invalidate our index | 139 // invalidate our index |
| 140 this->purgeIfNecessary(SkGL::ComputeTextureMemorySize(bitmap)); | 140 this->purgeIfNecessary(SkGL::ComputeTextureMemorySize(bitmap)); |
| 141 | 141 |
| 142 Key key(bitmap); | 142 Key key(bitmap); |
| 143 int index; | 143 int index; |
| 144 Entry* entry = this->find(key, &index); | 144 Entry* entry = this->find(key, &index); |
| 145 | 145 |
| 146 if (NULL == entry) { | 146 if (NULL == entry) { |
| 147 entry = SkNEW_ARGS(Entry, (bitmap)); | 147 entry = SkNEW_ARGS(Entry, (bitmap)); |
| 148 | 148 |
| 149 entry->fName = SkGL::BindNewTexture(bitmap, &entry->fTexSize); | 149 entry->fName = SkGL::BindNewTexture(bitmap, &entry->fTexSize); |
| 150 if (0 == entry->fName) { | 150 if (0 == entry->fName) { |
| 151 SkDELETE(entry); | 151 SkDELETE(entry); |
| 152 return NULL; | 152 return NULL; |
| 153 } | 153 } |
| 154 fHash[key.getHashIndex()] = entry; | 154 fHash[key.getHashIndex()] = entry; |
| 155 *fSorted.insert(index) = entry; | 155 *fSorted.insert(index) = entry; |
| 156 | 156 |
| 157 fTexCount += 1; | 157 fTexCount += 1; |
| 158 fTexSize += entry->memSize(); | 158 fTexSize += entry->memSize(); |
| 159 } else { | 159 } else { |
| 160 // detach from our llist | 160 // detach from our llist |
| 161 Entry* prev = entry->fPrev; | 161 Entry* prev = entry->fPrev; |
| 162 Entry* next = entry->fNext; | 162 Entry* next = entry->fNext; |
| 163 if (prev) { | 163 if (prev) { |
| 164 prev->fNext = next; | 164 prev->fNext = next; |
| 165 } else { | 165 } else { |
| 166 SkASSERT(fHead == entry); | 166 SkASSERT(fHead == entry); |
| 167 fHead = next; | 167 fHead = next; |
| 168 } | 168 } |
| 169 if (next) { | 169 if (next) { |
| 170 next->fPrev = prev; | 170 next->fPrev = prev; |
| 171 } else { | 171 } else { |
| 172 SkASSERT(fTail == entry); | 172 SkASSERT(fTail == entry); |
| 173 fTail = prev; | 173 fTail = prev; |
| 174 } | 174 } |
| 175 // now bind the texture | 175 // now bind the texture |
| 176 glBindTexture(GL_TEXTURE_2D, entry->fName); | 176 glBindTexture(GL_TEXTURE_2D, entry->fName); |
| 177 } | 177 } |
| 178 | 178 |
| 179 // add to head of llist for LRU | 179 // add to head of llist for LRU |
| 180 entry->fPrev = NULL; | 180 entry->fPrev = NULL; |
| 181 entry->fNext = fHead; | 181 entry->fNext = fHead; |
| 182 if (NULL != fHead) { | 182 if (NULL != fHead) { |
| 183 SkASSERT(NULL == fHead->fPrev); | 183 SkASSERT(NULL == fHead->fPrev); |
| 184 fHead->fPrev = entry; | 184 fHead->fPrev = entry; |
| 185 } | 185 } |
| 186 fHead = entry; | 186 fHead = entry; |
| 187 if (NULL == fTail) { | 187 if (NULL == fTail) { |
| 188 fTail = entry; | 188 fTail = entry; |
| 189 } | 189 } |
| 190 | 190 |
| 191 this->validate(); | 191 this->validate(); |
| 192 entry->lock(); | 192 entry->lock(); |
| 193 | 193 |
| 194 #ifdef TRACE_HASH_HITS | 194 #ifdef TRACE_HASH_HITS |
| 195 SkDebugf("---- texture cache hash=%d sorted=%d\n", gHashHits, gSortedHits); | 195 SkDebugf("---- texture cache hash=%d sorted=%d\n", gHashHits, gSortedHits); |
| 196 #endif | 196 #endif |
| 197 return entry; | 197 return entry; |
| 198 } | 198 } |
| 199 | 199 |
| 200 void SkTextureCache::unlock(Entry* entry) { | 200 void SkTextureCache::unlock(Entry* entry) { |
| 201 this->validate(); | 201 this->validate(); |
| 202 | 202 |
| 203 #ifdef SK_DEBUG | 203 #ifdef SK_DEBUG |
| 204 SkASSERT(entry); | 204 SkASSERT(entry); |
| 205 int index = this->findInSorted(entry->getKey()); | 205 int index = this->findInSorted(entry->getKey()); |
| 206 SkASSERT(fSorted[index] == entry); | 206 SkASSERT(fSorted[index] == entry); |
| 207 #endif | 207 #endif |
| 208 | 208 |
| 209 SkASSERT(entry->fLockCount > 0); | 209 SkASSERT(entry->fLockCount > 0); |
| 210 entry->unlock(); | 210 entry->unlock(); |
| 211 } | 211 } |
| 212 | 212 |
| 213 void SkTextureCache::purgeIfNecessary(size_t extraSize) { | 213 void SkTextureCache::purgeIfNecessary(size_t extraSize) { |
| 214 this->validate(); | 214 this->validate(); |
| 215 | 215 |
| 216 size_t countMax = fTexCountMax; | 216 size_t countMax = fTexCountMax; |
| 217 size_t sizeMax = fTexSizeMax; | 217 size_t sizeMax = fTexSizeMax; |
| 218 | 218 |
| 219 // take extraSize into account, but watch for underflow of size_t | 219 // take extraSize into account, but watch for underflow of size_t |
| 220 if (extraSize > sizeMax) { | 220 if (extraSize > sizeMax) { |
| 221 sizeMax = 0; | 221 sizeMax = 0; |
| 222 } else { | 222 } else { |
| 223 sizeMax -= extraSize; | 223 sizeMax -= extraSize; |
| 224 } | 224 } |
| 225 | 225 |
| 226 Entry* entry = fTail; | 226 Entry* entry = fTail; |
| 227 while (entry) { | 227 while (entry) { |
| 228 if (fTexCount <= countMax && fTexSize <= sizeMax) { | 228 if (fTexCount <= countMax && fTexSize <= sizeMax) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 253 if (prev) { | 253 if (prev) { |
| 254 prev->fNext = next; | 254 prev->fNext = next; |
| 255 } else { | 255 } else { |
| 256 fHead = next; | 256 fHead = next; |
| 257 } | 257 } |
| 258 if (next) { | 258 if (next) { |
| 259 next->fPrev = prev; | 259 next->fPrev = prev; |
| 260 } else { | 260 } else { |
| 261 fTail = prev; | 261 fTail = prev; |
| 262 } | 262 } |
| 263 | 263 |
| 264 // now delete it | 264 // now delete it |
| 265 #ifdef TRACE_TEXTURE_CACHE_PURGE | 265 #ifdef TRACE_TEXTURE_CACHE_PURGE |
| 266 SkDebugf("---- purge texture cache %d size=%d\n", | 266 SkDebugf("---- purge texture cache %d size=%d\n", |
| 267 entry->name(), entry->memSize()); | 267 entry->name(), entry->memSize()); |
| 268 #endif | 268 #endif |
| 269 SkDELETE(entry); | 269 SkDELETE(entry); |
| 270 | 270 |
| 271 // keep going | 271 // keep going |
| 272 entry = prev; | 272 entry = prev; |
| 273 } | 273 } |
| 274 | 274 |
| 275 this->validate(); | 275 this->validate(); |
| 276 } | 276 } |
| 277 | 277 |
| 278 void SkTextureCache::setMaxCount(size_t count) { | 278 void SkTextureCache::setMaxCount(size_t count) { |
| 279 if (fTexCountMax != count) { | 279 if (fTexCountMax != count) { |
| 280 fTexCountMax = count; | 280 fTexCountMax = count; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 296 if (0 == fTexCount) { | 296 if (0 == fTexCount) { |
| 297 SkASSERT(0 == fTexSize); | 297 SkASSERT(0 == fTexSize); |
| 298 SkASSERT(NULL == fHead); | 298 SkASSERT(NULL == fHead); |
| 299 SkASSERT(NULL == fTail); | 299 SkASSERT(NULL == fTail); |
| 300 return; | 300 return; |
| 301 } | 301 } |
| 302 | 302 |
| 303 SkASSERT(fTexSize); // do we allow a zero-sized texture? | 303 SkASSERT(fTexSize); // do we allow a zero-sized texture? |
| 304 SkASSERT(fHead); | 304 SkASSERT(fHead); |
| 305 SkASSERT(fTail); | 305 SkASSERT(fTail); |
| 306 | 306 |
| 307 SkASSERT(NULL == fHead->fPrev); | 307 SkASSERT(NULL == fHead->fPrev); |
| 308 SkASSERT(NULL == fTail->fNext); | 308 SkASSERT(NULL == fTail->fNext); |
| 309 if (1 == fTexCount) { | 309 if (1 == fTexCount) { |
| 310 SkASSERT(fHead == fTail); | 310 SkASSERT(fHead == fTail); |
| 311 } | 311 } |
| 312 | 312 |
| 313 const Entry* entry = fHead; | 313 const Entry* entry = fHead; |
| 314 size_t count = 0; | 314 size_t count = 0; |
| 315 size_t size = 0; | 315 size_t size = 0; |
| 316 size_t i; | 316 size_t i; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 336 SkASSERT(size < fTexSize); | 336 SkASSERT(size < fTexSize); |
| 337 size += entry->memSize(); | 337 size += entry->memSize(); |
| 338 count += 1; | 338 count += 1; |
| 339 if (NULL == entry->fPrev) { | 339 if (NULL == entry->fPrev) { |
| 340 SkASSERT(fHead == entry); | 340 SkASSERT(fHead == entry); |
| 341 } | 341 } |
| 342 entry = entry->fPrev; | 342 entry = entry->fPrev; |
| 343 } | 343 } |
| 344 SkASSERT(count == fTexCount); | 344 SkASSERT(count == fTexCount); |
| 345 SkASSERT(size == fTexSize); | 345 SkASSERT(size == fTexSize); |
| 346 | 346 |
| 347 SkASSERT(count == (size_t)fSorted.count()); | 347 SkASSERT(count == (size_t)fSorted.count()); |
| 348 for (i = 1; i < count; i++) { | 348 for (i = 1; i < count; i++) { |
| 349 SkASSERT(fSorted[i-1]->getKey() < fSorted[i]->getKey()); | 349 SkASSERT(fSorted[i-1]->getKey() < fSorted[i]->getKey()); |
| 350 } | 350 } |
| 351 | 351 |
| 352 for (i = 0; i < kHashCount; i++) { | 352 for (i = 0; i < kHashCount; i++) { |
| 353 if (fHash[i]) { | 353 if (fHash[i]) { |
| 354 size_t index = fHash[i]->getKey().getHashIndex(); | 354 size_t index = fHash[i]->getKey().getHashIndex(); |
| 355 SkASSERT(index == i); | 355 SkASSERT(index == i); |
| 356 index = fSorted.find(fHash[i]); | 356 index = fSorted.find(fHash[i]); |
| 357 SkASSERT((size_t)index < count); | 357 SkASSERT((size_t)index < count); |
| 358 } | 358 } |
| 359 } | 359 } |
| 360 } | 360 } |
| 361 #endif | 361 #endif |
| 362 | 362 |
| 363 | 363 |
| OLD | NEW |