зеркало из https://github.com/mozilla/moz-skia.git
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
This commit is contained in:
Родитель
58c856a54a
Коммит
d94697c21a
|
@ -67,84 +67,26 @@ protected:
|
|||
return this->INHERITED::onQuery(evt);
|
||||
}
|
||||
|
||||
void drawN(SkCanvas* canvas, const SkBitmap& bitmap) {
|
||||
SkAutoCanvasRestore acr(canvas, true);
|
||||
for (int i = N; i > 1; i >>= 1) {
|
||||
canvas->drawBitmap(bitmap, 0, 0, NULL);
|
||||
canvas->translate(SkIntToScalar(N + 8), 0);
|
||||
canvas->scale(SK_ScalarHalf, SK_ScalarHalf);
|
||||
}
|
||||
}
|
||||
|
||||
void drawN2(SkCanvas* canvas, const SkBitmap& bitmap) {
|
||||
SkBitmap bg;
|
||||
bg.setConfig(SkBitmap::kARGB_8888_Config, N, N);
|
||||
bg.allocPixels();
|
||||
|
||||
SkAutoCanvasRestore acr(canvas, true);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
bg.eraseColor(SK_ColorTRANSPARENT);
|
||||
SkCanvas c(bg);
|
||||
c.scale(SK_Scalar1 / (1 << i), SK_Scalar1 / (1 << i));
|
||||
c.drawBitmap(bitmap, 0, 0, NULL);
|
||||
|
||||
canvas->save();
|
||||
canvas->scale(SkIntToScalar(1 << i), SkIntToScalar(1 << i));
|
||||
canvas->drawBitmap(bg, 0, 0, NULL);
|
||||
canvas->restore();
|
||||
canvas->translate(SkIntToScalar(N + 8), 0);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void onDrawContent(SkCanvas* canvas) {
|
||||
this->init();
|
||||
canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
|
||||
|
||||
canvas->scale(1.00000001f, 0.9999999f);
|
||||
|
||||
drawN2(canvas, fBitmap);
|
||||
|
||||
canvas->translate(0, SkIntToScalar(N + 8));
|
||||
SkBitmap bitmap(fBitmap);
|
||||
bitmap.buildMipMap();
|
||||
drawN2(canvas, bitmap);
|
||||
|
||||
SkScalar time = SampleCode::GetAnimScalar(SkIntToScalar(1)/4,
|
||||
SkIntToScalar(2));
|
||||
if (time >= SK_Scalar1) {
|
||||
time = SkIntToScalar(2) - time;
|
||||
}
|
||||
fWidth = 8 + SkScalarRound(N * time);
|
||||
|
||||
SkRect dst;
|
||||
dst.set(0, 0, SkIntToScalar(fWidth), SkIntToScalar(fWidth));
|
||||
|
||||
static const SkPaint::FilterLevel gLevel[] = {
|
||||
SkPaint::kNone_FilterLevel,
|
||||
SkPaint::kLow_FilterLevel,
|
||||
SkPaint::kMedium_FilterLevel,
|
||||
SkPaint::kHigh_FilterLevel,
|
||||
};
|
||||
|
||||
SkPaint paint;
|
||||
paint.setFilterBitmap(true);
|
||||
paint.setAntiAlias(true);
|
||||
|
||||
canvas->translate(0, SkIntToScalar(N + 8));
|
||||
canvas->drawBitmapRect(fBitmap, NULL, dst, NULL);
|
||||
canvas->translate(SkIntToScalar(N + 8), 0);
|
||||
canvas->drawBitmapRect(fBitmap, NULL, dst, &paint);
|
||||
canvas->translate(-SkIntToScalar(N + 8), SkIntToScalar(N + 8));
|
||||
canvas->drawBitmapRect(bitmap, NULL, dst, NULL);
|
||||
canvas->translate(SkIntToScalar(N + 8), 0);
|
||||
canvas->drawBitmapRect(bitmap, NULL, dst, &paint);
|
||||
|
||||
SkShader* s = SkShader::CreateBitmapShader(bitmap,
|
||||
SkShader::kRepeat_TileMode,
|
||||
SkShader::kRepeat_TileMode);
|
||||
paint.setShader(s)->unref();
|
||||
SkMatrix m;
|
||||
m.setScale(SkIntToScalar(fWidth) / N,
|
||||
SkIntToScalar(fWidth) / N);
|
||||
s->setLocalMatrix(m);
|
||||
SkRect r;
|
||||
r.set(0, 0, SkIntToScalar(4*N), SkIntToScalar(5*N/2));
|
||||
r.offset(SkIntToScalar(N + 12), -SkIntToScalar(N + 4));
|
||||
canvas->drawRect(r, paint);
|
||||
|
||||
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(gLevel); ++i) {
|
||||
SkScalar x = 10 + i * 100;
|
||||
SkScalar y = 10;
|
||||
|
||||
paint.setFilterLevel(gLevel[i]);
|
||||
|
||||
canvas->drawBitmap(fBitmap, x, y, &paint);
|
||||
}
|
||||
this->inval(NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче