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