diff options
author | Bo Liu <boliu@google.com> | 2014-08-13 09:53:42 -0700 |
---|---|---|
committer | Bo Liu <boliu@google.com> | 2014-08-13 09:53:42 -0700 |
commit | e90b557be8fb14d632e6243bf7c4efc9286740e3 (patch) | |
tree | 6fac41aff192982f0a486c991fdb9694930ceb14 | |
parent | 9465c499720c87a1e61ec91f1c0b11babf928f5d (diff) | |
parent | c7560eb5d81a46be62c0531054bc3b1447d8dc0e (diff) | |
download | skia-e90b557be8fb14d632e6243bf7c4efc9286740e3.tar.gz |
Merge from Chromium at DEPS revision 37.0.2062.76
This commit was generated by merge_to_master.py.
Change-Id: I4eb8934973e4c6323bdcc15be5e18313c9c5c764
-rw-r--r-- | bench/ImageCacheBench.cpp | 2 | ||||
-rw-r--r-- | gyp/tests.gypi | 1 | ||||
-rw-r--r-- | include/core/SkGraphics.h | 44 | ||||
-rw-r--r-- | src/core/SkBitmapProcState.cpp | 19 | ||||
-rw-r--r-- | src/core/SkScaledImageCache.cpp | 82 | ||||
-rw-r--r-- | src/core/SkScaledImageCache.h | 35 | ||||
-rw-r--r-- | tests/ImageCacheTest.cpp | 2 | ||||
-rw-r--r-- | tests/ScaledImageCache.cpp | 60 |
8 files changed, 200 insertions, 45 deletions
diff --git a/bench/ImageCacheBench.cpp b/bench/ImageCacheBench.cpp index 5f1715fc3..e65d1fc3e 100644 --- a/bench/ImageCacheBench.cpp +++ b/bench/ImageCacheBench.cpp @@ -37,7 +37,7 @@ protected: } virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { - if (fCache.getBytesUsed() == 0) { + if (fCache.getTotalBytesUsed() == 0) { this->populateCache(); } diff --git a/gyp/tests.gypi b/gyp/tests.gypi index 2a7dddd4f..9e418d687 100644 --- a/gyp/tests.gypi +++ b/gyp/tests.gypi @@ -155,6 +155,7 @@ '../tests/RuntimeConfigTest.cpp', '../tests/SHA1Test.cpp', '../tests/ScalarTest.cpp', + '../tests/ScaledImageCache.cpp', '../tests/SerializationTest.cpp', '../tests/ShaderImageFilterTest.cpp', '../tests/ShaderOpacityTest.cpp', diff --git a/include/core/SkGraphics.h b/include/core/SkGraphics.h index 2667a388d..e7865ca5a 100644 --- a/include/core/SkGraphics.h +++ b/include/core/SkGraphics.h @@ -79,9 +79,47 @@ public: */ static void PurgeFontCache(); - static size_t GetImageCacheBytesUsed(); - static size_t GetImageCacheByteLimit(); - static size_t SetImageCacheByteLimit(size_t newLimit); + /** + * Scaling bitmaps with the SkPaint::kHigh_FilterLevel setting is + * expensive, so the result is saved in the global Scaled Image + * Cache. + * + * This function returns the memory usage of the Scaled Image Cache. + */ + static size_t GetImageCacheTotalBytesUsed(); + /** + * These functions get/set the memory usage limit for the Scaled + * Image Cache. Bitmaps are purged from the cache when the + * memory useage exceeds this limit. + */ + static size_t GetImageCacheTotalByteLimit(); + static size_t SetImageCacheTotalByteLimit(size_t newLimit); + + // DEPRECATED + static size_t GetImageCacheBytesUsed() { + return GetImageCacheTotalBytesUsed(); + } + // DEPRECATED + static size_t GetImageCacheByteLimit() { + return GetImageCacheTotalByteLimit(); + } + // DEPRECATED + static size_t SetImageCacheByteLimit(size_t newLimit) { + return SetImageCacheTotalByteLimit(newLimit); + } + + /** + * Scaling bitmaps with the SkPaint::kHigh_FilterLevel setting is + * expensive, so the result is saved in the global Scaled Image + * Cache. When the resulting bitmap is too large, this can + * overload the cache. If the ImageCacheSingleAllocationByteLimit + * is set to a non-zero number, and the resulting bitmap would be + * larger than that value, the bitmap scaling algorithm falls + * back onto a cheaper algorithm and does not cache the result. + * Zero is the default value. + */ + static size_t GetImageCacheSingleAllocationByteLimit(); + static size_t SetImageCacheSingleAllocationByteLimit(size_t newLimit); /** * Applications with command line options may pass optional state, such diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp index f6f9f3fa0..137bcda91 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 a03024819..43ff7ef89 100644 --- a/src/core/SkScaledImageCache.cpp +++ b/src/core/SkScaledImageCache.cpp @@ -165,12 +165,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; } @@ -297,7 +298,7 @@ SkScaledImageCache::SkScaledImageCache(DiscardableFactory factory) { SkScaledImageCache::SkScaledImageCache(size_t byteLimit) { this->init(); - fByteLimit = byteLimit; + fTotalByteLimit = byteLimit; } SkScaledImageCache::~SkScaledImageCache() { @@ -502,10 +503,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; @@ -531,13 +532,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(); } @@ -597,7 +598,7 @@ void SkScaledImageCache::addToHead(Rec* rec) { if (!fTail) { fTail = rec; } - fBytesUsed += rec->bytesUsed(); + fTotalBytesUsed += rec->bytesUsed(); fCount += 1; this->validate(); @@ -609,14 +610,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; } @@ -631,7 +632,7 @@ void SkScaledImageCache::validate() const { while (rec) { count += 1; used += rec->bytesUsed(); - SkASSERT(used <= fBytesUsed); + SkASSERT(used <= fTotalBytesUsed); rec = rec->fNext; } SkASSERT(fCount == count); @@ -661,10 +662,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" @@ -751,19 +762,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() { @@ -776,18 +787,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 fe072306d..817147e3b 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, diff --git a/tests/ImageCacheTest.cpp b/tests/ImageCacheTest.cpp index 92d0b519d..00f6c77aa 100644 --- a/tests/ImageCacheTest.cpp +++ b/tests/ImageCacheTest.cpp @@ -74,7 +74,7 @@ static void test_cache(skiatest::Reporter* reporter, SkScaledImageCache& cache, } } - cache.setByteLimit(0); + cache.setTotalByteLimit(0); } #include "SkDiscardableMemoryPool.h" diff --git a/tests/ScaledImageCache.cpp b/tests/ScaledImageCache.cpp new file mode 100644 index 000000000..2040afea2 --- /dev/null +++ b/tests/ScaledImageCache.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Test.h" +#include "SkGraphics.h" +#include "SkCanvas.h" + +static const int kCanvasSize = 1; +static const int kBitmapSize = 16; +static const int kScale = 8; + +static size_t test_scaled_image_cache_useage() { + SkAutoTUnref<SkCanvas> canvas( + SkCanvas::NewRasterN32(kCanvasSize, kCanvasSize)); + SkBitmap bitmap; + SkAssertResult(bitmap.allocN32Pixels(kBitmapSize, kBitmapSize)); + SkScalar scaledSize = SkIntToScalar(kScale * kBitmapSize); + canvas->clipRect(SkRect::MakeLTRB(0, 0, scaledSize, scaledSize)); + SkPaint paint; + paint.setFilterLevel(SkPaint::kHigh_FilterLevel); + size_t bytesUsed = SkGraphics::GetImageCacheBytesUsed(); + canvas->drawBitmapRect(bitmap, + SkRect::MakeLTRB(0, 0, scaledSize, scaledSize), + &paint); + return SkGraphics::GetImageCacheBytesUsed() - bytesUsed; +} + +// http://crbug.com/389439 +DEF_TEST(ScaledImageCache_SingleAllocationByteLimit, reporter) { + size_t originalByteLimit = SkGraphics::GetImageCacheByteLimit(); + size_t originalAllocationLimit = + SkGraphics::GetImageCacheSingleAllocationByteLimit(); + + size_t size = kBitmapSize * kScale * kBitmapSize * kScale + * SkColorTypeBytesPerPixel(kN32_SkColorType); + + SkGraphics::SetImageCacheByteLimit(0); // clear cache + SkGraphics::SetImageCacheByteLimit(2 * size); + SkGraphics::SetImageCacheSingleAllocationByteLimit(0); + + REPORTER_ASSERT(reporter, size == test_scaled_image_cache_useage()); + + SkGraphics::SetImageCacheByteLimit(0); // clear cache + SkGraphics::SetImageCacheByteLimit(2 * size); + SkGraphics::SetImageCacheSingleAllocationByteLimit(size * 2); + + REPORTER_ASSERT(reporter, size == test_scaled_image_cache_useage()); + + SkGraphics::SetImageCacheByteLimit(0); // clear cache + SkGraphics::SetImageCacheByteLimit(2 * size); + SkGraphics::SetImageCacheSingleAllocationByteLimit(size / 2); + + REPORTER_ASSERT(reporter, 0 == test_scaled_image_cache_useage()); + + SkGraphics::SetImageCacheSingleAllocationByteLimit(originalAllocationLimit); + SkGraphics::SetImageCacheByteLimit(originalByteLimit); +} |