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 "SkChecksum.h" | 8 #include "SkChecksum.h" |
9 #include "SkScaledImageCache.h" | 9 #include "SkScaledImageCache.h" |
10 #include "SkMipMap.h" | 10 #include "SkMipMap.h" |
11 #include "SkPixelRef.h" | 11 #include "SkPixelRef.h" |
12 #include "SkRect.h" | 12 #include "SkRect.h" |
13 | 13 |
14 // This can be defined by the caller's build system | 14 // This can be defined by the caller's build system |
15 //#define SK_USE_DISCARDABLE_SCALEDIMAGECACHE | 15 //#define SK_USE_DISCARDABLE_SCALEDIMAGECACHE |
16 | 16 |
17 #ifndef SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT | 17 #ifndef SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT |
18 # define SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT 1024 | 18 # define SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT 1024 |
19 #endif | 19 #endif |
20 | 20 |
21 #ifndef SK_DEFAULT_IMAGE_CACHE_LIMIT | 21 #ifndef SK_DEFAULT_IMAGE_CACHE_LIMIT |
22 #define SK_DEFAULT_IMAGE_CACHE_LIMIT (2 * 1024 * 1024) | 22 #define SK_DEFAULT_IMAGE_CACHE_LIMIT (2 * 1024 * 1024) |
23 #endif | 23 #endif |
24 | 24 |
25 static inline SkScaledImageCache::ID* rec_to_id(SkScaledImageCache::Rec* rec) { | |
26 return reinterpret_cast<SkScaledImageCache::ID*>(rec); | |
27 } | |
28 | |
29 static inline SkScaledImageCache::Rec* id_to_rec(SkScaledImageCache::ID* id) { | |
30 return reinterpret_cast<SkScaledImageCache::Rec*>(id); | |
31 } | |
32 | |
33 void SkScaledImageCache::Key::init(size_t length) { | 25 void SkScaledImageCache::Key::init(size_t length) { |
34 SkASSERT(SkAlign4(length) == length); | 26 SkASSERT(SkAlign4(length) == length); |
35 // 2 is fCount32 and fHash | 27 // 2 is fCount32 and fHash |
36 fCount32 = SkToS32(2 + (length >> 2)); | 28 fCount32 = SkToS32(2 + (length >> 2)); |
37 // skip both of our fields whe computing the murmur | 29 // skip both of our fields whe computing the murmur |
38 fHash = SkChecksum::Murmur3(this->as32() + 2, (fCount32 - 2) << 2); | 30 fHash = SkChecksum::Murmur3(this->as32() + 2, (fCount32 - 2) << 2); |
39 } | 31 } |
40 | 32 |
41 SkScaledImageCache::Key* SkScaledImageCache::Key::clone() const { | |
42 size_t size = fCount32 << 2; | |
43 void* copy = sk_malloc_throw(size); | |
44 memcpy(copy, this, size); | |
45 return (Key*)copy; | |
46 } | |
47 | |
48 struct SkScaledImageCache::Rec { | |
49 Rec(const Key& key, const SkBitmap& bm) : fKey(key.clone()), fBitmap(bm) { | |
50 fLockCount = 1; | |
51 fMip = NULL; | |
52 } | |
53 | |
54 Rec(const Key& key, const SkMipMap* mip) : fKey(key.clone()) { | |
55 fLockCount = 1; | |
56 fMip = mip; | |
57 mip->ref(); | |
58 } | |
59 | |
60 ~Rec() { | |
61 SkSafeUnref(fMip); | |
62 sk_free(fKey); | |
63 } | |
64 | |
65 static const Key& GetKey(const Rec& rec) { return *rec.fKey; } | |
66 static uint32_t Hash(const Key& key) { return key.hash(); } | |
67 | |
68 size_t bytesUsed() const { | |
69 return fMip ? fMip->getSize() : fBitmap.getSize(); | |
70 } | |
71 | |
72 Rec* fNext; | |
73 Rec* fPrev; | |
74 | |
75 // this guy wants to be 64bit aligned | |
76 Key* fKey; | |
77 | |
78 int32_t fLockCount; | |
79 | |
80 // we use either fBitmap or fMip, but not both | |
81 SkBitmap fBitmap; | |
82 const SkMipMap* fMip; | |
83 }; | |
84 | |
85 #include "SkTDynamicHash.h" | 33 #include "SkTDynamicHash.h" |
86 | 34 |
87 class SkScaledImageCache::Hash : | 35 class SkScaledImageCache::Hash : |
88 public SkTDynamicHash<SkScaledImageCache::Rec, SkScaledImageCache::Key> {}; | 36 public SkTDynamicHash<SkScaledImageCache::Rec, SkScaledImageCache::Key> {}; |
89 | 37 |
90 | 38 |
91 /////////////////////////////////////////////////////////////////////////////// | 39 /////////////////////////////////////////////////////////////////////////////// |
92 | 40 |
93 // experimental hash to speed things up | 41 // experimental hash to speed things up |
94 #define USE_HASH | 42 #define USE_HASH |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
253 while (rec) { | 201 while (rec) { |
254 Rec* next = rec->fNext; | 202 Rec* next = rec->fNext; |
255 SkDELETE(rec); | 203 SkDELETE(rec); |
256 rec = next; | 204 rec = next; |
257 } | 205 } |
258 delete fHash; | 206 delete fHash; |
259 } | 207 } |
260 | 208 |
261 //////////////////////////////////////////////////////////////////////////////// | 209 //////////////////////////////////////////////////////////////////////////////// |
262 | 210 |
263 /** | 211 const SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(const Key& key) { |
264 This private method is the fully general record finder. All other | |
265 record finders should call this function or the one above. | |
266 */ | |
267 SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(const SkScaledImageCach
e::Key& key) { | |
268 #ifdef USE_HASH | 212 #ifdef USE_HASH |
269 Rec* rec = fHash->find(key); | 213 Rec* rec = fHash->find(key); |
270 #else | 214 #else |
271 Rec* rec = find_rec_in_list(fHead, key); | 215 Rec* rec = find_rec_in_list(fHead, key); |
272 #endif | 216 #endif |
273 if (rec) { | 217 if (rec) { |
274 this->moveToHead(rec); // for our LRU | 218 this->moveToHead(rec); // for our LRU |
275 rec->fLockCount += 1; | 219 rec->fLockCount += 1; |
276 } | 220 } |
277 return rec; | 221 return rec; |
278 } | 222 } |
279 | 223 |
280 SkScaledImageCache::ID* SkScaledImageCache::findAndLock(const Key& key, SkBitmap
* result) { | 224 const SkScaledImageCache::Rec* SkScaledImageCache::addAndLock(Rec* rec) { |
281 Rec* rec = this->findAndLock(key); | |
282 if (rec) { | |
283 SkASSERT(NULL == rec->fMip); | |
284 SkASSERT(rec->fBitmap.pixelRef()); | |
285 *result = rec->fBitmap; | |
286 } | |
287 return rec_to_id(rec); | |
288 } | |
289 | |
290 SkScaledImageCache::ID* SkScaledImageCache::findAndLock(const Key& key, const Sk
MipMap** mip) { | |
291 Rec* rec = this->findAndLock(key); | |
292 if (rec) { | |
293 SkASSERT(rec->fMip); | |
294 SkASSERT(NULL == rec->fBitmap.pixelRef()); | |
295 *mip = rec->fMip; | |
296 } | |
297 return rec_to_id(rec); | |
298 } | |
299 | |
300 | |
301 //////////////////////////////////////////////////////////////////////////////// | |
302 /** | |
303 This private method is the fully general record adder. All other | |
304 record adders should call this funtion. */ | |
305 SkScaledImageCache::ID* SkScaledImageCache::addAndLock(SkScaledImageCache::Rec*
rec) { | |
306 SkASSERT(rec); | 225 SkASSERT(rec); |
307 // See if we already have this key (racy inserts, etc.) | 226 // See if we already have this key (racy inserts, etc.) |
308 Rec* existing = this->findAndLock(*rec->fKey); | 227 const Rec* existing = this->findAndLock(rec->getKey()); |
309 if (NULL != existing) { | 228 if (NULL != existing) { |
310 // Since we already have a matching entry, just delete the new one and r
eturn. | |
311 // Call sites cannot assume the passed in object will live past this cal
l. | |
312 existing->fBitmap = rec->fBitmap; | |
313 SkDELETE(rec); | 229 SkDELETE(rec); |
314 return rec_to_id(existing); | 230 return existing; |
315 } | 231 } |
316 | 232 |
317 this->addToHead(rec); | 233 this->addToHead(rec); |
318 SkASSERT(1 == rec->fLockCount); | 234 SkASSERT(1 == rec->fLockCount); |
319 #ifdef USE_HASH | 235 #ifdef USE_HASH |
320 SkASSERT(fHash); | 236 SkASSERT(fHash); |
321 fHash->add(rec); | 237 fHash->add(rec); |
322 #endif | 238 #endif |
323 // We may (now) be overbudget, so see if we need to purge something. | 239 // We may (now) be overbudget, so see if we need to purge something. |
324 this->purgeAsNeeded(); | 240 this->purgeAsNeeded(); |
325 return rec_to_id(rec); | 241 return rec; |
326 } | 242 } |
327 | 243 |
328 SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const Key& key, const SkB
itmap& scaled) { | 244 void SkScaledImageCache::add(Rec* rec) { |
329 Rec* rec = SkNEW_ARGS(Rec, (key, scaled)); | 245 SkASSERT(rec); |
330 return this->addAndLock(rec); | 246 // See if we already have this key (racy inserts, etc.) |
| 247 const Rec* existing = this->findAndLock(rec->getKey()); |
| 248 if (NULL != existing) { |
| 249 SkDELETE(rec); |
| 250 this->unlock(existing); |
| 251 return; |
| 252 } |
| 253 |
| 254 this->addToHead(rec); |
| 255 SkASSERT(1 == rec->fLockCount); |
| 256 #ifdef USE_HASH |
| 257 SkASSERT(fHash); |
| 258 fHash->add(rec); |
| 259 #endif |
| 260 this->unlock(rec); |
331 } | 261 } |
332 | 262 |
333 SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const Key& key, const SkM
ipMap* mip) { | 263 void SkScaledImageCache::unlock(SkScaledImageCache::ID id) { |
334 Rec* rec = SkNEW_ARGS(Rec, (key, mip)); | |
335 return this->addAndLock(rec); | |
336 } | |
337 | |
338 void SkScaledImageCache::unlock(SkScaledImageCache::ID* id) { | |
339 SkASSERT(id); | 264 SkASSERT(id); |
340 | 265 |
341 #ifdef SK_DEBUG | 266 #ifdef SK_DEBUG |
342 { | 267 { |
343 bool found = false; | 268 bool found = false; |
344 Rec* rec = fHead; | 269 Rec* rec = fHead; |
345 while (rec != NULL) { | 270 while (rec != NULL) { |
346 if (rec == id_to_rec(id)) { | 271 if (rec == id) { |
347 found = true; | 272 found = true; |
348 break; | 273 break; |
349 } | 274 } |
350 rec = rec->fNext; | 275 rec = rec->fNext; |
351 } | 276 } |
352 SkASSERT(found); | 277 SkASSERT(found); |
353 } | 278 } |
354 #endif | 279 #endif |
355 Rec* rec = id_to_rec(id); | 280 const Rec* rec = id; |
356 SkASSERT(rec->fLockCount > 0); | 281 SkASSERT(rec->fLockCount > 0); |
357 rec->fLockCount -= 1; | 282 const_cast<Rec*>(rec)->fLockCount -= 1; |
358 | 283 |
359 // we may have been over-budget, but now have released something, so check | 284 // we may have been over-budget, but now have released something, so check |
360 // if we should purge. | 285 // if we should purge. |
361 if (0 == rec->fLockCount) { | 286 if (0 == rec->fLockCount) { |
362 this->purgeAsNeeded(); | 287 this->purgeAsNeeded(); |
363 } | 288 } |
364 } | 289 } |
365 | 290 |
366 void SkScaledImageCache::purgeAsNeeded() { | 291 void SkScaledImageCache::purgeAsNeeded() { |
367 size_t byteLimit; | 292 size_t byteLimit; |
(...skipping 15 matching lines...) Expand all Loading... |
383 if (bytesUsed < byteLimit && countUsed < countLimit) { | 308 if (bytesUsed < byteLimit && countUsed < countLimit) { |
384 break; | 309 break; |
385 } | 310 } |
386 | 311 |
387 Rec* prev = rec->fPrev; | 312 Rec* prev = rec->fPrev; |
388 if (0 == rec->fLockCount) { | 313 if (0 == rec->fLockCount) { |
389 size_t used = rec->bytesUsed(); | 314 size_t used = rec->bytesUsed(); |
390 SkASSERT(used <= bytesUsed); | 315 SkASSERT(used <= bytesUsed); |
391 this->detach(rec); | 316 this->detach(rec); |
392 #ifdef USE_HASH | 317 #ifdef USE_HASH |
393 fHash->remove(*rec->fKey); | 318 fHash->remove(rec->getKey()); |
394 #endif | 319 #endif |
395 | 320 |
396 SkDELETE(rec); | 321 SkDELETE(rec); |
397 | 322 |
398 bytesUsed -= used; | 323 bytesUsed -= used; |
399 countUsed -= 1; | 324 countUsed -= 1; |
400 } | 325 } |
401 rec = prev; | 326 rec = prev; |
402 } | 327 } |
403 | 328 |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
569 #ifdef SK_USE_DISCARDABLE_SCALEDIMAGECACHE | 494 #ifdef SK_USE_DISCARDABLE_SCALEDIMAGECACHE |
570 gScaledImageCache = SkNEW_ARGS(SkScaledImageCache, (SkDiscardableMemory:
:Create)); | 495 gScaledImageCache = SkNEW_ARGS(SkScaledImageCache, (SkDiscardableMemory:
:Create)); |
571 #else | 496 #else |
572 gScaledImageCache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CAC
HE_LIMIT)); | 497 gScaledImageCache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CAC
HE_LIMIT)); |
573 #endif | 498 #endif |
574 atexit(cleanup_gScaledImageCache); | 499 atexit(cleanup_gScaledImageCache); |
575 } | 500 } |
576 return gScaledImageCache; | 501 return gScaledImageCache; |
577 } | 502 } |
578 | 503 |
579 SkScaledImageCache::ID* SkScaledImageCache::FindAndLock(const Key& key, SkBitmap
* result) { | 504 void SkScaledImageCache::Unlock(SkScaledImageCache::ID id) { |
580 SkAutoMutexAcquire am(gMutex); | |
581 return get_cache()->findAndLock(key, result); | |
582 } | |
583 | |
584 SkScaledImageCache::ID* SkScaledImageCache::FindAndLock(const Key& key, SkMipMap
const ** mip) { | |
585 SkAutoMutexAcquire am(gMutex); | |
586 return get_cache()->findAndLock(key, mip); | |
587 } | |
588 | |
589 SkScaledImageCache::ID* SkScaledImageCache::AddAndLock(const Key& key, const SkB
itmap& scaled) { | |
590 SkAutoMutexAcquire am(gMutex); | |
591 return get_cache()->addAndLock(key, scaled); | |
592 } | |
593 | |
594 SkScaledImageCache::ID* SkScaledImageCache::AddAndLock(const Key& key, const SkM
ipMap* mip) { | |
595 SkAutoMutexAcquire am(gMutex); | |
596 return get_cache()->addAndLock(key, mip); | |
597 } | |
598 | |
599 void SkScaledImageCache::Unlock(SkScaledImageCache::ID* id) { | |
600 SkAutoMutexAcquire am(gMutex); | 505 SkAutoMutexAcquire am(gMutex); |
601 get_cache()->unlock(id); | 506 get_cache()->unlock(id); |
602 | 507 |
603 // get_cache()->dump(); | 508 // get_cache()->dump(); |
604 } | 509 } |
605 | 510 |
606 size_t SkScaledImageCache::GetTotalBytesUsed() { | 511 size_t SkScaledImageCache::GetTotalBytesUsed() { |
607 SkAutoMutexAcquire am(gMutex); | 512 SkAutoMutexAcquire am(gMutex); |
608 return get_cache()->getTotalBytesUsed(); | 513 return get_cache()->getTotalBytesUsed(); |
609 } | 514 } |
(...skipping 21 matching lines...) Expand all Loading... |
631 size_t SkScaledImageCache::SetSingleAllocationByteLimit(size_t size) { | 536 size_t SkScaledImageCache::SetSingleAllocationByteLimit(size_t size) { |
632 SkAutoMutexAcquire am(gMutex); | 537 SkAutoMutexAcquire am(gMutex); |
633 return get_cache()->setSingleAllocationByteLimit(size); | 538 return get_cache()->setSingleAllocationByteLimit(size); |
634 } | 539 } |
635 | 540 |
636 size_t SkScaledImageCache::GetSingleAllocationByteLimit() { | 541 size_t SkScaledImageCache::GetSingleAllocationByteLimit() { |
637 SkAutoMutexAcquire am(gMutex); | 542 SkAutoMutexAcquire am(gMutex); |
638 return get_cache()->getSingleAllocationByteLimit(); | 543 return get_cache()->getSingleAllocationByteLimit(); |
639 } | 544 } |
640 | 545 |
| 546 const SkScaledImageCache::Rec* SkScaledImageCache::FindAndLock(const Key& key) { |
| 547 SkAutoMutexAcquire am(gMutex); |
| 548 return get_cache()->findAndLock(key); |
| 549 } |
| 550 |
| 551 const SkScaledImageCache::Rec* SkScaledImageCache::AddAndLock(Rec* rec) { |
| 552 SkAutoMutexAcquire am(gMutex); |
| 553 return get_cache()->addAndLock(rec); |
| 554 } |
| 555 |
| 556 void SkScaledImageCache::Add(Rec* rec) { |
| 557 SkAutoMutexAcquire am(gMutex); |
| 558 get_cache()->add(rec); |
| 559 } |
| 560 |
641 /////////////////////////////////////////////////////////////////////////////// | 561 /////////////////////////////////////////////////////////////////////////////// |
642 | 562 |
643 #include "SkGraphics.h" | 563 #include "SkGraphics.h" |
644 | 564 |
645 size_t SkGraphics::GetImageCacheTotalBytesUsed() { | 565 size_t SkGraphics::GetImageCacheTotalBytesUsed() { |
646 return SkScaledImageCache::GetTotalBytesUsed(); | 566 return SkScaledImageCache::GetTotalBytesUsed(); |
647 } | 567 } |
648 | 568 |
649 size_t SkGraphics::GetImageCacheTotalByteLimit() { | 569 size_t SkGraphics::GetImageCacheTotalByteLimit() { |
650 return SkScaledImageCache::GetTotalByteLimit(); | 570 return SkScaledImageCache::GetTotalByteLimit(); |
651 } | 571 } |
652 | 572 |
653 size_t SkGraphics::SetImageCacheTotalByteLimit(size_t newLimit) { | 573 size_t SkGraphics::SetImageCacheTotalByteLimit(size_t newLimit) { |
654 return SkScaledImageCache::SetTotalByteLimit(newLimit); | 574 return SkScaledImageCache::SetTotalByteLimit(newLimit); |
655 } | 575 } |
656 | 576 |
657 size_t SkGraphics::GetImageCacheSingleAllocationByteLimit() { | 577 size_t SkGraphics::GetImageCacheSingleAllocationByteLimit() { |
658 return SkScaledImageCache::GetSingleAllocationByteLimit(); | 578 return SkScaledImageCache::GetSingleAllocationByteLimit(); |
659 } | 579 } |
660 | 580 |
661 size_t SkGraphics::SetImageCacheSingleAllocationByteLimit(size_t newLimit) { | 581 size_t SkGraphics::SetImageCacheSingleAllocationByteLimit(size_t newLimit) { |
662 return SkScaledImageCache::SetSingleAllocationByteLimit(newLimit); | 582 return SkScaledImageCache::SetSingleAllocationByteLimit(newLimit); |
663 } | 583 } |
664 | 584 |
OLD | NEW |