1 /* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkScaledImageCache.h" 9 #include "SkMipMap.h" 10 #include "SkPixelRef.h" 11 #include "SkRect.h" 12 13 // This can be defined by the caller's build system 14 //#define SK_USE_DISCARDABLE_SCALEDIMAGECACHE 15 16 #ifndef SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT 17 # define SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT 1024 18 #endif 19 20 #ifndef SK_DEFAULT_IMAGE_CACHE_LIMIT 21 #define SK_DEFAULT_IMAGE_CACHE_LIMIT (2 * 1024 * 1024) 22 #endif 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 // Implemented from en.wikipedia.org/wiki/MurmurHash. 33 static uint32_t compute_hash(const uint32_t data[], int count) { 34 uint32_t hash = 0; 35 36 for (int i = 0; i < count; ++i) { 37 uint32_t k = data[i]; 38 k *= 0xcc9e2d51; 39 k = (k << 15) | (k >> 17); 40 k *= 0x1b873593; 41 42 hash ^= k; 43 hash = (hash << 13) | (hash >> 19); 44 hash *= 5; 45 hash += 0xe6546b64; 46 } 47 48 // hash ^= size; 49 hash ^= hash >> 16; 50 hash *= 0x85ebca6b; 51 hash ^= hash >> 13; 52 hash *= 0xc2b2ae35; 53 hash ^= hash >> 16; 54 55 return hash; 56 } 57 58 struct SkScaledImageCache::Key { 59 Key(uint32_t genID, 60 SkScalar scaleX, 61 SkScalar scaleY, 62 SkIRect bounds) 63 : fGenID(genID) 64 , fScaleX(scaleX) 65 , fScaleY(scaleY) 66 , fBounds(bounds) { 67 fHash = compute_hash(&fGenID, 7); 68 } 69 70 bool operator<(const Key& other) const { 71 const uint32_t* a = &fGenID; 72 const uint32_t* b = &other.fGenID; 73 for (int i = 0; i < 7; ++i) { 74 if (a[i] < b[i]) { 75 return true; 76 } 77 if (a[i] > b[i]) { 78 return false; 79 } 80 } 81 return false; 82 } 83 84 bool operator==(const Key& other) const { 85 const uint32_t* a = &fHash; 86 const uint32_t* b = &other.fHash; 87 for (int i = 0; i < 8; ++i) { 88 if (a[i] != b[i]) { 89 return false; 90 } 91 } 92 return true; 93 } 94 95 uint32_t fHash; 96 uint32_t fGenID; 97 float fScaleX; 98 float fScaleY; 99 SkIRect fBounds; 100 }; 101 102 struct SkScaledImageCache::Rec { 103 Rec(const Key& key, const SkBitmap& bm) : fKey(key), fBitmap(bm) { 104 fLockCount = 1; 105 fMip = NULL; 106 } 107 108 Rec(const Key& key, const SkMipMap* mip) : fKey(key) { 109 fLockCount = 1; 110 fMip = mip; 111 mip->ref(); 112 } 113 114 ~Rec() { 115 SkSafeUnref(fMip); 116 } 117 118 static const Key& GetKey(const Rec& rec) { return rec.fKey; } 119 static uint32_t Hash(const Key& key) { return key.fHash; } 120 121 size_t bytesUsed() const { 122 return fMip ? fMip->getSize() : fBitmap.getSize(); 123 } 124 125 Rec* fNext; 126 Rec* fPrev; 127 128 // this guy wants to be 64bit aligned 129 Key fKey; 130 131 int32_t fLockCount; 132 133 // we use either fBitmap or fMip, but not both 134 SkBitmap fBitmap; 135 const SkMipMap* fMip; 136 }; 137 138 #include "SkTDynamicHash.h" 139 140 class SkScaledImageCache::Hash : 141 public SkTDynamicHash<SkScaledImageCache::Rec, SkScaledImageCache::Key> {}; 142 143 144 /////////////////////////////////////////////////////////////////////////////// 145 146 // experimental hash to speed things up 147 #define USE_HASH 148 149 #if !defined(USE_HASH) 150 static inline SkScaledImageCache::Rec* find_rec_in_list( 151 SkScaledImageCache::Rec* head, const Key & key) { 152 SkScaledImageCache::Rec* rec = head; 153 while ((rec != NULL) && (rec->fKey != key)) { 154 rec = rec->fNext; 155 } 156 return rec; 157 } 158 #endif 159 160 void SkScaledImageCache::init() { 161 fHead = NULL; 162 fTail = NULL; 163 #ifdef USE_HASH 164 fHash = new Hash; 165 #else 166 fHash = NULL; 167 #endif 168 fTotalBytesUsed = 0; 169 fCount = 0; 170 fSingleAllocationByteLimit = 0; 171 fAllocator = NULL; 172 173 // One of these should be explicit set by the caller after we return. 174 fTotalByteLimit = 0; 175 fDiscardableFactory = NULL; 176 } 177 178 #include "SkDiscardableMemory.h" 179 180 class SkOneShotDiscardablePixelRef : public SkPixelRef { 181 public: 182 SK_DECLARE_INST_COUNT(SkOneShotDiscardablePixelRef) 183 // Ownership of the discardablememory is transfered to the pixelref 184 SkOneShotDiscardablePixelRef(const SkImageInfo&, SkDiscardableMemory*, size_t rowBytes); 185 ~SkOneShotDiscardablePixelRef(); 186 187 SK_DECLARE_UNFLATTENABLE_OBJECT() 188 189 protected: 190 virtual bool onNewLockPixels(LockRec*) SK_OVERRIDE; 191 virtual void onUnlockPixels() SK_OVERRIDE; 192 virtual size_t getAllocatedSizeInBytes() const SK_OVERRIDE; 193 194 private: 195 SkDiscardableMemory* fDM; 196 size_t fRB; 197 bool fFirstTime; 198 199 typedef SkPixelRef INHERITED; 200 }; 201 202 SkOneShotDiscardablePixelRef::SkOneShotDiscardablePixelRef(const SkImageInfo& info, 203 SkDiscardableMemory* dm, 204 size_t rowBytes) 205 : INHERITED(info) 206 , fDM(dm) 207 , fRB(rowBytes) 208 { 209 SkASSERT(dm->data()); 210 fFirstTime = true; 211 } 212 213 SkOneShotDiscardablePixelRef::~SkOneShotDiscardablePixelRef() { 214 SkDELETE(fDM); 215 } 216 217 bool SkOneShotDiscardablePixelRef::onNewLockPixels(LockRec* rec) { 218 if (fFirstTime) { 219 // we're already locked 220 SkASSERT(fDM->data()); 221 fFirstTime = false; 222 goto SUCCESS; 223 } 224 225 // A previous call to onUnlock may have deleted our DM, so check for that 226 if (NULL == fDM) { 227 return false; 228 } 229 230 if (!fDM->lock()) { 231 // since it failed, we delete it now, to free-up the resource 232 delete fDM; 233 fDM = NULL; 234 return false; 235 } 236 237 SUCCESS: 238 rec->fPixels = fDM->data(); 239 rec->fColorTable = NULL; 240 rec->fRowBytes = fRB; 241 return true; 242 } 243 244 void SkOneShotDiscardablePixelRef::onUnlockPixels() { 245 SkASSERT(!fFirstTime); 246 fDM->unlock(); 247 } 248 249 size_t SkOneShotDiscardablePixelRef::getAllocatedSizeInBytes() const { 250 return this->info().getSafeSize(fRB); 251 } 252 253 class SkScaledImageCacheDiscardableAllocator : public SkBitmap::Allocator { 254 public: 255 SkScaledImageCacheDiscardableAllocator( 256 SkScaledImageCache::DiscardableFactory factory) { 257 SkASSERT(factory); 258 fFactory = factory; 259 } 260 261 virtual bool allocPixelRef(SkBitmap*, SkColorTable*) SK_OVERRIDE; 262 263 private: 264 SkScaledImageCache::DiscardableFactory fFactory; 265 }; 266 267 bool SkScaledImageCacheDiscardableAllocator::allocPixelRef(SkBitmap* bitmap, 268 SkColorTable* ctable) { 269 size_t size = bitmap->getSize(); 270 uint64_t size64 = bitmap->computeSize64(); 271 if (0 == size || size64 > (uint64_t)size) { 272 return false; 273 } 274 275 SkDiscardableMemory* dm = fFactory(size); 276 if (NULL == dm) { 277 return false; 278 } 279 280 // can we relax this? 281 if (kN32_SkColorType != bitmap->colorType()) { 282 return false; 283 } 284 285 SkImageInfo info = bitmap->info(); 286 bitmap->setPixelRef(SkNEW_ARGS(SkOneShotDiscardablePixelRef, 287 (info, dm, bitmap->rowBytes())))->unref(); 288 bitmap->lockPixels(); 289 return bitmap->readyToDraw(); 290 } 291 292 SkScaledImageCache::SkScaledImageCache(DiscardableFactory factory) { 293 this->init(); 294 fDiscardableFactory = factory; 295 296 fAllocator = SkNEW_ARGS(SkScaledImageCacheDiscardableAllocator, (factory)); 297 } 298 299 SkScaledImageCache::SkScaledImageCache(size_t byteLimit) { 300 this->init(); 301 fTotalByteLimit = byteLimit; 302 } 303 304 SkScaledImageCache::~SkScaledImageCache() { 305 SkSafeUnref(fAllocator); 306 307 Rec* rec = fHead; 308 while (rec) { 309 Rec* next = rec->fNext; 310 SkDELETE(rec); 311 rec = next; 312 } 313 delete fHash; 314 } 315 316 //////////////////////////////////////////////////////////////////////////////// 317 318 319 SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(uint32_t genID, 320 SkScalar scaleX, 321 SkScalar scaleY, 322 const SkIRect& bounds) { 323 const Key key(genID, scaleX, scaleY, bounds); 324 return this->findAndLock(key); 325 } 326 327 /** 328 This private method is the fully general record finder. All other 329 record finders should call this function or the one above. */ 330 SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(const SkScaledImageCache::Key& key) { 331 if (key.fBounds.isEmpty()) { 332 return NULL; 333 } 334 #ifdef USE_HASH 335 Rec* rec = fHash->find(key); 336 #else 337 Rec* rec = find_rec_in_list(fHead, key); 338 #endif 339 if (rec) { 340 this->moveToHead(rec); // for our LRU 341 rec->fLockCount += 1; 342 } 343 return rec; 344 } 345 346 /** 347 This function finds the bounds of the bitmap *within its pixelRef*. 348 If the bitmap lacks a pixelRef, it will return an empty rect, since 349 that doesn't make sense. This may be a useful enough function that 350 it should be somewhere else (in SkBitmap?). */ 351 static SkIRect get_bounds_from_bitmap(const SkBitmap& bm) { 352 if (!(bm.pixelRef())) { 353 return SkIRect::MakeEmpty(); 354 } 355 SkIPoint origin = bm.pixelRefOrigin(); 356 return SkIRect::MakeXYWH(origin.fX, origin.fY, bm.width(), bm.height()); 357 } 358 359 360 SkScaledImageCache::ID* SkScaledImageCache::findAndLock(uint32_t genID, 361 int32_t width, 362 int32_t height, 363 SkBitmap* bitmap) { 364 Rec* rec = this->findAndLock(genID, SK_Scalar1, SK_Scalar1, 365 SkIRect::MakeWH(width, height)); 366 if (rec) { 367 SkASSERT(NULL == rec->fMip); 368 SkASSERT(rec->fBitmap.pixelRef()); 369 *bitmap = rec->fBitmap; 370 } 371 return rec_to_id(rec); 372 } 373 374 SkScaledImageCache::ID* SkScaledImageCache::findAndLock(const SkBitmap& orig, 375 SkScalar scaleX, 376 SkScalar scaleY, 377 SkBitmap* scaled) { 378 if (0 == scaleX || 0 == scaleY) { 379 // degenerate, and the key we use for mipmaps 380 return NULL; 381 } 382 Rec* rec = this->findAndLock(orig.getGenerationID(), scaleX, 383 scaleY, get_bounds_from_bitmap(orig)); 384 if (rec) { 385 SkASSERT(NULL == rec->fMip); 386 SkASSERT(rec->fBitmap.pixelRef()); 387 *scaled = rec->fBitmap; 388 } 389 return rec_to_id(rec); 390 } 391 392 SkScaledImageCache::ID* SkScaledImageCache::findAndLockMip(const SkBitmap& orig, 393 SkMipMap const ** mip) { 394 Rec* rec = this->findAndLock(orig.getGenerationID(), 0, 0, 395 get_bounds_from_bitmap(orig)); 396 if (rec) { 397 SkASSERT(rec->fMip); 398 SkASSERT(NULL == rec->fBitmap.pixelRef()); 399 *mip = rec->fMip; 400 } 401 return rec_to_id(rec); 402 } 403 404 405 //////////////////////////////////////////////////////////////////////////////// 406 /** 407 This private method is the fully general record adder. All other 408 record adders should call this funtion. */ 409 SkScaledImageCache::ID* SkScaledImageCache::addAndLock(SkScaledImageCache::Rec* rec) { 410 SkASSERT(rec); 411 // See if we already have this key (racy inserts, etc.) 412 Rec* existing = this->findAndLock(rec->fKey); 413 if (NULL != existing) { 414 // Since we already have a matching entry, just delete the new one and return. 415 // Call sites cannot assume the passed in object will live past this call. 416 existing->fBitmap = rec->fBitmap; 417 SkDELETE(rec); 418 return rec_to_id(existing); 419 } 420 421 this->addToHead(rec); 422 SkASSERT(1 == rec->fLockCount); 423 #ifdef USE_HASH 424 SkASSERT(fHash); 425 fHash->add(rec); 426 #endif 427 // We may (now) be overbudget, so see if we need to purge something. 428 this->purgeAsNeeded(); 429 return rec_to_id(rec); 430 } 431 432 SkScaledImageCache::ID* SkScaledImageCache::addAndLock(uint32_t genID, 433 int32_t width, 434 int32_t height, 435 const SkBitmap& bitmap) { 436 Key key(genID, SK_Scalar1, SK_Scalar1, SkIRect::MakeWH(width, height)); 437 Rec* rec = SkNEW_ARGS(Rec, (key, bitmap)); 438 return this->addAndLock(rec); 439 } 440 441 SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const SkBitmap& orig, 442 SkScalar scaleX, 443 SkScalar scaleY, 444 const SkBitmap& scaled) { 445 if (0 == scaleX || 0 == scaleY) { 446 // degenerate, and the key we use for mipmaps 447 return NULL; 448 } 449 SkIRect bounds = get_bounds_from_bitmap(orig); 450 if (bounds.isEmpty()) { 451 return NULL; 452 } 453 Key key(orig.getGenerationID(), scaleX, scaleY, bounds); 454 Rec* rec = SkNEW_ARGS(Rec, (key, scaled)); 455 return this->addAndLock(rec); 456 } 457 458 SkScaledImageCache::ID* SkScaledImageCache::addAndLockMip(const SkBitmap& orig, 459 const SkMipMap* mip) { 460 SkIRect bounds = get_bounds_from_bitmap(orig); 461 if (bounds.isEmpty()) { 462 return NULL; 463 } 464 Key key(orig.getGenerationID(), 0, 0, bounds); 465 Rec* rec = SkNEW_ARGS(Rec, (key, mip)); 466 return this->addAndLock(rec); 467 } 468 469 void SkScaledImageCache::unlock(SkScaledImageCache::ID* id) { 470 SkASSERT(id); 471 472 #ifdef SK_DEBUG 473 { 474 bool found = false; 475 Rec* rec = fHead; 476 while (rec != NULL) { 477 if (rec == id_to_rec(id)) { 478 found = true; 479 break; 480 } 481 rec = rec->fNext; 482 } 483 SkASSERT(found); 484 } 485 #endif 486 Rec* rec = id_to_rec(id); 487 SkASSERT(rec->fLockCount > 0); 488 rec->fLockCount -= 1; 489 490 // we may have been over-budget, but now have released something, so check 491 // if we should purge. 492 if (0 == rec->fLockCount) { 493 this->purgeAsNeeded(); 494 } 495 } 496 497 void SkScaledImageCache::purgeAsNeeded() { 498 size_t byteLimit; 499 int countLimit; 500 501 if (fDiscardableFactory) { 502 countLimit = SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT; 503 byteLimit = SK_MaxU32; // no limit based on bytes 504 } else { 505 countLimit = SK_MaxS32; // no limit based on count 506 byteLimit = fTotalByteLimit; 507 } 508 509 size_t bytesUsed = fTotalBytesUsed; 510 int countUsed = fCount; 511 512 Rec* rec = fTail; 513 while (rec) { 514 if (bytesUsed < byteLimit && countUsed < countLimit) { 515 break; 516 } 517 518 Rec* prev = rec->fPrev; 519 if (0 == rec->fLockCount) { 520 size_t used = rec->bytesUsed(); 521 SkASSERT(used <= bytesUsed); 522 this->detach(rec); 523 #ifdef USE_HASH 524 fHash->remove(rec->fKey); 525 #endif 526 527 SkDELETE(rec); 528 529 bytesUsed -= used; 530 countUsed -= 1; 531 } 532 rec = prev; 533 } 534 535 fTotalBytesUsed = bytesUsed; 536 fCount = countUsed; 537 } 538 539 size_t SkScaledImageCache::setTotalByteLimit(size_t newLimit) { 540 size_t prevLimit = fTotalByteLimit; 541 fTotalByteLimit = newLimit; 542 if (newLimit < prevLimit) { 543 this->purgeAsNeeded(); 544 } 545 return prevLimit; 546 } 547 548 /////////////////////////////////////////////////////////////////////////////// 549 550 void SkScaledImageCache::detach(Rec* rec) { 551 Rec* prev = rec->fPrev; 552 Rec* next = rec->fNext; 553 554 if (!prev) { 555 SkASSERT(fHead == rec); 556 fHead = next; 557 } else { 558 prev->fNext = next; 559 } 560 561 if (!next) { 562 fTail = prev; 563 } else { 564 next->fPrev = prev; 565 } 566 567 rec->fNext = rec->fPrev = NULL; 568 } 569 570 void SkScaledImageCache::moveToHead(Rec* rec) { 571 if (fHead == rec) { 572 return; 573 } 574 575 SkASSERT(fHead); 576 SkASSERT(fTail); 577 578 this->validate(); 579 580 this->detach(rec); 581 582 fHead->fPrev = rec; 583 rec->fNext = fHead; 584 fHead = rec; 585 586 this->validate(); 587 } 588 589 void SkScaledImageCache::addToHead(Rec* rec) { 590 this->validate(); 591 592 rec->fPrev = NULL; 593 rec->fNext = fHead; 594 if (fHead) { 595 fHead->fPrev = rec; 596 } 597 fHead = rec; 598 if (!fTail) { 599 fTail = rec; 600 } 601 fTotalBytesUsed += rec->bytesUsed(); 602 fCount += 1; 603 604 this->validate(); 605 } 606 607 /////////////////////////////////////////////////////////////////////////////// 608 609 #ifdef SK_DEBUG 610 void SkScaledImageCache::validate() const { 611 if (NULL == fHead) { 612 SkASSERT(NULL == fTail); 613 SkASSERT(0 == fTotalBytesUsed); 614 return; 615 } 616 617 if (fHead == fTail) { 618 SkASSERT(NULL == fHead->fPrev); 619 SkASSERT(NULL == fHead->fNext); 620 SkASSERT(fHead->bytesUsed() == fTotalBytesUsed); 621 return; 622 } 623 624 SkASSERT(NULL == fHead->fPrev); 625 SkASSERT(NULL != fHead->fNext); 626 SkASSERT(NULL == fTail->fNext); 627 SkASSERT(NULL != fTail->fPrev); 628 629 size_t used = 0; 630 int count = 0; 631 const Rec* rec = fHead; 632 while (rec) { 633 count += 1; 634 used += rec->bytesUsed(); 635 SkASSERT(used <= fTotalBytesUsed); 636 rec = rec->fNext; 637 } 638 SkASSERT(fCount == count); 639 640 rec = fTail; 641 while (rec) { 642 SkASSERT(count > 0); 643 count -= 1; 644 SkASSERT(used >= rec->bytesUsed()); 645 used -= rec->bytesUsed(); 646 rec = rec->fPrev; 647 } 648 649 SkASSERT(0 == count); 650 SkASSERT(0 == used); 651 } 652 #endif 653 654 void SkScaledImageCache::dump() const { 655 this->validate(); 656 657 const Rec* rec = fHead; 658 int locked = 0; 659 while (rec) { 660 locked += rec->fLockCount > 0; 661 rec = rec->fNext; 662 } 663 664 SkDebugf("SkScaledImageCache: count=%d bytes=%d locked=%d %s\n", 665 fCount, fTotalBytesUsed, locked, 666 fDiscardableFactory ? "discardable" : "malloc"); 667 } 668 669 size_t SkScaledImageCache::setSingleAllocationByteLimit(size_t newLimit) { 670 size_t oldLimit = fSingleAllocationByteLimit; 671 fSingleAllocationByteLimit = newLimit; 672 return oldLimit; 673 } 674 675 size_t SkScaledImageCache::getSingleAllocationByteLimit() const { 676 return fSingleAllocationByteLimit; 677 } 678 679 /////////////////////////////////////////////////////////////////////////////// 680 681 #include "SkThread.h" 682 683 SK_DECLARE_STATIC_MUTEX(gMutex); 684 static SkScaledImageCache* gScaledImageCache = NULL; 685 static void cleanup_gScaledImageCache() { 686 // We'll clean this up in our own tests, but disable for clients. 687 // Chrome seems to have funky multi-process things going on in unit tests that 688 // makes this unsafe to delete when the main process atexit()s. 689 // SkLazyPtr does the same sort of thing. 690 #if SK_DEVELOPER 691 SkDELETE(gScaledImageCache); 692 #endif 693 } 694 695 /** Must hold gMutex when calling. */ 696 static SkScaledImageCache* get_cache() { 697 // gMutex is always held when this is called, so we don't need to be fancy in here. 698 gMutex.assertHeld(); 699 if (NULL == gScaledImageCache) { 700 #ifdef SK_USE_DISCARDABLE_SCALEDIMAGECACHE 701 gScaledImageCache = SkNEW_ARGS(SkScaledImageCache, (SkDiscardableMemory::Create)); 702 #else 703 gScaledImageCache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CACHE_LIMIT)); 704 #endif 705 atexit(cleanup_gScaledImageCache); 706 } 707 return gScaledImageCache; 708 } 709 710 711 SkScaledImageCache::ID* SkScaledImageCache::FindAndLock( 712 uint32_t pixelGenerationID, 713 int32_t width, 714 int32_t height, 715 SkBitmap* scaled) { 716 SkAutoMutexAcquire am(gMutex); 717 return get_cache()->findAndLock(pixelGenerationID, width, height, scaled); 718 } 719 720 SkScaledImageCache::ID* SkScaledImageCache::AddAndLock( 721 uint32_t pixelGenerationID, 722 int32_t width, 723 int32_t height, 724 const SkBitmap& scaled) { 725 SkAutoMutexAcquire am(gMutex); 726 return get_cache()->addAndLock(pixelGenerationID, width, height, scaled); 727 } 728 729 730 SkScaledImageCache::ID* SkScaledImageCache::FindAndLock(const SkBitmap& orig, 731 SkScalar scaleX, 732 SkScalar scaleY, 733 SkBitmap* scaled) { 734 SkAutoMutexAcquire am(gMutex); 735 return get_cache()->findAndLock(orig, scaleX, scaleY, scaled); 736 } 737 738 SkScaledImageCache::ID* SkScaledImageCache::FindAndLockMip(const SkBitmap& orig, 739 SkMipMap const ** mip) { 740 SkAutoMutexAcquire am(gMutex); 741 return get_cache()->findAndLockMip(orig, mip); 742 } 743 744 SkScaledImageCache::ID* SkScaledImageCache::AddAndLock(const SkBitmap& orig, 745 SkScalar scaleX, 746 SkScalar scaleY, 747 const SkBitmap& scaled) { 748 SkAutoMutexAcquire am(gMutex); 749 return get_cache()->addAndLock(orig, scaleX, scaleY, scaled); 750 } 751 752 SkScaledImageCache::ID* SkScaledImageCache::AddAndLockMip(const SkBitmap& orig, 753 const SkMipMap* mip) { 754 SkAutoMutexAcquire am(gMutex); 755 return get_cache()->addAndLockMip(orig, mip); 756 } 757 758 void SkScaledImageCache::Unlock(SkScaledImageCache::ID* id) { 759 SkAutoMutexAcquire am(gMutex); 760 get_cache()->unlock(id); 761 762 // get_cache()->dump(); 763 } 764 765 size_t SkScaledImageCache::GetTotalBytesUsed() { 766 SkAutoMutexAcquire am(gMutex); 767 return get_cache()->getTotalBytesUsed(); 768 } 769 770 size_t SkScaledImageCache::GetTotalByteLimit() { 771 SkAutoMutexAcquire am(gMutex); 772 return get_cache()->getTotalByteLimit(); 773 } 774 775 size_t SkScaledImageCache::SetTotalByteLimit(size_t newLimit) { 776 SkAutoMutexAcquire am(gMutex); 777 return get_cache()->setTotalByteLimit(newLimit); 778 } 779 780 SkBitmap::Allocator* SkScaledImageCache::GetAllocator() { 781 SkAutoMutexAcquire am(gMutex); 782 return get_cache()->allocator(); 783 } 784 785 void SkScaledImageCache::Dump() { 786 SkAutoMutexAcquire am(gMutex); 787 get_cache()->dump(); 788 } 789 790 size_t SkScaledImageCache::SetSingleAllocationByteLimit(size_t size) { 791 SkAutoMutexAcquire am(gMutex); 792 return get_cache()->setSingleAllocationByteLimit(size); 793 } 794 795 size_t SkScaledImageCache::GetSingleAllocationByteLimit() { 796 SkAutoMutexAcquire am(gMutex); 797 return get_cache()->getSingleAllocationByteLimit(); 798 } 799 800 /////////////////////////////////////////////////////////////////////////////// 801 802 #include "SkGraphics.h" 803 804 size_t SkGraphics::GetImageCacheTotalBytesUsed() { 805 return SkScaledImageCache::GetTotalBytesUsed(); 806 } 807 808 size_t SkGraphics::GetImageCacheTotalByteLimit() { 809 return SkScaledImageCache::GetTotalByteLimit(); 810 } 811 812 size_t SkGraphics::SetImageCacheTotalByteLimit(size_t newLimit) { 813 return SkScaledImageCache::SetTotalByteLimit(newLimit); 814 } 815 816 size_t SkGraphics::GetImageCacheSingleAllocationByteLimit() { 817 return SkScaledImageCache::GetSingleAllocationByteLimit(); 818 } 819 820 size_t SkGraphics::SetImageCacheSingleAllocationByteLimit(size_t newLimit) { 821 return SkScaledImageCache::SetSingleAllocationByteLimit(newLimit); 822 } 823 824