• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
rec_to_id(SkScaledImageCache::Rec * rec)25 static inline SkScaledImageCache::ID* rec_to_id(SkScaledImageCache::Rec* rec) {
26     return reinterpret_cast<SkScaledImageCache::ID*>(rec);
27 }
28 
id_to_rec(SkScaledImageCache::ID * id)29 static 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.
compute_hash(const uint32_t data[],int count)34 static 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 
59 struct SkScaledImageCache::Key {
KeySkScaledImageCache::Key60     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 
operator <SkScaledImageCache::Key71     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 
operator ==SkScaledImageCache::Key85     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 
103 struct SkScaledImageCache::Rec {
RecSkScaledImageCache::Rec104     Rec(const Key& key, const SkBitmap& bm) : fKey(key), fBitmap(bm) {
105         fLockCount = 1;
106         fMip = NULL;
107     }
108 
RecSkScaledImageCache::Rec109     Rec(const Key& key, const SkMipMap* mip) : fKey(key) {
110         fLockCount = 1;
111         fMip = mip;
112         mip->ref();
113     }
114 
~RecSkScaledImageCache::Rec115     ~Rec() {
116         SkSafeUnref(fMip);
117     }
118 
bytesUsedSkScaledImageCache::Rec119     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 
138 namespace { // can't use static functions w/ template parameters
key_from_rec(const SkScaledImageCache::Rec & rec)139 const SkScaledImageCache::Key& key_from_rec(const SkScaledImageCache::Rec& rec) {
140     return rec.fKey;
141 }
142 
hash_from_key(const SkScaledImageCache::Key & key)143 uint32_t hash_from_key(const SkScaledImageCache::Key& key) {
144     return key.fHash;
145 }
146 
eq_rec_key(const SkScaledImageCache::Rec & rec,const SkScaledImageCache::Key & key)147 bool eq_rec_key(const SkScaledImageCache::Rec& rec, const SkScaledImageCache::Key& key) {
148     return rec.fKey == key;
149 }
150 }
151 
152 class 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)
find_rec_in_list(SkScaledImageCache::Rec * head,const Key & key)164 static 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 
init()174 void 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 
193 class SkOneShotDiscardablePixelRef : public SkPixelRef {
194 public:
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 
201 protected:
202     virtual void* onLockPixels(SkColorTable**) SK_OVERRIDE;
203     virtual void onUnlockPixels() SK_OVERRIDE;
204     virtual size_t getAllocatedSizeInBytes() const SK_OVERRIDE;
205 
206 private:
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 
SkOneShotDiscardablePixelRef(const SkImageInfo & info,SkDiscardableMemory * dm,size_t rowBytes)216 SkOneShotDiscardablePixelRef::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 
~SkOneShotDiscardablePixelRef()229 SkOneShotDiscardablePixelRef::~SkOneShotDiscardablePixelRef() {
230     SkDELETE(fDM);
231 }
232 
onLockPixels(SkColorTable ** ctable)233 void* 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 
onUnlockPixels()255 void SkOneShotDiscardablePixelRef::onUnlockPixels() {
256     SkASSERT(!fFirstTime);
257     fDM->unlock();
258 }
259 
getAllocatedSizeInBytes() const260 size_t SkOneShotDiscardablePixelRef::getAllocatedSizeInBytes() const {
261     return fInfo.fHeight * fRB;
262 }
263 
264 class SkScaledImageCacheDiscardableAllocator : public SkBitmap::Allocator {
265 public:
SkScaledImageCacheDiscardableAllocator(SkScaledImageCache::DiscardableFactory factory)266     SkScaledImageCacheDiscardableAllocator(
267                             SkScaledImageCache::DiscardableFactory factory) {
268         SkASSERT(factory);
269         fFactory = factory;
270     }
271 
272     virtual bool allocPixelRef(SkBitmap*, SkColorTable*) SK_OVERRIDE;
273 
274 private:
275     SkScaledImageCache::DiscardableFactory fFactory;
276 };
277 
allocPixelRef(SkBitmap * bitmap,SkColorTable * ctable)278 bool 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 
SkScaledImageCache(DiscardableFactory factory)308 SkScaledImageCache::SkScaledImageCache(DiscardableFactory factory) {
309     this->init();
310     fDiscardableFactory = factory;
311 
312     fAllocator = SkNEW_ARGS(SkScaledImageCacheDiscardableAllocator, (factory));
313 }
314 
SkScaledImageCache(size_t byteLimit)315 SkScaledImageCache::SkScaledImageCache(size_t byteLimit) {
316     this->init();
317     fByteLimit = byteLimit;
318 }
319 
~SkScaledImageCache()320 SkScaledImageCache::~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 
findAndLock(uint32_t genID,SkScalar scaleX,SkScalar scaleY,const SkIRect & bounds)335 SkScaledImageCache::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. */
findAndLock(const SkScaledImageCache::Key & key)346 SkScaledImageCache::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?). */
get_bounds_from_bitmap(const SkBitmap & bm)367 static 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 
findAndLock(uint32_t genID,int32_t width,int32_t height,SkBitmap * bitmap)378 SkScaledImageCache::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 
findAndLock(const SkBitmap & orig,SkScalar scaleX,SkScalar scaleY,SkBitmap * scaled)392 SkScaledImageCache::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 
findAndLockMip(const SkBitmap & orig,SkMipMap const ** mip)410 SkScaledImageCache::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. */
addAndLock(SkScaledImageCache::Rec * rec)427 SkScaledImageCache::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 (existing != NULL) {
432         return rec_to_id(existing);
433     }
434 
435     this->addToHead(rec);
436     SkASSERT(1 == rec->fLockCount);
437 #ifdef USE_HASH
438     SkASSERT(fHash);
439     fHash->add(rec);
440 #endif
441     // We may (now) be overbudget, so see if we need to purge something.
442     this->purgeAsNeeded();
443     return rec_to_id(rec);
444 }
445 
addAndLock(uint32_t genID,int32_t width,int32_t height,const SkBitmap & bitmap)446 SkScaledImageCache::ID* SkScaledImageCache::addAndLock(uint32_t genID,
447                                                        int32_t width,
448                                                        int32_t height,
449                                                        const SkBitmap& bitmap) {
450     Key key(genID, SK_Scalar1, SK_Scalar1, SkIRect::MakeWH(width, height));
451     Rec* rec = SkNEW_ARGS(Rec, (key, bitmap));
452     return this->addAndLock(rec);
453 }
454 
addAndLock(const SkBitmap & orig,SkScalar scaleX,SkScalar scaleY,const SkBitmap & scaled)455 SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const SkBitmap& orig,
456                                                        SkScalar scaleX,
457                                                        SkScalar scaleY,
458                                                        const SkBitmap& scaled) {
459     if (0 == scaleX || 0 == scaleY) {
460         // degenerate, and the key we use for mipmaps
461         return NULL;
462     }
463     SkIRect bounds = get_bounds_from_bitmap(orig);
464     if (bounds.isEmpty()) {
465         return NULL;
466     }
467     Key key(orig.getGenerationID(), scaleX, scaleY, bounds);
468     Rec* rec = SkNEW_ARGS(Rec, (key, scaled));
469     return this->addAndLock(rec);
470 }
471 
addAndLockMip(const SkBitmap & orig,const SkMipMap * mip)472 SkScaledImageCache::ID* SkScaledImageCache::addAndLockMip(const SkBitmap& orig,
473                                                           const SkMipMap* mip) {
474     SkIRect bounds = get_bounds_from_bitmap(orig);
475     if (bounds.isEmpty()) {
476         return NULL;
477     }
478     Key key(orig.getGenerationID(), 0, 0, bounds);
479     Rec* rec = SkNEW_ARGS(Rec, (key, mip));
480     return this->addAndLock(rec);
481 }
482 
unlock(SkScaledImageCache::ID * id)483 void SkScaledImageCache::unlock(SkScaledImageCache::ID* id) {
484     SkASSERT(id);
485 
486 #ifdef SK_DEBUG
487     {
488         bool found = false;
489         Rec* rec = fHead;
490         while (rec != NULL) {
491             if (rec == id_to_rec(id)) {
492                 found = true;
493                 break;
494             }
495             rec = rec->fNext;
496         }
497         SkASSERT(found);
498     }
499 #endif
500     Rec* rec = id_to_rec(id);
501     SkASSERT(rec->fLockCount > 0);
502     rec->fLockCount -= 1;
503 
504     // we may have been over-budget, but now have released something, so check
505     // if we should purge.
506     if (0 == rec->fLockCount) {
507         this->purgeAsNeeded();
508     }
509 }
510 
purgeAsNeeded()511 void SkScaledImageCache::purgeAsNeeded() {
512     size_t byteLimit;
513     int    countLimit;
514 
515     if (fDiscardableFactory) {
516         countLimit = SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT;
517         byteLimit = SK_MaxU32;  // no limit based on bytes
518     } else {
519         countLimit = SK_MaxS32; // no limit based on count
520         byteLimit = fByteLimit;
521     }
522 
523     size_t bytesUsed = fBytesUsed;
524     int    countUsed = fCount;
525 
526     Rec* rec = fTail;
527     while (rec) {
528         if (bytesUsed < byteLimit && countUsed < countLimit) {
529             break;
530         }
531 
532         Rec* prev = rec->fPrev;
533         if (0 == rec->fLockCount) {
534             size_t used = rec->bytesUsed();
535             SkASSERT(used <= bytesUsed);
536             this->detach(rec);
537 #ifdef USE_HASH
538             fHash->remove(rec->fKey);
539 #endif
540 
541             SkDELETE(rec);
542 
543             bytesUsed -= used;
544             countUsed -= 1;
545         }
546         rec = prev;
547     }
548 
549     fBytesUsed = bytesUsed;
550     fCount = countUsed;
551 }
552 
setByteLimit(size_t newLimit)553 size_t SkScaledImageCache::setByteLimit(size_t newLimit) {
554     size_t prevLimit = fByteLimit;
555     fByteLimit = newLimit;
556     if (newLimit < prevLimit) {
557         this->purgeAsNeeded();
558     }
559     return prevLimit;
560 }
561 
562 ///////////////////////////////////////////////////////////////////////////////
563 
detach(Rec * rec)564 void SkScaledImageCache::detach(Rec* rec) {
565     Rec* prev = rec->fPrev;
566     Rec* next = rec->fNext;
567 
568     if (!prev) {
569         SkASSERT(fHead == rec);
570         fHead = next;
571     } else {
572         prev->fNext = next;
573     }
574 
575     if (!next) {
576         fTail = prev;
577     } else {
578         next->fPrev = prev;
579     }
580 
581     rec->fNext = rec->fPrev = NULL;
582 }
583 
moveToHead(Rec * rec)584 void SkScaledImageCache::moveToHead(Rec* rec) {
585     if (fHead == rec) {
586         return;
587     }
588 
589     SkASSERT(fHead);
590     SkASSERT(fTail);
591 
592     this->validate();
593 
594     this->detach(rec);
595 
596     fHead->fPrev = rec;
597     rec->fNext = fHead;
598     fHead = rec;
599 
600     this->validate();
601 }
602 
addToHead(Rec * rec)603 void SkScaledImageCache::addToHead(Rec* rec) {
604     this->validate();
605 
606     rec->fPrev = NULL;
607     rec->fNext = fHead;
608     if (fHead) {
609         fHead->fPrev = rec;
610     }
611     fHead = rec;
612     if (!fTail) {
613         fTail = rec;
614     }
615     fBytesUsed += rec->bytesUsed();
616     fCount += 1;
617 
618     this->validate();
619 }
620 
621 ///////////////////////////////////////////////////////////////////////////////
622 
623 #ifdef SK_DEBUG
validate() const624 void SkScaledImageCache::validate() const {
625     if (NULL == fHead) {
626         SkASSERT(NULL == fTail);
627         SkASSERT(0 == fBytesUsed);
628         return;
629     }
630 
631     if (fHead == fTail) {
632         SkASSERT(NULL == fHead->fPrev);
633         SkASSERT(NULL == fHead->fNext);
634         SkASSERT(fHead->bytesUsed() == fBytesUsed);
635         return;
636     }
637 
638     SkASSERT(NULL == fHead->fPrev);
639     SkASSERT(NULL != fHead->fNext);
640     SkASSERT(NULL == fTail->fNext);
641     SkASSERT(NULL != fTail->fPrev);
642 
643     size_t used = 0;
644     int count = 0;
645     const Rec* rec = fHead;
646     while (rec) {
647         count += 1;
648         used += rec->bytesUsed();
649         SkASSERT(used <= fBytesUsed);
650         rec = rec->fNext;
651     }
652     SkASSERT(fCount == count);
653 
654     rec = fTail;
655     while (rec) {
656         SkASSERT(count > 0);
657         count -= 1;
658         SkASSERT(used >= rec->bytesUsed());
659         used -= rec->bytesUsed();
660         rec = rec->fPrev;
661     }
662 
663     SkASSERT(0 == count);
664     SkASSERT(0 == used);
665 }
666 #endif
667 
dump() const668 void SkScaledImageCache::dump() const {
669     this->validate();
670 
671     const Rec* rec = fHead;
672     int locked = 0;
673     while (rec) {
674         locked += rec->fLockCount > 0;
675         rec = rec->fNext;
676     }
677 
678     SkDebugf("SkScaledImageCache: count=%d bytes=%d locked=%d %s\n",
679              fCount, fBytesUsed, locked,
680              fDiscardableFactory ? "discardable" : "malloc");
681 }
682 
683 ///////////////////////////////////////////////////////////////////////////////
684 
685 #include "SkThread.h"
686 
687 SK_DECLARE_STATIC_MUTEX(gMutex);
688 
create_cache(SkScaledImageCache ** cache)689 static void create_cache(SkScaledImageCache** cache) {
690 #ifdef SK_USE_DISCARDABLE_SCALEDIMAGECACHE
691     *cache = SkNEW_ARGS(SkScaledImageCache, (SkDiscardableMemory::Create));
692 #else
693     *cache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CACHE_LIMIT));
694 #endif
695 }
696 
get_cache()697 static SkScaledImageCache* get_cache() {
698     static SkScaledImageCache* gCache(NULL);
699     SK_DECLARE_STATIC_ONCE(create_cache_once);
700     SkOnce(&create_cache_once, create_cache, &gCache);
701     SkASSERT(NULL != gCache);
702     return gCache;
703 }
704 
705 
FindAndLock(uint32_t pixelGenerationID,int32_t width,int32_t height,SkBitmap * scaled)706 SkScaledImageCache::ID* SkScaledImageCache::FindAndLock(
707                                 uint32_t pixelGenerationID,
708                                 int32_t width,
709                                 int32_t height,
710                                 SkBitmap* scaled) {
711     SkAutoMutexAcquire am(gMutex);
712     return get_cache()->findAndLock(pixelGenerationID, width, height, scaled);
713 }
714 
AddAndLock(uint32_t pixelGenerationID,int32_t width,int32_t height,const SkBitmap & scaled)715 SkScaledImageCache::ID* SkScaledImageCache::AddAndLock(
716                                uint32_t pixelGenerationID,
717                                int32_t width,
718                                int32_t height,
719                                const SkBitmap& scaled) {
720     SkAutoMutexAcquire am(gMutex);
721     return get_cache()->addAndLock(pixelGenerationID, width, height, scaled);
722 }
723 
724 
FindAndLock(const SkBitmap & orig,SkScalar scaleX,SkScalar scaleY,SkBitmap * scaled)725 SkScaledImageCache::ID* SkScaledImageCache::FindAndLock(const SkBitmap& orig,
726                                                         SkScalar scaleX,
727                                                         SkScalar scaleY,
728                                                         SkBitmap* scaled) {
729     SkAutoMutexAcquire am(gMutex);
730     return get_cache()->findAndLock(orig, scaleX, scaleY, scaled);
731 }
732 
FindAndLockMip(const SkBitmap & orig,SkMipMap const ** mip)733 SkScaledImageCache::ID* SkScaledImageCache::FindAndLockMip(const SkBitmap& orig,
734                                                        SkMipMap const ** mip) {
735     SkAutoMutexAcquire am(gMutex);
736     return get_cache()->findAndLockMip(orig, mip);
737 }
738 
AddAndLock(const SkBitmap & orig,SkScalar scaleX,SkScalar scaleY,const SkBitmap & scaled)739 SkScaledImageCache::ID* SkScaledImageCache::AddAndLock(const SkBitmap& orig,
740                                                        SkScalar scaleX,
741                                                        SkScalar scaleY,
742                                                        const SkBitmap& scaled) {
743     SkAutoMutexAcquire am(gMutex);
744     return get_cache()->addAndLock(orig, scaleX, scaleY, scaled);
745 }
746 
AddAndLockMip(const SkBitmap & orig,const SkMipMap * mip)747 SkScaledImageCache::ID* SkScaledImageCache::AddAndLockMip(const SkBitmap& orig,
748                                                           const SkMipMap* mip) {
749     SkAutoMutexAcquire am(gMutex);
750     return get_cache()->addAndLockMip(orig, mip);
751 }
752 
Unlock(SkScaledImageCache::ID * id)753 void SkScaledImageCache::Unlock(SkScaledImageCache::ID* id) {
754     SkAutoMutexAcquire am(gMutex);
755     get_cache()->unlock(id);
756 
757 //    get_cache()->dump();
758 }
759 
GetBytesUsed()760 size_t SkScaledImageCache::GetBytesUsed() {
761     SkAutoMutexAcquire am(gMutex);
762     return get_cache()->getBytesUsed();
763 }
764 
GetByteLimit()765 size_t SkScaledImageCache::GetByteLimit() {
766     SkAutoMutexAcquire am(gMutex);
767     return get_cache()->getByteLimit();
768 }
769 
SetByteLimit(size_t newLimit)770 size_t SkScaledImageCache::SetByteLimit(size_t newLimit) {
771     SkAutoMutexAcquire am(gMutex);
772     return get_cache()->setByteLimit(newLimit);
773 }
774 
GetAllocator()775 SkBitmap::Allocator* SkScaledImageCache::GetAllocator() {
776     SkAutoMutexAcquire am(gMutex);
777     return get_cache()->allocator();
778 }
779 
Dump()780 void SkScaledImageCache::Dump() {
781     SkAutoMutexAcquire am(gMutex);
782     get_cache()->dump();
783 }
784 
785 ///////////////////////////////////////////////////////////////////////////////
786 
787 #include "SkGraphics.h"
788 
GetImageCacheBytesUsed()789 size_t SkGraphics::GetImageCacheBytesUsed() {
790     return SkScaledImageCache::GetBytesUsed();
791 }
792 
GetImageCacheByteLimit()793 size_t SkGraphics::GetImageCacheByteLimit() {
794     return SkScaledImageCache::GetByteLimit();
795 }
796 
SetImageCacheByteLimit(size_t newLimit)797 size_t SkGraphics::SetImageCacheByteLimit(size_t newLimit) {
798     return SkScaledImageCache::SetByteLimit(newLimit);
799 }
800