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 |
18 static inline SkScaledImageCache::ID* rec_to_id(SkScaledImageCache::Rec* rec) { | |
19 return reinterpret_cast<SkScaledImageCache::ID*>(rec); | |
20 } | |
21 | |
22 static inline SkScaledImageCache::Rec* id_to_rec(SkScaledImageCache::ID* id) { | |
23 return reinterpret_cast<SkScaledImageCache::Rec*>(id); | |
24 } | |
17 | 25 |
18 // Implemented from en.wikipedia.org/wiki/MurmurHash. | 26 // Implemented from en.wikipedia.org/wiki/MurmurHash. |
19 static uint32_t compute_hash(const uint32_t data[], int count) { | 27 static uint32_t compute_hash(const uint32_t data[], int count) { |
20 uint32_t hash = 0; | 28 uint32_t hash = 0; |
21 | 29 |
22 for (int i = 0; i < count; ++i) { | 30 for (int i = 0; i < count; ++i) { |
23 uint32_t k = data[i]; | 31 uint32_t k = data[i]; |
24 k *= 0xcc9e2d51; | 32 k *= 0xcc9e2d51; |
25 k = (k << 15) | (k >> 17); | 33 k = (k << 15) | (k >> 17); |
26 k *= 0x1b873593; | 34 k *= 0x1b873593; |
(...skipping 20 matching lines...) Expand all Loading... | |
47 if (!pr) { | 55 if (!pr) { |
48 return false; | 56 return false; |
49 } | 57 } |
50 | 58 |
51 size_t x, y; | 59 size_t x, y; |
52 SkTDivMod(bm.pixelRefOffset(), bm.rowBytes(), &y, &x); | 60 SkTDivMod(bm.pixelRefOffset(), bm.rowBytes(), &y, &x); |
53 x >>= 2; | 61 x >>= 2; |
54 | 62 |
55 fGenID = pr->getGenerationID(); | 63 fGenID = pr->getGenerationID(); |
56 fBounds.set(x, y, x + bm.width(), y + bm.height()); | 64 fBounds.set(x, y, x + bm.width(), y + bm.height()); |
57 fScaleX = scaleX; | 65 fScaleX = SkScalarToFloat(scaleX); |
58 fScaleY = scaleY; | 66 fScaleY = SkScalarToFloat(scaleY); |
59 | 67 |
60 fHash = compute_hash(&fGenID, 7); | 68 fHash = compute_hash(&fGenID, 7); |
61 return true; | 69 return true; |
62 } | 70 } |
71 void init(uint32_t genID, | |
72 SkScalar scaleX, | |
reed1
2013/10/24 21:07:04
do we *always* pass in 1.0 for these today? If so,
hal.canary
2013/10/25 16:37:10
I have just cleaned this code up a lot. Now there
| |
73 SkScalar scaleY, | |
74 int32_t width, | |
75 int32_t height) { | |
76 fGenID = genID; | |
77 fScaleX = SkScalarToFloat(scaleX); | |
78 fScaleY = SkScalarToFloat(scaleY); | |
79 fBounds.set(0, 0, width, height); | |
80 fHash = compute_hash(&fGenID, 7); | |
81 } | |
63 | 82 |
64 bool operator<(const Key& other) const { | 83 bool operator<(const Key& other) const { |
65 const uint32_t* a = &fGenID; | 84 const uint32_t* a = &fGenID; |
66 const uint32_t* b = &other.fGenID; | 85 const uint32_t* b = &other.fGenID; |
67 for (int i = 0; i < 7; ++i) { | 86 for (int i = 0; i < 7; ++i) { |
68 if (a[i] < b[i]) { | 87 if (a[i] < b[i]) { |
69 return true; | 88 return true; |
70 } | 89 } |
71 if (a[i] > b[i]) { | 90 if (a[i] > b[i]) { |
72 return false; | 91 return false; |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
167 SkScaledImageCache::~SkScaledImageCache() { | 186 SkScaledImageCache::~SkScaledImageCache() { |
168 Rec* rec = fHead; | 187 Rec* rec = fHead; |
169 while (rec) { | 188 while (rec) { |
170 Rec* next = rec->fNext; | 189 Rec* next = rec->fNext; |
171 SkDELETE(rec); | 190 SkDELETE(rec); |
172 rec = next; | 191 rec = next; |
173 } | 192 } |
174 delete fHash; | 193 delete fHash; |
175 } | 194 } |
176 | 195 |
196 static inline SkScaledImageCache::Rec* find_rec_in_list( | |
197 SkScaledImageCache::Rec* head, const Key & key) { | |
198 SkScaledImageCache::Rec* rec = head; | |
199 while ((rec != NULL) && !(rec->fKey == key)) { | |
reed1
2013/10/24 21:07:04
!(a == b) ?
seems like we should have != operat
hal.canary
2013/10/25 16:37:10
Done.
| |
200 rec = rec->fNext; | |
201 } | |
202 return rec; | |
203 } | |
204 | |
177 SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(const SkBitmap& orig, | 205 SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(const SkBitmap& orig, |
178 SkScalar scaleX, | 206 SkScalar scaleX, |
179 SkScalar scaleY) { | 207 SkScalar scaleY) { |
180 Key key; | 208 Key key; |
181 if (!key.init(orig, scaleX, scaleY)) { | 209 if (!key.init(orig, scaleX, scaleY)) { |
182 return NULL; | 210 return NULL; |
183 } | 211 } |
184 | 212 |
185 #ifdef USE_HASH | 213 #ifdef USE_HASH |
186 Rec* rec = fHash->find(key); | 214 Rec* rec = fHash->find(key); |
scroggo
2013/10/24 20:41:39
Can this whole #if #else be a helper function?
Re
hal.canary
2013/10/25 16:37:10
I have move some things around to remove this repe
| |
187 #else | 215 #else |
188 Rec* rec = fHead; | 216 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 | 217 #endif |
196 | |
197 if (rec) { | 218 if (rec) { |
198 this->moveToHead(rec); // for our LRU | 219 this->moveToHead(rec); // for our LRU |
199 rec->fLockCount += 1; | 220 rec->fLockCount += 1; |
200 } | 221 } |
201 return rec; | 222 return rec; |
202 } | 223 } |
203 | 224 |
225 | |
226 SkScaledImageCache::ID* SkScaledImageCache::findAndLock( | |
227 uint32_t pixelGenerationID, | |
228 int32_t width, | |
229 int32_t height, | |
230 SkBitmap* scaled) { | |
231 Key key; | |
232 key.init(pixelGenerationID, SK_Scalar1, SK_Scalar1, width, height); | |
233 #ifdef USE_HASH | |
234 Rec* rec = fHash->find(key); | |
235 #else | |
236 Rec* rec = find_rec_in_list(fHead, key); | |
237 #endif | |
238 if (rec) { | |
239 this->moveToHead(rec); // for our LRU | |
240 rec->fLockCount += 1; | |
241 SkASSERT(NULL == rec->fMip); | |
242 SkASSERT(rec->fBitmap.pixelRef()); | |
243 *scaled = rec->fBitmap; | |
244 } | |
245 return rec_to_id(rec); | |
246 } | |
247 | |
204 SkScaledImageCache::ID* SkScaledImageCache::findAndLock(const SkBitmap& orig, | 248 SkScaledImageCache::ID* SkScaledImageCache::findAndLock(const SkBitmap& orig, |
205 SkScalar scaleX, | 249 SkScalar scaleX, |
206 SkScalar scaleY, | 250 SkScalar scaleY, |
207 SkBitmap* scaled) { | 251 SkBitmap* scaled) { |
208 if (0 == scaleX || 0 == scaleY) { | 252 if (0 == scaleX || 0 == scaleY) { |
209 // degenerate, and the key we use for mipmaps | 253 // degenerate, and the key we use for mipmaps |
210 return NULL; | 254 return NULL; |
211 } | 255 } |
212 | 256 |
213 Rec* rec = this->findAndLock(orig, scaleX, scaleY); | 257 Rec* rec = this->findAndLock(orig, scaleX, scaleY); |
214 if (rec) { | 258 if (rec) { |
215 SkASSERT(NULL == rec->fMip); | 259 SkASSERT(NULL == rec->fMip); |
216 SkASSERT(rec->fBitmap.pixelRef()); | 260 SkASSERT(rec->fBitmap.pixelRef()); |
217 *scaled = rec->fBitmap; | 261 *scaled = rec->fBitmap; |
218 } | 262 } |
219 return (ID*)rec; | 263 return rec_to_id(rec); |
220 } | 264 } |
221 | 265 |
222 SkScaledImageCache::ID* SkScaledImageCache::findAndLockMip(const SkBitmap& orig, | 266 SkScaledImageCache::ID* SkScaledImageCache::findAndLockMip(const SkBitmap& orig, |
223 SkMipMap const ** mip ) { | 267 SkMipMap const ** mip ) { |
224 Rec* rec = this->findAndLock(orig, 0, 0); | 268 Rec* rec = this->findAndLock(orig, 0, 0); |
225 if (rec) { | 269 if (rec) { |
226 SkASSERT(rec->fMip); | 270 SkASSERT(rec->fMip); |
227 SkASSERT(NULL == rec->fBitmap.pixelRef()); | 271 SkASSERT(NULL == rec->fBitmap.pixelRef()); |
228 *mip = rec->fMip; | 272 *mip = rec->fMip; |
229 } | 273 } |
230 return (ID*)rec; | 274 return rec_to_id(rec); |
275 } | |
276 | |
277 SkScaledImageCache::ID* SkScaledImageCache::addAndLock( | |
278 uint32_t pixelGenerationID, | |
279 int32_t width, | |
280 int32_t height, | |
281 const SkBitmap& scaled) { | |
282 Key key; | |
283 key.init(pixelGenerationID, SK_Scalar1, SK_Scalar1, width, height); | |
284 Rec* rec = SkNEW_ARGS(Rec, (key, scaled)); | |
285 this->addToHead(rec); | |
286 SkASSERT(1 == rec->fLockCount); | |
287 | |
288 #ifdef USE_HASH | |
289 fHash->add(rec); | |
290 #endif | |
291 | |
292 // We may (now) be overbudget, so see if we need to purge something. | |
293 this->purgeAsNeeded(); | |
294 return rec_to_id(rec); | |
231 } | 295 } |
232 | 296 |
233 SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const SkBitmap& orig, | 297 SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const SkBitmap& orig, |
234 SkScalar scaleX, | 298 SkScalar scaleX, |
235 SkScalar scaleY, | 299 SkScalar scaleY, |
236 const SkBitmap& scaled) { | 300 const SkBitmap& scaled) { |
237 if (0 == scaleX || 0 == scaleY) { | 301 if (0 == scaleX || 0 == scaleY) { |
238 // degenerate, and the key we use for mipmaps | 302 // degenerate, and the key we use for mipmaps |
239 return NULL; | 303 return NULL; |
240 } | 304 } |
241 | 305 |
242 Key key; | 306 Key key; |
243 if (!key.init(orig, scaleX, scaleY)) { | 307 if (!key.init(orig, scaleX, scaleY)) { |
244 return NULL; | 308 return NULL; |
245 } | 309 } |
246 | 310 |
247 Rec* rec = SkNEW_ARGS(Rec, (key, scaled)); | 311 Rec* rec = SkNEW_ARGS(Rec, (key, scaled)); |
248 this->addToHead(rec); | 312 this->addToHead(rec); |
249 SkASSERT(1 == rec->fLockCount); | 313 SkASSERT(1 == rec->fLockCount); |
250 | 314 |
251 #ifdef USE_HASH | 315 #ifdef USE_HASH |
252 fHash->add(rec); | 316 fHash->add(rec); |
253 #endif | 317 #endif |
254 | 318 |
255 // We may (now) be overbudget, so see if we need to purge something. | 319 // We may (now) be overbudget, so see if we need to purge something. |
256 this->purgeAsNeeded(); | 320 this->purgeAsNeeded(); |
257 return (ID*)rec; | 321 return rec_to_id(rec); |
258 } | 322 } |
259 | 323 |
260 SkScaledImageCache::ID* SkScaledImageCache::addAndLockMip(const SkBitmap& orig, | 324 SkScaledImageCache::ID* SkScaledImageCache::addAndLockMip(const SkBitmap& orig, |
261 const SkMipMap* mip) { | 325 const SkMipMap* mip) { |
262 Key key; | 326 Key key; |
263 if (!key.init(orig, 0, 0)) { | 327 if (!key.init(orig, 0, 0)) { |
264 return NULL; | 328 return NULL; |
265 } | 329 } |
266 | 330 |
267 Rec* rec = SkNEW_ARGS(Rec, (key, mip)); | 331 Rec* rec = SkNEW_ARGS(Rec, (key, mip)); |
268 this->addToHead(rec); | 332 this->addToHead(rec); |
269 SkASSERT(1 == rec->fLockCount); | 333 SkASSERT(1 == rec->fLockCount); |
270 | 334 |
271 #ifdef USE_HASH | 335 #ifdef USE_HASH |
272 fHash->add(rec); | 336 fHash->add(rec); |
273 #endif | 337 #endif |
274 | 338 |
275 // We may (now) be overbudget, so see if we need to purge something. | 339 // We may (now) be overbudget, so see if we need to purge something. |
276 this->purgeAsNeeded(); | 340 this->purgeAsNeeded(); |
277 return (ID*)rec; | 341 return rec_to_id(rec); |
278 } | 342 } |
279 | 343 |
280 void SkScaledImageCache::unlock(SkScaledImageCache::ID* id) { | 344 void SkScaledImageCache::unlock(SkScaledImageCache::ID* id) { |
281 SkASSERT(id); | 345 SkASSERT(id); |
282 | 346 |
283 #ifdef SK_DEBUG | 347 #ifdef SK_DEBUG |
284 { | 348 { |
285 bool found = false; | 349 bool found = false; |
286 Rec* rec = fHead; | 350 Rec* rec = fHead; |
287 while (rec != NULL) { | 351 while (rec != NULL) { |
288 if ((ID*)rec == id) { | 352 if (rec == id_to_rec(id)) { |
289 found = true; | 353 found = true; |
290 break; | 354 break; |
291 } | 355 } |
292 rec = rec->fNext; | 356 rec = rec->fNext; |
293 } | 357 } |
294 SkASSERT(found); | 358 SkASSERT(found); |
295 } | 359 } |
296 #endif | 360 #endif |
297 Rec* rec = (Rec*)id; | 361 Rec* rec = id_to_rec(id); |
298 SkASSERT(rec->fLockCount > 0); | 362 SkASSERT(rec->fLockCount > 0); |
299 rec->fLockCount -= 1; | 363 rec->fLockCount -= 1; |
300 | 364 |
301 // we may have been over-budget, but now have released something, so check | 365 // we may have been over-budget, but now have released something, so check |
302 // if we should purge. | 366 // if we should purge. |
303 if (0 == rec->fLockCount) { | 367 if (0 == rec->fLockCount) { |
304 this->purgeAsNeeded(); | 368 this->purgeAsNeeded(); |
305 } | 369 } |
306 } | 370 } |
307 | 371 |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
444 SkASSERT(0 == used); | 508 SkASSERT(0 == used); |
445 } | 509 } |
446 #endif | 510 #endif |
447 | 511 |
448 /////////////////////////////////////////////////////////////////////////////// | 512 /////////////////////////////////////////////////////////////////////////////// |
449 | 513 |
450 #include "SkThread.h" | 514 #include "SkThread.h" |
451 | 515 |
452 SK_DECLARE_STATIC_MUTEX(gMutex); | 516 SK_DECLARE_STATIC_MUTEX(gMutex); |
453 | 517 |
518 static void create_cache(SkScaledImageCache** cache) { | |
519 *cache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CACHE_LIMIT)); | |
520 } | |
521 | |
454 static SkScaledImageCache* get_cache() { | 522 static SkScaledImageCache* get_cache() { |
455 static SkScaledImageCache* gCache; | 523 static SkScaledImageCache* gCache(NULL); |
456 if (!gCache) { | 524 SK_DECLARE_STATIC_ONCE(create_cache_once); |
457 gCache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CACHE_LIMIT)); | 525 SkOnce<SkScaledImageCache**>(&create_cache_once, create_cache, &gCache); |
458 } | 526 SkASSERT(NULL != gCache); |
459 return gCache; | 527 return gCache; |
460 } | 528 } |
461 | 529 |
530 | |
531 SkScaledImageCache::ID* SkScaledImageCache::FindAndLock( | |
532 uint32_t pixelGenerationID, | |
533 int32_t width, | |
534 int32_t height, | |
535 SkBitmap* scaled) { | |
536 SkAutoMutexAcquire am(gMutex); | |
537 return get_cache()->findAndLock(pixelGenerationID, width, height, scaled); | |
538 } | |
539 | |
540 SkScaledImageCache::ID* SkScaledImageCache::AddAndLock( | |
541 uint32_t pixelGenerationID, | |
542 int32_t width, | |
543 int32_t height, | |
544 const SkBitmap& scaled) { | |
545 SkAutoMutexAcquire am(gMutex); | |
546 return get_cache()->addAndLock(pixelGenerationID, width, height, scaled); | |
547 } | |
548 | |
549 | |
462 SkScaledImageCache::ID* SkScaledImageCache::FindAndLock(const SkBitmap& orig, | 550 SkScaledImageCache::ID* SkScaledImageCache::FindAndLock(const SkBitmap& orig, |
463 SkScalar scaleX, | 551 SkScalar scaleX, |
464 SkScalar scaleY, | 552 SkScalar scaleY, |
465 SkBitmap* scaled) { | 553 SkBitmap* scaled) { |
466 SkAutoMutexAcquire am(gMutex); | 554 SkAutoMutexAcquire am(gMutex); |
467 return get_cache()->findAndLock(orig, scaleX, scaleY, scaled); | 555 return get_cache()->findAndLock(orig, scaleX, scaleY, scaled); |
468 } | 556 } |
469 | 557 |
470 SkScaledImageCache::ID* SkScaledImageCache::FindAndLockMip(const SkBitmap& orig, | 558 SkScaledImageCache::ID* SkScaledImageCache::FindAndLockMip(const SkBitmap& orig, |
471 SkMipMap const ** mip) { | 559 SkMipMap const ** mip) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
515 return SkScaledImageCache::GetBytesUsed(); | 603 return SkScaledImageCache::GetBytesUsed(); |
516 } | 604 } |
517 | 605 |
518 size_t SkGraphics::GetImageCacheByteLimit() { | 606 size_t SkGraphics::GetImageCacheByteLimit() { |
519 return SkScaledImageCache::GetByteLimit(); | 607 return SkScaledImageCache::GetByteLimit(); |
520 } | 608 } |
521 | 609 |
522 size_t SkGraphics::SetImageCacheByteLimit(size_t newLimit) { | 610 size_t SkGraphics::SetImageCacheByteLimit(size_t newLimit) { |
523 return SkScaledImageCache::SetByteLimit(newLimit); | 611 return SkScaledImageCache::SetByteLimit(newLimit); |
524 } | 612 } |
OLD | NEW |