diff options
author | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-07-24 14:31:33 +0000 |
---|---|---|
committer | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-07-24 14:31:33 +0000 |
commit | d94697c21ae479df4190a1afbf08d85ce244a4ef (patch) | |
tree | 3a8170934ed3aa549e0d9a2a3f8eb22f2c9640e7 /src | |
parent | 58c856a54a75e703aa3c82a0cd4e1affd9bd8ffc (diff) |
add mipmaps to scaledimagecache
BUG=
Review URL: https://codereview.chromium.org/19789016
git-svn-id: http://skia.googlecode.com/svn/trunk@10305 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkBitmapProcState.cpp | 46 | ||||
-rw-r--r-- | src/core/SkMipMap.cpp | 19 | ||||
-rw-r--r-- | src/core/SkMipMap.h | 14 | ||||
-rw-r--r-- | src/core/SkScaledImageCache.cpp | 96 | ||||
-rw-r--r-- | src/core/SkScaledImageCache.h | 14 |
5 files changed, 152 insertions, 37 deletions
diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp index 37c5026797..3a059d3876 100644 --- a/src/core/SkBitmapProcState.cpp +++ b/src/core/SkBitmapProcState.cpp @@ -12,6 +12,7 @@ #include "SkShader.h" // for tilemodes #include "SkUtilsArm.h" #include "SkBitmapScaler.h" +#include "SkMipMap.h" #include "SkScaledImageCache.h" #if !SK_ARM_NEON_IS_NONE @@ -92,7 +93,7 @@ static bool valid_for_filtering(unsigned dimension) { return (dimension & ~0x3FFF) == 0; } -static bool effective_matrix_scale_sqrd(const SkMatrix& mat) { +static SkScalar effective_matrix_scale_sqrd(const SkMatrix& mat) { SkPoint v1, v2; v1.fX = mat.getScaleX(); @@ -225,24 +226,43 @@ void SkBitmapProcState::possiblyScaleImage() { * a scale > 1 to indicate down scaling by the CTM. */ if (scaleSqd > SK_Scalar1) { - if (!fOrigBitmap.hasMipMap()) { - fOrigBitmap.buildMipMap(); - // build may fail, so we need to check again + const SkMipMap* mip = NULL; + + SkASSERT(NULL == fScaledCacheID); + fScaledCacheID = SkScaledImageCache::FindAndLockMip(fOrigBitmap, &mip); + if (!fScaledCacheID) { + SkASSERT(NULL == mip); + mip = SkMipMap::Build(fOrigBitmap); + if (mip) { + fScaledCacheID = SkScaledImageCache::AddAndLockMip(fOrigBitmap, + mip); + mip->unref(); // the cache took a ref + SkASSERT(fScaledCacheID); + } + } else { + SkASSERT(mip); } - if (fOrigBitmap.hasMipMap()) { - int shift = fOrigBitmap.extractMipLevel(&fScaledBitmap, - SkScalarToFixed(fInvMatrix.getScaleX()), - SkScalarToFixed(fInvMatrix.getSkewY())); - if (shift > 0) { - SkScalar scale = SkFixedToScalar(SK_Fixed1 >> shift); - fInvMatrix.postScale(scale, scale); + + if (mip) { + SkScalar levelScale = SkScalarInvert(SkScalarSqrt(scaleSqd)); + SkMipMap::Level level; + if (mip->extractLevel(levelScale, &level)) { + SkScalar invScaleFixup = level.fScale; + fInvMatrix.postScale(invScaleFixup, invScaleFixup); + + fScaledBitmap.setConfig(fOrigBitmap.config(), + level.fWidth, level.fHeight, + level.fRowBytes); + fScaledBitmap.setPixels(level.fPixels); fBitmap = &fScaledBitmap; } } } - // Now that we've built the mipmaps (if applicable), we set the filter-level - // bilinear interpolation. + /* + * At this point, we may or may not have built a mipmap. Regardless, we + * now fall back on Low so will bilerp whatever fBitmap now points at. + */ fFilterLevel = SkPaint::kLow_FilterLevel; } diff --git a/src/core/SkMipMap.cpp b/src/core/SkMipMap.cpp index c9f5145f0a..0673c7e093 100644 --- a/src/core/SkMipMap.cpp +++ b/src/core/SkMipMap.cpp @@ -192,6 +192,7 @@ SkMipMap* SkMipMap::Build(const SkBitmap& src) { levels[i].fWidth = width; levels[i].fHeight = height; levels[i].fRowBytes = rowBytes; + levels[i].fScale = (float)width / src.width(); SkBitmap dstBM; dstBM.setConfig(config, width, height, rowBytes); @@ -210,7 +211,23 @@ SkMipMap* SkMipMap::Build(const SkBitmap& src) { } SkASSERT(addr == baseAddr + size); - return SkNEW_ARGS(SkMipMap, (levels, countLevels)); + return SkNEW_ARGS(SkMipMap, (levels, countLevels, size)); +} + +/////////////////////////////////////////////////////////////////////////////// + +//static int gCounter; + +SkMipMap::SkMipMap(Level* levels, int count, size_t size) + : fSize(size), fLevels(levels), fCount(count) { + SkASSERT(levels); + SkASSERT(count > 0); +// SkDebugf("mips %d\n", ++gCounter); +} + +SkMipMap::~SkMipMap() { + sk_free(fLevels); +// SkDebugf("mips %d\n", --gCounter); } static SkFixed compute_level(SkScalar scale) { diff --git a/src/core/SkMipMap.h b/src/core/SkMipMap.h index f8753cdc1b..ed912ba976 100644 --- a/src/core/SkMipMap.h +++ b/src/core/SkMipMap.h @@ -21,23 +21,21 @@ public: void* fPixels; uint32_t fRowBytes; uint32_t fWidth, fHeight; + float fScale; // < 1.0 }; bool extractLevel(SkScalar scale, Level*) const; + size_t getSize() const { return fSize; } + private: + size_t fSize; Level* fLevels; int fCount; // we take ownership of levels, and will free it with sk_free() - SkMipMap(Level* levels, int count) : fLevels(levels), fCount(count) { - SkASSERT(levels); - SkASSERT(count > 0); - } - - virtual ~SkMipMap() { - sk_free(fLevels); - } + SkMipMap(Level* levels, int count, size_t size); + virtual ~SkMipMap(); static Level* AllocLevels(int levelCount, size_t pixelSize); }; diff --git a/src/core/SkScaledImageCache.cpp b/src/core/SkScaledImageCache.cpp index 8d7b81bf3e..84a5c56020 100644 --- a/src/core/SkScaledImageCache.cpp +++ b/src/core/SkScaledImageCache.cpp @@ -6,6 +6,7 @@ */ #include "SkScaledImageCache.h" +#include "SkMipMap.h" #include "SkPixelRef.h" #include "SkRect.h" @@ -110,10 +111,21 @@ struct Key { struct SkScaledImageCache::Rec { Rec(const Key& key, const SkBitmap& bm) : fKey(key), fBitmap(bm) { fLockCount = 1; + fMip = NULL; } - + + Rec(const Key& key, const SkMipMap* mip) : fKey(key) { + fLockCount = 1; + fMip = mip; + mip->ref(); + } + + ~Rec() { + SkSafeUnref(fMip); + } + size_t bytesUsed() const { - return fBitmap.getSize(); + return fMip ? fMip->getSize() : fBitmap.getSize(); } Rec* fNext; @@ -123,7 +135,10 @@ struct SkScaledImageCache::Rec { Key fKey; int32_t fLockCount; + + // we use either fBitmap or fMip, but not both SkBitmap fBitmap; + const SkMipMap* fMip; }; SkScaledImageCache::SkScaledImageCache(size_t byteLimit) { @@ -143,44 +158,89 @@ SkScaledImageCache::~SkScaledImageCache() { } } -SkScaledImageCache::ID* SkScaledImageCache::findAndLock(const SkBitmap& orig, +SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(const SkBitmap& orig, SkScalar scaleX, - SkScalar scaleY, - SkBitmap* scaled) { + SkScalar scaleY) { Key key; if (!key.init(orig, scaleX, scaleY)) { return NULL; } - + Rec* rec = fHead; while (rec != NULL) { if (rec->fKey == key) { this->moveToHead(rec); // for our LRU rec->fLockCount += 1; - *scaled = rec->fBitmap; -// SkDebugf("Found: [%d %d] %d\n", rec->fBitmap.width(), rec->fBitmap.height(), rec->fLockCount); - return (ID*)rec; + return rec; } rec = rec->fNext; } return NULL; } +SkScaledImageCache::ID* SkScaledImageCache::findAndLock(const SkBitmap& orig, + SkScalar scaleX, + SkScalar scaleY, + SkBitmap* scaled) { + if (0 == scaleX || 0 == scaleY) { + // degenerate, and the key we use for mipmaps + return NULL; + } + + Rec* rec = this->findAndLock(orig, scaleX, scaleY); + if (rec) { + SkASSERT(NULL == rec->fMip); + SkASSERT(rec->fBitmap.pixelRef()); + *scaled = rec->fBitmap; + } + return (ID*)rec; +} + +SkScaledImageCache::ID* SkScaledImageCache::findAndLockMip(const SkBitmap& orig, + SkMipMap const ** mip) { + Rec* rec = this->findAndLock(orig, 0, 0); + if (rec) { + SkASSERT(rec->fMip); + SkASSERT(NULL == rec->fBitmap.pixelRef()); + *mip = rec->fMip; + } + return (ID*)rec; +} + SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const SkBitmap& orig, SkScalar scaleX, SkScalar scaleY, const SkBitmap& scaled) { + if (0 == scaleX || 0 == scaleY) { + // degenerate, and the key we use for mipmaps + return NULL; + } + Key key; if (!key.init(orig, scaleX, scaleY)) { return NULL; } - + Rec* rec = SkNEW_ARGS(Rec, (key, scaled)); this->addToHead(rec); SkASSERT(1 == rec->fLockCount); + + // We may (now) be overbudget, so see if we need to purge something. + this->purgeAsNeeded(); + return (ID*)rec; +} -// SkDebugf("Added: [%d %d]\n", rec->fBitmap.width(), rec->fBitmap.height()); - +SkScaledImageCache::ID* SkScaledImageCache::addAndLockMip(const SkBitmap& orig, + const SkMipMap* mip) { + Key key; + if (!key.init(orig, 0, 0)) { + return NULL; + } + + Rec* rec = SkNEW_ARGS(Rec, (key, mip)); + this->addToHead(rec); + SkASSERT(1 == rec->fLockCount); + // We may (now) be overbudget, so see if we need to purge something. this->purgeAsNeeded(); return (ID*)rec; @@ -375,6 +435,12 @@ SkScaledImageCache::ID* SkScaledImageCache::FindAndLock(const SkBitmap& orig, return get_cache()->findAndLock(orig, scaleX, scaleY, scaled); } +SkScaledImageCache::ID* SkScaledImageCache::FindAndLockMip(const SkBitmap& orig, + SkMipMap const ** mip) { + SkAutoMutexAcquire am(gMutex); + return get_cache()->findAndLockMip(orig, mip); +} + SkScaledImageCache::ID* SkScaledImageCache::AddAndLock(const SkBitmap& orig, SkScalar scaleX, SkScalar scaleY, @@ -383,6 +449,12 @@ SkScaledImageCache::ID* SkScaledImageCache::AddAndLock(const SkBitmap& orig, return get_cache()->addAndLock(orig, scaleX, scaleY, scaled); } +SkScaledImageCache::ID* SkScaledImageCache::AddAndLockMip(const SkBitmap& orig, + const SkMipMap* mip) { + SkAutoMutexAcquire am(gMutex); + return get_cache()->addAndLockMip(orig, mip); +} + void SkScaledImageCache::Unlock(SkScaledImageCache::ID* id) { SkAutoMutexAcquire am(gMutex); return get_cache()->unlock(id); diff --git a/src/core/SkScaledImageCache.h b/src/core/SkScaledImageCache.h index 3d85ce37a2..f1f6c4fd7e 100644 --- a/src/core/SkScaledImageCache.h +++ b/src/core/SkScaledImageCache.h @@ -10,6 +10,8 @@ #include "SkBitmap.h" +class SkMipMap; + /** * Cache object for bitmaps (with possible scale in X Y as part of the key). * @@ -31,10 +33,12 @@ public: static ID* FindAndLock(const SkBitmap& original, SkScalar scaleX, SkScalar scaleY, SkBitmap* scaled); - + static ID* FindAndLockMip(const SkBitmap& original, SkMipMap const**); + static ID* AddAndLock(const SkBitmap& original, SkScalar scaleX, - SkScalar scaleY, const SkBitmap& scaled); - + SkScalar scaleY, const SkBitmap& scaled); + static ID* AddAndLockMip(const SkBitmap& original, const SkMipMap*); + static void Unlock(ID*); static size_t GetBytesUsed(); @@ -56,6 +60,7 @@ public: */ ID* findAndLock(const SkBitmap& original, SkScalar scaleX, SkScalar scaleY, SkBitmap* scaled); + ID* findAndLockMip(const SkBitmap& original, SkMipMap const**); /** * To add a new (scaled) bitmap to the cache, call AddAndLock. Use the @@ -63,6 +68,7 @@ public: */ ID* addAndLock(const SkBitmap& original, SkScalar scaleX, SkScalar scaleY, const SkBitmap& scaled); + ID* addAndLockMip(const SkBitmap& original, const SkMipMap*); /** * Given a non-null ID ptr returned by either findAndLock or addAndLock, @@ -91,6 +97,8 @@ private: size_t fByteLimit; int fCount; + Rec* findAndLock(const SkBitmap& original, SkScalar sx, SkScalar sy); + void purgeAsNeeded(); // linklist management |