Home | History | Annotate | Download | only in core
      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