* found in the LICENSE file.
*/
+#include "SkChecksum.h"
#include "SkScaledImageCache.h"
#include "SkMipMap.h"
-#include "SkOnce.h"
#include "SkPixelRef.h"
#include "SkRect.h"
return reinterpret_cast<SkScaledImageCache::Rec*>(id);
}
- // Implemented from en.wikipedia.org/wiki/MurmurHash.
-static uint32_t compute_hash(const uint32_t data[], int count) {
- uint32_t hash = 0;
-
- for (int i = 0; i < count; ++i) {
- uint32_t k = data[i];
- k *= 0xcc9e2d51;
- k = (k << 15) | (k >> 17);
- k *= 0x1b873593;
-
- hash ^= k;
- hash = (hash << 13) | (hash >> 19);
- hash *= 5;
- hash += 0xe6546b64;
- }
-
- // hash ^= size;
- hash ^= hash >> 16;
- hash *= 0x85ebca6b;
- hash ^= hash >> 13;
- hash *= 0xc2b2ae35;
- hash ^= hash >> 16;
-
- return hash;
-}
-
struct SkScaledImageCache::Key {
Key(uint32_t genID,
SkScalar scaleX,
, fScaleX(scaleX)
, fScaleY(scaleY)
, fBounds(bounds) {
- fHash = compute_hash(&fGenID, 7);
+ fHash = SkChecksum::Murmur3(&fGenID, 28);
}
bool operator<(const Key& other) const {
SkSafeUnref(fMip);
}
+ static const Key& GetKey(const Rec& rec) { return rec.fKey; }
+ static uint32_t Hash(const Key& key) { return key.fHash; }
+
size_t bytesUsed() const {
return fMip ? fMip->getSize() : fBitmap.getSize();
}
#include "SkTDynamicHash.h"
-namespace { // can't use static functions w/ template parameters
-const SkScaledImageCache::Key& key_from_rec(const SkScaledImageCache::Rec& rec) {
- return rec.fKey;
-}
+class SkScaledImageCache::Hash :
+ public SkTDynamicHash<SkScaledImageCache::Rec, SkScaledImageCache::Key> {};
-uint32_t hash_from_key(const SkScaledImageCache::Key& key) {
- return key.fHash;
-}
-
-bool eq_rec_key(const SkScaledImageCache::Rec& rec, const SkScaledImageCache::Key& key) {
- return rec.fKey == key;
-}
-}
-
-class SkScaledImageCache::Hash : public SkTDynamicHash<SkScaledImageCache::Rec,
- SkScaledImageCache::Key,
- key_from_rec,
- hash_from_key,
- eq_rec_key> {};
///////////////////////////////////////////////////////////////////////////////
#else
fHash = NULL;
#endif
- fBytesUsed = 0;
+ fTotalBytesUsed = 0;
fCount = 0;
+ fSingleAllocationByteLimit = 0;
fAllocator = NULL;
// One of these should be explicit set by the caller after we return.
- fByteLimit = 0;
+ fTotalByteLimit = 0;
fDiscardableFactory = NULL;
}
SkOneShotDiscardablePixelRef(const SkImageInfo&, SkDiscardableMemory*, size_t rowBytes);
~SkOneShotDiscardablePixelRef();
- SK_DECLARE_UNFLATTENABLE_OBJECT()
-
protected:
virtual bool onNewLockPixels(LockRec*) SK_OVERRIDE;
virtual void onUnlockPixels() SK_OVERRIDE;
bool SkScaledImageCacheDiscardableAllocator::allocPixelRef(SkBitmap* bitmap,
SkColorTable* ctable) {
size_t size = bitmap->getSize();
- if (0 == size) {
+ uint64_t size64 = bitmap->computeSize64();
+ if (0 == size || size64 > (uint64_t)size) {
return false;
}
}
// can we relax this?
- if (kPMColor_SkColorType != bitmap->colorType()) {
+ if (kN32_SkColorType != bitmap->colorType()) {
return false;
}
SkScaledImageCache::SkScaledImageCache(size_t byteLimit) {
this->init();
- fByteLimit = byteLimit;
+ fTotalByteLimit = byteLimit;
}
SkScaledImageCache::~SkScaledImageCache() {
byteLimit = SK_MaxU32; // no limit based on bytes
} else {
countLimit = SK_MaxS32; // no limit based on count
- byteLimit = fByteLimit;
+ byteLimit = fTotalByteLimit;
}
- size_t bytesUsed = fBytesUsed;
+ size_t bytesUsed = fTotalBytesUsed;
int countUsed = fCount;
Rec* rec = fTail;
rec = prev;
}
- fBytesUsed = bytesUsed;
+ fTotalBytesUsed = bytesUsed;
fCount = countUsed;
}
-size_t SkScaledImageCache::setByteLimit(size_t newLimit) {
- size_t prevLimit = fByteLimit;
- fByteLimit = newLimit;
+size_t SkScaledImageCache::setTotalByteLimit(size_t newLimit) {
+ size_t prevLimit = fTotalByteLimit;
+ fTotalByteLimit = newLimit;
if (newLimit < prevLimit) {
this->purgeAsNeeded();
}
if (!fTail) {
fTail = rec;
}
- fBytesUsed += rec->bytesUsed();
+ fTotalBytesUsed += rec->bytesUsed();
fCount += 1;
this->validate();
void SkScaledImageCache::validate() const {
if (NULL == fHead) {
SkASSERT(NULL == fTail);
- SkASSERT(0 == fBytesUsed);
+ SkASSERT(0 == fTotalBytesUsed);
return;
}
if (fHead == fTail) {
SkASSERT(NULL == fHead->fPrev);
SkASSERT(NULL == fHead->fNext);
- SkASSERT(fHead->bytesUsed() == fBytesUsed);
+ SkASSERT(fHead->bytesUsed() == fTotalBytesUsed);
return;
}
while (rec) {
count += 1;
used += rec->bytesUsed();
- SkASSERT(used <= fBytesUsed);
+ SkASSERT(used <= fTotalBytesUsed);
rec = rec->fNext;
}
SkASSERT(fCount == count);
}
SkDebugf("SkScaledImageCache: count=%d bytes=%d locked=%d %s\n",
- fCount, fBytesUsed, locked,
+ fCount, fTotalBytesUsed, locked,
fDiscardableFactory ? "discardable" : "malloc");
}
+size_t SkScaledImageCache::setSingleAllocationByteLimit(size_t newLimit) {
+ size_t oldLimit = fSingleAllocationByteLimit;
+ fSingleAllocationByteLimit = newLimit;
+ return oldLimit;
+}
+
+size_t SkScaledImageCache::getSingleAllocationByteLimit() const {
+ return fSingleAllocationByteLimit;
+}
+
///////////////////////////////////////////////////////////////////////////////
#include "SkThread.h"
SK_DECLARE_STATIC_MUTEX(gMutex);
static SkScaledImageCache* gScaledImageCache = NULL;
-static void cleanup_gScaledImageCache() { SkDELETE(gScaledImageCache); }
-
-static void create_cache(int) {
-#ifdef SK_USE_DISCARDABLE_SCALEDIMAGECACHE
- gScaledImageCache = SkNEW_ARGS(SkScaledImageCache, (SkDiscardableMemory::Create));
-#else
- gScaledImageCache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CACHE_LIMIT));
+static void cleanup_gScaledImageCache() {
+ // We'll clean this up in our own tests, but disable for clients.
+ // Chrome seems to have funky multi-process things going on in unit tests that
+ // makes this unsafe to delete when the main process atexit()s.
+ // SkLazyPtr does the same sort of thing.
+#if SK_DEVELOPER
+ SkDELETE(gScaledImageCache);
#endif
}
+/** Must hold gMutex when calling. */
static SkScaledImageCache* get_cache() {
- SK_DECLARE_STATIC_ONCE(once);
- SkOnce(&once, create_cache, 0, cleanup_gScaledImageCache);
- SkASSERT(NULL != gScaledImageCache);
+ // gMutex is always held when this is called, so we don't need to be fancy in here.
+ gMutex.assertHeld();
+ if (NULL == gScaledImageCache) {
+#ifdef SK_USE_DISCARDABLE_SCALEDIMAGECACHE
+ gScaledImageCache = SkNEW_ARGS(SkScaledImageCache, (SkDiscardableMemory::Create));
+#else
+ gScaledImageCache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CACHE_LIMIT));
+#endif
+ atexit(cleanup_gScaledImageCache);
+ }
return gScaledImageCache;
}
// get_cache()->dump();
}
-size_t SkScaledImageCache::GetBytesUsed() {
+size_t SkScaledImageCache::GetTotalBytesUsed() {
SkAutoMutexAcquire am(gMutex);
- return get_cache()->getBytesUsed();
+ return get_cache()->getTotalBytesUsed();
}
-size_t SkScaledImageCache::GetByteLimit() {
+size_t SkScaledImageCache::GetTotalByteLimit() {
SkAutoMutexAcquire am(gMutex);
- return get_cache()->getByteLimit();
+ return get_cache()->getTotalByteLimit();
}
-size_t SkScaledImageCache::SetByteLimit(size_t newLimit) {
+size_t SkScaledImageCache::SetTotalByteLimit(size_t newLimit) {
SkAutoMutexAcquire am(gMutex);
- return get_cache()->setByteLimit(newLimit);
+ return get_cache()->setTotalByteLimit(newLimit);
}
SkBitmap::Allocator* SkScaledImageCache::GetAllocator() {
get_cache()->dump();
}
+size_t SkScaledImageCache::SetSingleAllocationByteLimit(size_t size) {
+ SkAutoMutexAcquire am(gMutex);
+ return get_cache()->setSingleAllocationByteLimit(size);
+}
+
+size_t SkScaledImageCache::GetSingleAllocationByteLimit() {
+ SkAutoMutexAcquire am(gMutex);
+ return get_cache()->getSingleAllocationByteLimit();
+}
+
///////////////////////////////////////////////////////////////////////////////
#include "SkGraphics.h"
-size_t SkGraphics::GetImageCacheBytesUsed() {
- return SkScaledImageCache::GetBytesUsed();
+size_t SkGraphics::GetImageCacheTotalBytesUsed() {
+ return SkScaledImageCache::GetTotalBytesUsed();
}
-size_t SkGraphics::GetImageCacheByteLimit() {
- return SkScaledImageCache::GetByteLimit();
+size_t SkGraphics::GetImageCacheTotalByteLimit() {
+ return SkScaledImageCache::GetTotalByteLimit();
}
-size_t SkGraphics::SetImageCacheByteLimit(size_t newLimit) {
- return SkScaledImageCache::SetByteLimit(newLimit);
+size_t SkGraphics::SetImageCacheTotalByteLimit(size_t newLimit) {
+ return SkScaledImageCache::SetTotalByteLimit(newLimit);
}
+
+size_t SkGraphics::GetImageCacheSingleAllocationByteLimit() {
+ return SkScaledImageCache::GetSingleAllocationByteLimit();
+}
+
+size_t SkGraphics::SetImageCacheSingleAllocationByteLimit(size_t newLimit) {
+ return SkScaledImageCache::SetSingleAllocationByteLimit(newLimit);
+}
+