diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/SkBitmapProcState.cpp | 19 | ||||
-rw-r--r-- | src/core/SkScaledImageCache.cpp | 82 | ||||
-rw-r--r-- | src/core/SkScaledImageCache.h | 35 |
3 files changed, 96 insertions, 40 deletions
diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp index f8ab8ab351..d48679e8c9 100644 --- a/src/core/SkBitmapProcState.cpp +++ b/src/core/SkBitmapProcState.cpp @@ -127,6 +127,21 @@ private: }; #define AutoScaledCacheUnlocker(...) SK_REQUIRE_LOCAL_VAR(AutoScaledCacheUnlocker) +// Check to see that the size of the bitmap that would be produced by +// scaling by the given inverted matrix is less than the maximum allowed. +static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) { + size_t maximumAllocation + = SkScaledImageCache::GetSingleAllocationByteLimit(); + if (0 == maximumAllocation) { + return true; + } + // float matrixScaleFactor = 1.0 / (invMat.scaleX * invMat.scaleY); + // return ((origBitmapSize * matrixScaleFactor) < maximumAllocationSize); + // Skip the division step: + return bm.info().getSafeSize(bm.info().minRowBytes()) + < (maximumAllocation * invMat.getScaleX() * invMat.getScaleY()); +} + // TODO -- we may want to pass the clip into this function so we only scale // the portion of the image that we're going to need. This will complicate // the interface to the cache, but might be well worth it. @@ -140,14 +155,14 @@ bool SkBitmapProcState::possiblyScaleImage() { if (fFilterLevel <= SkPaint::kLow_FilterLevel) { return false; } - // Check to see if the transformation matrix is simple, and if we're // doing high quality scaling. If so, do the bitmap scale here and // remove the scaling component from the matrix. if (SkPaint::kHigh_FilterLevel == fFilterLevel && fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask) && - kN32_SkColorType == fOrigBitmap.colorType()) { + kN32_SkColorType == fOrigBitmap.colorType() && + cache_size_okay(fOrigBitmap, fInvMatrix)) { SkScalar invScaleX = fInvMatrix.getScaleX(); SkScalar invScaleY = fInvMatrix.getScaleY(); diff --git a/src/core/SkScaledImageCache.cpp b/src/core/SkScaledImageCache.cpp index 6d63edb468..dca75969f8 100644 --- a/src/core/SkScaledImageCache.cpp +++ b/src/core/SkScaledImageCache.cpp @@ -140,12 +140,13 @@ void SkScaledImageCache::init() { #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; } @@ -270,7 +271,7 @@ SkScaledImageCache::SkScaledImageCache(DiscardableFactory factory) { SkScaledImageCache::SkScaledImageCache(size_t byteLimit) { this->init(); - fByteLimit = byteLimit; + fTotalByteLimit = byteLimit; } SkScaledImageCache::~SkScaledImageCache() { @@ -475,10 +476,10 @@ void SkScaledImageCache::purgeAsNeeded() { 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; @@ -504,13 +505,13 @@ void SkScaledImageCache::purgeAsNeeded() { 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(); } @@ -570,7 +571,7 @@ void SkScaledImageCache::addToHead(Rec* rec) { if (!fTail) { fTail = rec; } - fBytesUsed += rec->bytesUsed(); + fTotalBytesUsed += rec->bytesUsed(); fCount += 1; this->validate(); @@ -582,14 +583,14 @@ void SkScaledImageCache::addToHead(Rec* rec) { 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; } @@ -604,7 +605,7 @@ void SkScaledImageCache::validate() const { while (rec) { count += 1; used += rec->bytesUsed(); - SkASSERT(used <= fBytesUsed); + SkASSERT(used <= fTotalBytesUsed); rec = rec->fNext; } SkASSERT(fCount == count); @@ -634,10 +635,20 @@ void SkScaledImageCache::dump() const { } 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" @@ -724,19 +735,19 @@ void SkScaledImageCache::Unlock(SkScaledImageCache::ID* id) { // 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() { @@ -749,18 +760,37 @@ void SkScaledImageCache::Dump() { 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::GetImageCacheTotalByteLimit() { + return SkScaledImageCache::GetTotalByteLimit(); } -size_t SkGraphics::GetImageCacheByteLimit() { - return SkScaledImageCache::GetByteLimit(); +size_t SkGraphics::SetImageCacheTotalByteLimit(size_t newLimit) { + return SkScaledImageCache::SetTotalByteLimit(newLimit); } -size_t SkGraphics::SetImageCacheByteLimit(size_t newLimit) { - return SkScaledImageCache::SetByteLimit(newLimit); +size_t SkGraphics::GetImageCacheSingleAllocationByteLimit() { + return SkScaledImageCache::GetSingleAllocationByteLimit(); } + +size_t SkGraphics::SetImageCacheSingleAllocationByteLimit(size_t newLimit) { + return SkScaledImageCache::SetSingleAllocationByteLimit(newLimit); +} + diff --git a/src/core/SkScaledImageCache.h b/src/core/SkScaledImageCache.h index fe072306d3..817147e3b8 100644 --- a/src/core/SkScaledImageCache.h +++ b/src/core/SkScaledImageCache.h @@ -60,9 +60,12 @@ public: static void Unlock(ID*); - static size_t GetBytesUsed(); - static size_t GetByteLimit(); - static size_t SetByteLimit(size_t newLimit); + static size_t GetTotalBytesUsed(); + static size_t GetTotalByteLimit(); + static size_t SetTotalByteLimit(size_t newLimit); + + static size_t SetSingleAllocationByteLimit(size_t); + static size_t GetSingleAllocationByteLimit(); static SkBitmap::Allocator* GetAllocator(); @@ -76,9 +79,9 @@ public: /** * Construct the cache to call DiscardableFactory when it * allocates memory for the pixels. In this mode, the cache has - * not explicit budget, and so methods like getBytesUsed() and - * getByteLimit() will return 0, and setByteLimit will ignore its argument - * and return 0. + * not explicit budget, and so methods like getTotalBytesUsed() + * and getTotalByteLimit() will return 0, and setTotalByteLimit + * will ignore its argument and return 0. */ SkScaledImageCache(DiscardableFactory); @@ -86,7 +89,7 @@ public: * Construct the cache, allocating memory with malloc, and respect the * byteLimit, purging automatically when a new image is added to the cache * that pushes the total bytesUsed over the limit. Note: The limit can be - * changed at runtime with setByteLimit. + * changed at runtime with setTotalByteLimit. */ SkScaledImageCache(size_t byteLimit); @@ -144,15 +147,22 @@ public: */ void unlock(ID*); - size_t getBytesUsed() const { return fBytesUsed; } - size_t getByteLimit() const { return fByteLimit; } + size_t getTotalBytesUsed() const { return fTotalBytesUsed; } + size_t getTotalByteLimit() const { return fTotalByteLimit; } /** + * This is respected by SkBitmapProcState::possiblyScaleImage. + * 0 is no maximum at all; this is the default. + * setSingleAllocationByteLimit() returns the previous value. + */ + size_t setSingleAllocationByteLimit(size_t maximumAllocationSize); + size_t getSingleAllocationByteLimit() const; + /** * Set the maximum number of bytes available to this cache. If the current * cache exceeds this new value, it will be purged to try to fit within * this new limit. */ - size_t setByteLimit(size_t newLimit); + size_t setTotalByteLimit(size_t newLimit); SkBitmap::Allocator* allocator() const { return fAllocator; }; @@ -175,8 +185,9 @@ private: // the allocator is NULL or one that matches discardables SkBitmap::Allocator* fAllocator; - size_t fBytesUsed; - size_t fByteLimit; + size_t fTotalBytesUsed; + size_t fTotalByteLimit; + size_t fSingleAllocationByteLimit; int fCount; Rec* findAndLock(uint32_t generationID, SkScalar sx, SkScalar sy, |