aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-07-24 14:31:33 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-07-24 14:31:33 +0000
commitd94697c21ae479df4190a1afbf08d85ce244a4ef (patch)
tree3a8170934ed3aa549e0d9a2a3f8eb22f2c9640e7 /src
parent58c856a54a75e703aa3c82a0cd4e1affd9bd8ffc (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.cpp46
-rw-r--r--src/core/SkMipMap.cpp19
-rw-r--r--src/core/SkMipMap.h14
-rw-r--r--src/core/SkScaledImageCache.cpp96
-rw-r--r--src/core/SkScaledImageCache.h14
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