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