Index: src/core/SkScaledImageCache.cpp |
diff --git a/src/core/SkScaledImageCache.cpp b/src/core/SkScaledImageCache.cpp |
index 11a0ee448f9c7cd590ff81c3409afded24163d8d..644ce7f05f6d72d4e8c52970103f67e4e2e2e9e9 100644 |
--- a/src/core/SkScaledImageCache.cpp |
+++ b/src/core/SkScaledImageCache.cpp |
@@ -7,6 +7,7 @@ |
#include "SkScaledImageCache.h" |
#include "SkMipMap.h" |
+#include "SkOnce.h" |
#include "SkPixelRef.h" |
#include "SkRect.h" |
@@ -14,6 +15,13 @@ |
#define SK_DEFAULT_IMAGE_CACHE_LIMIT (2 * 1024 * 1024) |
#endif |
+static inline SkScaledImageCache::ID* rec_to_id(SkScaledImageCache::Rec* rec) { |
+ return reinterpret_cast<SkScaledImageCache::ID*>(rec); |
+} |
+ |
+static inline SkScaledImageCache::Rec* id_to_rec(SkScaledImageCache::ID* id) { |
+ return reinterpret_cast<SkScaledImageCache::Rec*>(id); |
+} |
// Implemented from en.wikipedia.org/wiki/MurmurHash. |
static uint32_t compute_hash(const uint32_t data[], int count) { |
@@ -42,23 +50,15 @@ static uint32_t compute_hash(const uint32_t data[], int count) { |
} |
struct Key { |
- bool init(const SkBitmap& bm, SkScalar scaleX, SkScalar scaleY) { |
- SkPixelRef* pr = bm.pixelRef(); |
- if (!pr) { |
- return false; |
- } |
- |
- size_t x, y; |
- SkTDivMod(bm.pixelRefOffset(), bm.rowBytes(), &y, &x); |
- x >>= 2; |
- |
- fGenID = pr->getGenerationID(); |
- fBounds.set(x, y, x + bm.width(), y + bm.height()); |
- fScaleX = scaleX; |
- fScaleY = scaleY; |
- |
+ Key(uint32_t genID, |
+ SkScalar scaleX, |
+ SkScalar scaleY, |
+ SkIRect bounds) |
+ : fGenID(genID) |
+ , fScaleX(scaleX) |
+ , fScaleY(scaleY) |
+ , fBounds(bounds) { |
fHash = compute_hash(&fGenID, 7); |
- return true; |
} |
bool operator<(const Key& other) const { |
@@ -151,6 +151,17 @@ class SkScaledImageCache::Hash : public SkTDynamicHash<SkScaledImageCache::Rec, |
// experimental hash to speed things up |
#define USE_HASH |
+#if !defined(USE_HASH) |
+static inline SkScaledImageCache::Rec* find_rec_in_list( |
+ SkScaledImageCache::Rec* head, const Key & key) { |
+ SkScaledImageCache::Rec* rec = head; |
+ while ((rec != NULL) && (rec->fKey != key)) { |
+ rec = rec->fNext; |
+ } |
+ return rec; |
+} |
+#endif |
+ |
SkScaledImageCache::SkScaledImageCache(size_t byteLimit) { |
fHead = NULL; |
fTail = NULL; |
@@ -174,26 +185,24 @@ SkScaledImageCache::~SkScaledImageCache() { |
delete fHash; |
} |
-SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(const SkBitmap& orig, |
+//////////////////////////////////////////////////////////////////////////////// |
+ |
+/** |
+ This private method is the fully general record finder. All other |
+ record finders should call this funtion. */ |
+SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(uint32_t genID, |
SkScalar scaleX, |
- SkScalar scaleY) { |
- Key key; |
- if (!key.init(orig, scaleX, scaleY)) { |
+ SkScalar scaleY, |
+ const SkIRect& bounds) { |
+ if (bounds.isEmpty()) { |
return NULL; |
} |
- |
+ Key key(genID, scaleX, scaleY, bounds); |
#ifdef USE_HASH |
Rec* rec = fHash->find(key); |
#else |
- Rec* rec = fHead; |
- while (rec != NULL) { |
- if (rec->fKey == key) { |
- break; |
- } |
- rec = rec->fNext; |
- } |
+ Rec* rec = find_rec_in_list(fHead, key); |
#endif |
- |
if (rec) { |
this->moveToHead(rec); // for our LRU |
rec->fLockCount += 1; |
@@ -201,6 +210,36 @@ SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(const SkBitmap& orig, |
return rec; |
} |
+/** |
+ This function finds the bounds of the bitmap *within its pixelRef*. |
+ If the bitmap lacks a pixelRef, it will return an empty rect, since |
+ that doesn't make sense. This may be a useful enough function that |
+ it should be somewhere else (in SkBitmap?). */ |
+static SkIRect get_bounds_from_bitmap(const SkBitmap& bm) { |
+ if (!(bm.pixelRef())) { |
+ return SkIRect::MakeEmpty(); |
+ } |
+ size_t x, y; |
+ SkTDivMod(bm.pixelRefOffset(), bm.rowBytes(), &y, &x); |
+ x >>= bm.shiftPerPixel(); |
+ return SkIRect::MakeXYWH(x, y, bm.width(), bm.height()); |
+} |
+ |
+ |
+SkScaledImageCache::ID* SkScaledImageCache::findAndLock(uint32_t genID, |
+ int32_t width, |
+ int32_t height, |
+ SkBitmap* bitmap) { |
+ Rec* rec = this->findAndLock(genID, SK_Scalar1, SK_Scalar1, |
+ SkIRect::MakeWH(width, height)); |
+ if (rec) { |
+ SkASSERT(NULL == rec->fMip); |
+ SkASSERT(rec->fBitmap.pixelRef()); |
+ *bitmap = rec->fBitmap; |
+ } |
+ return rec_to_id(rec); |
+} |
+ |
SkScaledImageCache::ID* SkScaledImageCache::findAndLock(const SkBitmap& orig, |
SkScalar scaleX, |
SkScalar scaleY, |
@@ -209,25 +248,53 @@ SkScaledImageCache::ID* SkScaledImageCache::findAndLock(const SkBitmap& orig, |
// degenerate, and the key we use for mipmaps |
return NULL; |
} |
- |
- Rec* rec = this->findAndLock(orig, scaleX, scaleY); |
+ Rec* rec = this->findAndLock(orig.getGenerationID(), scaleX, |
+ scaleY, get_bounds_from_bitmap(orig)); |
if (rec) { |
SkASSERT(NULL == rec->fMip); |
SkASSERT(rec->fBitmap.pixelRef()); |
*scaled = rec->fBitmap; |
} |
- return (ID*)rec; |
+ return rec_to_id(rec); |
} |
SkScaledImageCache::ID* SkScaledImageCache::findAndLockMip(const SkBitmap& orig, |
SkMipMap const ** mip) { |
- Rec* rec = this->findAndLock(orig, 0, 0); |
+ Rec* rec = this->findAndLock(orig.getGenerationID(), 0, 0, |
+ get_bounds_from_bitmap(orig)); |
if (rec) { |
SkASSERT(rec->fMip); |
SkASSERT(NULL == rec->fBitmap.pixelRef()); |
*mip = rec->fMip; |
} |
- return (ID*)rec; |
+ return rec_to_id(rec); |
+} |
+ |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+/** |
+ This private method is the fully general record adder. All other |
+ record adders should call this funtion. */ |
+void SkScaledImageCache::addAndLock(SkScaledImageCache::Rec* rec) { |
+ SkASSERT(rec); |
+ this->addToHead(rec); |
+ SkASSERT(1 == rec->fLockCount); |
+#ifdef USE_HASH |
+ SkASSERT(fHash); |
+ fHash->add(rec); |
+#endif |
+ // We may (now) be overbudget, so see if we need to purge something. |
+ this->purgeAsNeeded(); |
+} |
+ |
+SkScaledImageCache::ID* SkScaledImageCache::addAndLock(uint32_t genID, |
+ int32_t width, |
+ int32_t height, |
+ const SkBitmap& bitmap) { |
+ Key key(genID, SK_Scalar1, SK_Scalar1, SkIRect::MakeWH(width, height)); |
+ Rec* rec = SkNEW_ARGS(Rec, (key, bitmap)); |
+ this->addAndLock(rec); |
+ return rec_to_id(rec); |
} |
SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const SkBitmap& orig, |
@@ -238,43 +305,26 @@ SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const SkBitmap& orig, |
// degenerate, and the key we use for mipmaps |
return NULL; |
} |
- |
- Key key; |
- if (!key.init(orig, scaleX, scaleY)) { |
+ SkIRect bounds = get_bounds_from_bitmap(orig); |
+ if (bounds.isEmpty()) { |
return NULL; |
} |
- |
+ Key key(orig.getGenerationID(), scaleX, scaleY, bounds); |
Rec* rec = SkNEW_ARGS(Rec, (key, scaled)); |
- this->addToHead(rec); |
- SkASSERT(1 == rec->fLockCount); |
- |
-#ifdef USE_HASH |
- fHash->add(rec); |
-#endif |
- |
- // We may (now) be overbudget, so see if we need to purge something. |
- this->purgeAsNeeded(); |
- return (ID*)rec; |
+ this->addAndLock(rec); |
+ return rec_to_id(rec); |
} |
SkScaledImageCache::ID* SkScaledImageCache::addAndLockMip(const SkBitmap& orig, |
const SkMipMap* mip) { |
- Key key; |
- if (!key.init(orig, 0, 0)) { |
+ SkIRect bounds = get_bounds_from_bitmap(orig); |
+ if (bounds.isEmpty()) { |
return NULL; |
} |
- |
+ Key key(orig.getGenerationID(), 0, 0, bounds); |
Rec* rec = SkNEW_ARGS(Rec, (key, mip)); |
- this->addToHead(rec); |
- SkASSERT(1 == rec->fLockCount); |
- |
-#ifdef USE_HASH |
- fHash->add(rec); |
-#endif |
- |
- // We may (now) be overbudget, so see if we need to purge something. |
- this->purgeAsNeeded(); |
- return (ID*)rec; |
+ this->addAndLock(rec); |
+ return rec_to_id(rec); |
} |
void SkScaledImageCache::unlock(SkScaledImageCache::ID* id) { |
@@ -285,7 +335,7 @@ void SkScaledImageCache::unlock(SkScaledImageCache::ID* id) { |
bool found = false; |
Rec* rec = fHead; |
while (rec != NULL) { |
- if ((ID*)rec == id) { |
+ if (rec == id_to_rec(id)) { |
found = true; |
break; |
} |
@@ -294,7 +344,7 @@ void SkScaledImageCache::unlock(SkScaledImageCache::ID* id) { |
SkASSERT(found); |
} |
#endif |
- Rec* rec = (Rec*)id; |
+ Rec* rec = id_to_rec(id); |
SkASSERT(rec->fLockCount > 0); |
rec->fLockCount -= 1; |
@@ -451,14 +501,38 @@ void SkScaledImageCache::validate() const { |
SK_DECLARE_STATIC_MUTEX(gMutex); |
+static void create_cache(SkScaledImageCache** cache) { |
+ *cache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CACHE_LIMIT)); |
+} |
+ |
static SkScaledImageCache* get_cache() { |
- static SkScaledImageCache* gCache; |
- if (!gCache) { |
- gCache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CACHE_LIMIT)); |
- } |
+ static SkScaledImageCache* gCache(NULL); |
+ SK_DECLARE_STATIC_ONCE(create_cache_once); |
+ SkOnce<SkScaledImageCache**>(&create_cache_once, create_cache, &gCache); |
+ SkASSERT(NULL != gCache); |
return gCache; |
} |
+ |
+SkScaledImageCache::ID* SkScaledImageCache::FindAndLock( |
+ uint32_t pixelGenerationID, |
+ int32_t width, |
+ int32_t height, |
+ SkBitmap* scaled) { |
+ SkAutoMutexAcquire am(gMutex); |
+ return get_cache()->findAndLock(pixelGenerationID, width, height, scaled); |
+} |
+ |
+SkScaledImageCache::ID* SkScaledImageCache::AddAndLock( |
+ uint32_t pixelGenerationID, |
+ int32_t width, |
+ int32_t height, |
+ const SkBitmap& scaled) { |
+ SkAutoMutexAcquire am(gMutex); |
+ return get_cache()->addAndLock(pixelGenerationID, width, height, scaled); |
+} |
+ |
+ |
SkScaledImageCache::ID* SkScaledImageCache::FindAndLock(const SkBitmap& orig, |
SkScalar scaleX, |
SkScalar scaleY, |