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