Chromium Code Reviews| Index: src/core/SkScaledImageCache.cpp |
| diff --git a/src/core/SkScaledImageCache.cpp b/src/core/SkScaledImageCache.cpp |
| index eba20c4f906644ce16307a4e18d30963d5188e1e..53467d639fd69c89a93e9741a89bb49bcfe64f8e 100644 |
| --- a/src/core/SkScaledImageCache.cpp |
| +++ b/src/core/SkScaledImageCache.cpp |
| @@ -11,6 +11,13 @@ |
| #include "SkPixelRef.h" |
| #include "SkRect.h" |
| +// This can be defined by the caller's build system |
| +//#define SK_USE_DISCARDABLE_SCALEDIMAGECACHE |
| + |
| +#ifndef SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT |
| +# define SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT 1024 |
|
hal.canary
2013/12/09 18:23:27
I assume you expect clients to set this number lar
reed1
2013/12/09 18:43:48
Or smaller
|
| +#endif |
| + |
| #ifndef SK_DEFAULT_IMAGE_CACHE_LIMIT |
| #define SK_DEFAULT_IMAGE_CACHE_LIMIT (2 * 1024 * 1024) |
| #endif |
| @@ -164,7 +171,7 @@ static inline SkScaledImageCache::Rec* find_rec_in_list( |
| } |
| #endif |
| -SkScaledImageCache::SkScaledImageCache(size_t byteLimit) { |
| +void SkScaledImageCache::init() { |
| fHead = NULL; |
| fTail = NULL; |
| #ifdef USE_HASH |
| @@ -173,11 +180,132 @@ SkScaledImageCache::SkScaledImageCache(size_t byteLimit) { |
| fHash = NULL; |
| #endif |
| fBytesUsed = 0; |
| - fByteLimit = byteLimit; |
| fCount = 0; |
| + fAllocator = NULL; |
| + |
| + // One of these should be explicit set by the caller after we return. |
| + fByteLimit = 0; |
| + fDiscardableFactory = NULL; |
| +} |
| + |
| +#include "SkDiscardableMemory.h" |
| + |
| +class SkOneShotDiscardablePixelRef : public SkPixelRef { |
| +public: |
| + // Ownership of the discardablememory is transfered to the pixelref |
| + SkOneShotDiscardablePixelRef(const SkImageInfo&, SkDiscardableMemory*, size_t rowBytes); |
| + ~SkOneShotDiscardablePixelRef(); |
| + |
| +protected: |
| + virtual void* onLockPixels(SkColorTable**) SK_OVERRIDE; |
| + virtual void onUnlockPixels() SK_OVERRIDE; |
| + virtual size_t getAllocatedSizeInBytes() const SK_OVERRIDE; |
| + |
| + virtual Factory getFactory() const SK_OVERRIDE { return NULL; } |
|
hal.canary
2013/12/09 18:23:27
Use SK_DECLARE_UNFLATTENABLE_OBJECT, since that is
reed1
2013/12/09 18:43:48
Done.
|
| + |
| +private: |
| + SkImageInfo fInfo; // remove when SkPixelRef gets this in baseclass |
| + |
| + SkDiscardableMemory* fDM; |
| + size_t fRB; |
|
hal.canary
2013/12/09 18:23:27
readability: I'd prefer fRowBytes
reed1
2013/12/09 18:43:48
Will conflict with the SkPixelRef when that CL lan
|
| + bool fFirstTime; |
| + |
| + typedef SkPixelRef INHERITED; |
| +}; |
| + |
| +SkOneShotDiscardablePixelRef::SkOneShotDiscardablePixelRef(const SkImageInfo& info, |
| + SkDiscardableMemory* dm, |
| + size_t rowBytes) |
| + : INHERITED(info) |
| + , fDM(dm) |
| + , fRB(rowBytes) |
| +{ |
| + fInfo = info; // remove this redundant field when SkPixelRef has info |
| + |
| + SkASSERT(dm->data()); |
| + fFirstTime = true; |
| +} |
| + |
| +SkOneShotDiscardablePixelRef::~SkOneShotDiscardablePixelRef() { |
| + SkDELETE(fDM); |
| +} |
| + |
| +void* SkOneShotDiscardablePixelRef::onLockPixels(SkColorTable** ctable) { |
| + if (fFirstTime) { |
| + // we're already locked |
| + fFirstTime = false; |
| + return fDM->data(); |
| + } |
| + return fDM->lock() ? fDM->data() : NULL; |
| +} |
| + |
| +void SkOneShotDiscardablePixelRef::onUnlockPixels() { |
| + SkASSERT(!fFirstTime); |
| + fDM->unlock(); |
| +} |
| + |
| +size_t SkOneShotDiscardablePixelRef::getAllocatedSizeInBytes() const { |
| + return fInfo.fHeight * fRB; |
| +} |
| + |
| +class SkScaledImageCacheDiscardableAllocator : public SkBitmap::Allocator { |
| +public: |
| + SkScaledImageCacheDiscardableAllocator( |
| + SkScaledImageCache::DiscardableFactory factory) { |
| + fFactory = factory; |
|
hal.canary
2013/12/09 18:23:27
Either assert != NULL or explicitly allow NULL (de
reed1
2013/12/09 18:43:48
Defaults are harder to read sometimes, and I don't
|
| + } |
| + |
| + virtual bool allocPixelRef(SkBitmap*, SkColorTable*) SK_OVERRIDE; |
| + |
| +private: |
| + SkScaledImageCache::DiscardableFactory fFactory; |
| +}; |
| + |
| +bool SkScaledImageCacheDiscardableAllocator::allocPixelRef(SkBitmap* bitmap, |
| + SkColorTable* ctable) { |
| + size_t size = bitmap->getSize(); |
| + if (0 == size) { |
| + return false; |
| + } |
| + |
| + SkDiscardableMemory* dm = fFactory(size); |
|
hal.canary
2013/12/09 18:23:27
SkDiscardableMemory* dm;
if (fFactory != NULL)
reed1
2013/12/09 18:43:48
asserting in constructor.
|
| + if (NULL == dm) { |
| + return false; |
| + } |
| + |
| + // can relax when we have bitmap::asImageInfo |
| + if (SkBitmap::kARGB_8888_Config != bitmap->config()) { |
| + return false; |
| + } |
| + |
| + SkImageInfo info = { |
| + bitmap->width(), |
| + bitmap->height(), |
| + kPMColor_SkColorType, |
| + bitmap->alphaType() |
| + }; |
| + |
| + bitmap->setPixelRef(SkNEW_ARGS(SkOneShotDiscardablePixelRef, |
| + (info, dm, bitmap->rowBytes())))->unref(); |
| + bitmap->lockPixels(); |
| + return bitmap->readyToDraw(); |
| +} |
| + |
| +SkScaledImageCache::SkScaledImageCache(DiscardableFactory factory) { |
| + this->init(); |
| + fDiscardableFactory = factory; |
| + |
| + fAllocator = SkNEW_ARGS(SkScaledImageCacheDiscardableAllocator, (factory)); |
| +} |
| + |
| +SkScaledImageCache::SkScaledImageCache(size_t byteLimit) { |
| + this->init(); |
| + fByteLimit = byteLimit; |
| } |
| SkScaledImageCache::~SkScaledImageCache() { |
| + SkSafeUnref(fAllocator); |
| + |
| Rec* rec = fHead; |
| while (rec) { |
| Rec* next = rec->fNext; |
| @@ -367,30 +495,45 @@ void SkScaledImageCache::unlock(SkScaledImageCache::ID* id) { |
| } |
| void SkScaledImageCache::purgeAsNeeded() { |
| - size_t byteLimit = fByteLimit; |
| - size_t bytesUsed = fBytesUsed; |
| + size_t byteLimit; |
| + int countLimit; |
| + |
| + if (fDiscardableFactory) { |
| + countLimit = SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT; |
| + byteLimit = SK_MaxU32; // no limit based on bytes |
| + } else { |
| + countLimit = SK_MaxS32; // no limit based on count |
| + byteLimit = fByteLimit; |
| + } |
| + size_t bytesUsed = fBytesUsed; |
| + int countUsed = fCount; |
| + |
| Rec* rec = fTail; |
| while (rec) { |
| - if (bytesUsed < byteLimit) { |
| + if (bytesUsed < byteLimit && countUsed < countLimit) { |
| break; |
| } |
| + |
| Rec* prev = rec->fPrev; |
| if (0 == rec->fLockCount) { |
| size_t used = rec->bytesUsed(); |
| SkASSERT(used <= bytesUsed); |
| - bytesUsed -= used; |
| this->detach(rec); |
| #ifdef USE_HASH |
| fHash->remove(rec->fKey); |
| #endif |
| SkDELETE(rec); |
| - fCount -= 1; |
| + |
| + bytesUsed -= used; |
| + countUsed -= 1; |
| } |
| rec = prev; |
| } |
| + |
| fBytesUsed = bytesUsed; |
| + fCount = countUsed; |
| } |
| size_t SkScaledImageCache::setByteLimit(size_t newLimit) { |
| @@ -513,7 +656,11 @@ void SkScaledImageCache::validate() const { |
| SK_DECLARE_STATIC_MUTEX(gMutex); |
| static void create_cache(SkScaledImageCache** cache) { |
| +#ifdef SK_USE_DISCARDABLE_SCALEDIMAGECACHE |
| + *cache = SkNEW_ARGS(SkScaledImageCache, (SkDiscardableMemory::Create)); |
| +#else |
| *cache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CACHE_LIMIT)); |
| +#endif |
| } |
| static SkScaledImageCache* get_cache() { |
| @@ -592,6 +739,11 @@ size_t SkScaledImageCache::SetByteLimit(size_t newLimit) { |
| return get_cache()->setByteLimit(newLimit); |
| } |
| +SkBitmap::Allocator* SkScaledImageCache::GetAllocator() { |
| + SkAutoMutexAcquire am(gMutex); |
| + return get_cache()->allocator(); |
| +} |
| + |
| /////////////////////////////////////////////////////////////////////////////// |
| #include "SkGraphics.h" |