OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkScaledImageCache.h" | 8 #include "SkScaledImageCache.h" |
9 #include "SkMipMap.h" | 9 #include "SkMipMap.h" |
| 10 #include "SkOnce.h" |
10 #include "SkPixelRef.h" | 11 #include "SkPixelRef.h" |
11 #include "SkRect.h" | 12 #include "SkRect.h" |
12 | 13 |
13 #ifndef SK_DEFAULT_IMAGE_CACHE_LIMIT | 14 #ifndef SK_DEFAULT_IMAGE_CACHE_LIMIT |
14 #define SK_DEFAULT_IMAGE_CACHE_LIMIT (2 * 1024 * 1024) | 15 #define SK_DEFAULT_IMAGE_CACHE_LIMIT (2 * 1024 * 1024) |
15 #endif | 16 #endif |
16 | 17 |
17 | 18 |
18 // Implemented from en.wikipedia.org/wiki/MurmurHash. | 19 // Implemented from en.wikipedia.org/wiki/MurmurHash. |
19 static uint32_t compute_hash(const uint32_t data[], int count) { | 20 static uint32_t compute_hash(const uint32_t data[], int count) { |
(...skipping 27 matching lines...) Expand all Loading... |
47 if (!pr) { | 48 if (!pr) { |
48 return false; | 49 return false; |
49 } | 50 } |
50 | 51 |
51 size_t x, y; | 52 size_t x, y; |
52 SkTDivMod(bm.pixelRefOffset(), bm.rowBytes(), &y, &x); | 53 SkTDivMod(bm.pixelRefOffset(), bm.rowBytes(), &y, &x); |
53 x >>= 2; | 54 x >>= 2; |
54 | 55 |
55 fGenID = pr->getGenerationID(); | 56 fGenID = pr->getGenerationID(); |
56 fBounds.set(x, y, x + bm.width(), y + bm.height()); | 57 fBounds.set(x, y, x + bm.width(), y + bm.height()); |
57 fScaleX = scaleX; | 58 fScaleX = SkScalarToFloat(scaleX); |
58 fScaleY = scaleY; | 59 fScaleY = SkScalarToFloat(scaleY); |
59 | 60 |
60 fHash = compute_hash(&fGenID, 7); | 61 fHash = compute_hash(&fGenID, 7); |
61 return true; | 62 return true; |
62 } | 63 } |
63 | 64 |
| 65 void init(int32_t width, |
| 66 int32_t height, |
| 67 uint32_t genID, |
| 68 SkScalar scaleX, |
| 69 SkScalar scaleY) { |
| 70 fBounds.set(0, 0, width, height); |
| 71 fGenID = genID; |
| 72 fScaleX = SkScalarToFloat(scaleX); |
| 73 fScaleY = SkScalarToFloat(scaleY); |
| 74 fHash = compute_hash(&fGenID, 7); |
| 75 } |
| 76 |
64 bool operator<(const Key& other) const { | 77 bool operator<(const Key& other) const { |
65 const uint32_t* a = &fGenID; | 78 const uint32_t* a = &fGenID; |
66 const uint32_t* b = &other.fGenID; | 79 const uint32_t* b = &other.fGenID; |
67 for (int i = 0; i < 7; ++i) { | 80 for (int i = 0; i < 7; ++i) { |
68 if (a[i] < b[i]) { | 81 if (a[i] < b[i]) { |
69 return true; | 82 return true; |
70 } | 83 } |
71 if (a[i] > b[i]) { | 84 if (a[i] > b[i]) { |
72 return false; | 85 return false; |
73 } | 86 } |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
167 SkScaledImageCache::~SkScaledImageCache() { | 180 SkScaledImageCache::~SkScaledImageCache() { |
168 Rec* rec = fHead; | 181 Rec* rec = fHead; |
169 while (rec) { | 182 while (rec) { |
170 Rec* next = rec->fNext; | 183 Rec* next = rec->fNext; |
171 SkDELETE(rec); | 184 SkDELETE(rec); |
172 rec = next; | 185 rec = next; |
173 } | 186 } |
174 delete fHash; | 187 delete fHash; |
175 } | 188 } |
176 | 189 |
| 190 static inline SkScaledImageCache::Rec* find_rec_in_list( |
| 191 SkScaledImageCache::Rec* head, const Key & key) { |
| 192 SkScaledImageCache::Rec* rec = head; |
| 193 while ((rec != NULL) && !(rec->fKey == key)) { |
| 194 rec = rec->fNext; |
| 195 } |
| 196 return rec; |
| 197 } |
| 198 |
177 SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(const SkBitmap& orig, | 199 SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(const SkBitmap& orig, |
178 SkScalar scaleX, | 200 SkScalar scaleX, |
179 SkScalar scaleY) { | 201 SkScalar scaleY) { |
180 Key key; | 202 Key key; |
181 if (!key.init(orig, scaleX, scaleY)) { | 203 if (!key.init(orig, scaleX, scaleY)) { |
182 return NULL; | 204 return NULL; |
183 } | 205 } |
184 | 206 |
185 #ifdef USE_HASH | 207 #ifdef USE_HASH |
186 Rec* rec = fHash->find(key); | 208 Rec* rec = fHash->find(key); |
187 #else | 209 #else |
188 Rec* rec = fHead; | 210 Rec* rec = find_rec_in_list(fHead, key); |
189 while (rec != NULL) { | |
190 if (rec->fKey == key) { | |
191 break; | |
192 } | |
193 rec = rec->fNext; | |
194 } | |
195 #endif | 211 #endif |
196 | |
197 if (rec) { | 212 if (rec) { |
198 this->moveToHead(rec); // for our LRU | 213 this->moveToHead(rec); // for our LRU |
199 rec->fLockCount += 1; | 214 rec->fLockCount += 1; |
200 } | 215 } |
201 return rec; | 216 return rec; |
202 } | 217 } |
203 | 218 |
| 219 |
| 220 SkScaledImageCache::ID* SkScaledImageCache::findAndLock( |
| 221 uint32_t pixelGenerationID, |
| 222 int32_t width, |
| 223 int32_t height, |
| 224 SkBitmap* scaled) { |
| 225 Key key; |
| 226 key.init(width, height, pixelGenerationID, SK_Scalar1, SK_Scalar1); |
| 227 #ifdef USE_HASH |
| 228 Rec* rec = fHash->find(key); |
| 229 #else |
| 230 Rec* rec = find_rec_in_list(fHead, key); |
| 231 #endif |
| 232 if (rec) { |
| 233 this->moveToHead(rec); // for our LRU |
| 234 rec->fLockCount += 1; |
| 235 SkASSERT(NULL == rec->fMip); |
| 236 SkASSERT(rec->fBitmap.pixelRef()); |
| 237 *scaled = rec->fBitmap; |
| 238 } |
| 239 return reinterpret_cast<ID*>(rec); |
| 240 } |
| 241 |
204 SkScaledImageCache::ID* SkScaledImageCache::findAndLock(const SkBitmap& orig, | 242 SkScaledImageCache::ID* SkScaledImageCache::findAndLock(const SkBitmap& orig, |
205 SkScalar scaleX, | 243 SkScalar scaleX, |
206 SkScalar scaleY, | 244 SkScalar scaleY, |
207 SkBitmap* scaled) { | 245 SkBitmap* scaled) { |
208 if (0 == scaleX || 0 == scaleY) { | 246 if (0 == scaleX || 0 == scaleY) { |
209 // degenerate, and the key we use for mipmaps | 247 // degenerate, and the key we use for mipmaps |
210 return NULL; | 248 return NULL; |
211 } | 249 } |
212 | 250 |
213 Rec* rec = this->findAndLock(orig, scaleX, scaleY); | 251 Rec* rec = this->findAndLock(orig, scaleX, scaleY); |
214 if (rec) { | 252 if (rec) { |
215 SkASSERT(NULL == rec->fMip); | 253 SkASSERT(NULL == rec->fMip); |
216 SkASSERT(rec->fBitmap.pixelRef()); | 254 SkASSERT(rec->fBitmap.pixelRef()); |
217 *scaled = rec->fBitmap; | 255 *scaled = rec->fBitmap; |
218 } | 256 } |
219 return (ID*)rec; | 257 return (ID*)rec; |
220 } | 258 } |
221 | 259 |
222 SkScaledImageCache::ID* SkScaledImageCache::findAndLockMip(const SkBitmap& orig, | 260 SkScaledImageCache::ID* SkScaledImageCache::findAndLockMip(const SkBitmap& orig, |
223 SkMipMap const ** mip
) { | 261 SkMipMap const ** mip
) { |
224 Rec* rec = this->findAndLock(orig, 0, 0); | 262 Rec* rec = this->findAndLock(orig, 0, 0); |
225 if (rec) { | 263 if (rec) { |
226 SkASSERT(rec->fMip); | 264 SkASSERT(rec->fMip); |
227 SkASSERT(NULL == rec->fBitmap.pixelRef()); | 265 SkASSERT(NULL == rec->fBitmap.pixelRef()); |
228 *mip = rec->fMip; | 266 *mip = rec->fMip; |
229 } | 267 } |
230 return (ID*)rec; | 268 return (ID*)rec; |
231 } | 269 } |
232 | 270 |
| 271 SkScaledImageCache::ID* SkScaledImageCache::addAndLock( |
| 272 uint32_t pixelGenerationID, |
| 273 int32_t width, |
| 274 int32_t height, |
| 275 const SkBitmap& scaled) { |
| 276 Key key; |
| 277 key.init(width, height, pixelGenerationID, SK_Scalar1, SK_Scalar1); |
| 278 Rec* rec = SkNEW_ARGS(Rec, (key, scaled)); |
| 279 this->addToHead(rec); |
| 280 SkASSERT(1 == rec->fLockCount); |
| 281 |
| 282 #ifdef USE_HASH |
| 283 fHash->add(rec); |
| 284 #endif |
| 285 |
| 286 // We may (now) be overbudget, so see if we need to purge something. |
| 287 this->purgeAsNeeded(); |
| 288 return reinterpret_cast<ID*>(rec); |
| 289 } |
| 290 |
233 SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const SkBitmap& orig, | 291 SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const SkBitmap& orig, |
234 SkScalar scaleX, | 292 SkScalar scaleX, |
235 SkScalar scaleY, | 293 SkScalar scaleY, |
236 const SkBitmap& scaled) { | 294 const SkBitmap& scaled) { |
237 if (0 == scaleX || 0 == scaleY) { | 295 if (0 == scaleX || 0 == scaleY) { |
238 // degenerate, and the key we use for mipmaps | 296 // degenerate, and the key we use for mipmaps |
239 return NULL; | 297 return NULL; |
240 } | 298 } |
241 | 299 |
242 Key key; | 300 Key key; |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
444 SkASSERT(0 == used); | 502 SkASSERT(0 == used); |
445 } | 503 } |
446 #endif | 504 #endif |
447 | 505 |
448 /////////////////////////////////////////////////////////////////////////////// | 506 /////////////////////////////////////////////////////////////////////////////// |
449 | 507 |
450 #include "SkThread.h" | 508 #include "SkThread.h" |
451 | 509 |
452 SK_DECLARE_STATIC_MUTEX(gMutex); | 510 SK_DECLARE_STATIC_MUTEX(gMutex); |
453 | 511 |
| 512 DEF_SK_ONCE(create_cache, SkScaledImageCache** cache) { |
| 513 *cache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CACHE_LIMIT)); |
| 514 } |
| 515 |
454 static SkScaledImageCache* get_cache() { | 516 static SkScaledImageCache* get_cache() { |
455 static SkScaledImageCache* gCache; | 517 static SkScaledImageCache* gCache = NULL; |
456 if (!gCache) { | 518 SK_ONCE(create_cache, &gCache); |
457 gCache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CACHE_LIMIT)); | 519 SkASSERT(NULL != gCache); |
458 } | |
459 return gCache; | 520 return gCache; |
460 } | 521 } |
461 | 522 |
| 523 |
| 524 SkScaledImageCache::ID* SkScaledImageCache::FindAndLock( |
| 525 uint32_t pixelGenerationID, |
| 526 int32_t width, |
| 527 int32_t height, |
| 528 SkBitmap* scaled) { |
| 529 SkAutoMutexAcquire am(gMutex); |
| 530 return get_cache()->findAndLock(pixelGenerationID, width, height, scaled); |
| 531 } |
| 532 |
| 533 SkScaledImageCache::ID* SkScaledImageCache::AddAndLock( |
| 534 uint32_t pixelGenerationID, |
| 535 int32_t width, |
| 536 int32_t height, |
| 537 const SkBitmap& scaled) { |
| 538 SkAutoMutexAcquire am(gMutex); |
| 539 return get_cache()->addAndLock(pixelGenerationID, width, height, scaled); |
| 540 } |
| 541 |
| 542 |
462 SkScaledImageCache::ID* SkScaledImageCache::FindAndLock(const SkBitmap& orig, | 543 SkScaledImageCache::ID* SkScaledImageCache::FindAndLock(const SkBitmap& orig, |
463 SkScalar scaleX, | 544 SkScalar scaleX, |
464 SkScalar scaleY, | 545 SkScalar scaleY, |
465 SkBitmap* scaled) { | 546 SkBitmap* scaled) { |
466 SkAutoMutexAcquire am(gMutex); | 547 SkAutoMutexAcquire am(gMutex); |
467 return get_cache()->findAndLock(orig, scaleX, scaleY, scaled); | 548 return get_cache()->findAndLock(orig, scaleX, scaleY, scaled); |
468 } | 549 } |
469 | 550 |
470 SkScaledImageCache::ID* SkScaledImageCache::FindAndLockMip(const SkBitmap& orig, | 551 SkScaledImageCache::ID* SkScaledImageCache::FindAndLockMip(const SkBitmap& orig, |
471 SkMipMap const ** mip) { | 552 SkMipMap const ** mip) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
515 return SkScaledImageCache::GetBytesUsed(); | 596 return SkScaledImageCache::GetBytesUsed(); |
516 } | 597 } |
517 | 598 |
518 size_t SkGraphics::GetImageCacheByteLimit() { | 599 size_t SkGraphics::GetImageCacheByteLimit() { |
519 return SkScaledImageCache::GetByteLimit(); | 600 return SkScaledImageCache::GetByteLimit(); |
520 } | 601 } |
521 | 602 |
522 size_t SkGraphics::SetImageCacheByteLimit(size_t newLimit) { | 603 size_t SkGraphics::SetImageCacheByteLimit(size_t newLimit) { |
523 return SkScaledImageCache::SetByteLimit(newLimit); | 604 return SkScaledImageCache::SetByteLimit(newLimit); |
524 } | 605 } |
OLD | NEW |