make imagecache's Key more general purpose

This should allow other clients with different sized keys to still use the cache.

BUG=skia:
R=fmalita@google.com, mtklein@google.com

Author: reed@google.com

Review URL: https://codereview.chromium.org/472343002
This commit is contained in:
reed 2014-08-20 13:41:56 -07:00 committed by Commit bot
parent 260d237566
commit 4f987e9431
2 changed files with 75 additions and 58 deletions

View File

@ -30,57 +30,28 @@ static inline SkScaledImageCache::Rec* id_to_rec(SkScaledImageCache::ID* id) {
return reinterpret_cast<SkScaledImageCache::Rec*>(id);
}
struct SkScaledImageCache::Key {
Key(uint32_t genID,
SkScalar scaleX,
SkScalar scaleY,
SkIRect bounds)
: fGenID(genID)
, fScaleX(scaleX)
, fScaleY(scaleY)
, fBounds(bounds) {
fHash = SkChecksum::Murmur3(&fGenID, 28);
}
void SkScaledImageCache::Key::init(size_t length) {
SkASSERT(SkAlign4(length) == length);
// 2 is fCount32 and fHash
fCount32 = SkToS32(2 + (length >> 2));
// skip both of our fields whe computing the murmur
fHash = SkChecksum::Murmur3(this->as32() + 2, (fCount32 - 2) << 2);
}
bool operator<(const Key& other) const {
const uint32_t* a = &fGenID;
const uint32_t* b = &other.fGenID;
for (int i = 0; i < 7; ++i) {
if (a[i] < b[i]) {
return true;
}
if (a[i] > b[i]) {
return false;
}
}
return false;
}
bool operator==(const Key& other) const {
const uint32_t* a = &fHash;
const uint32_t* b = &other.fHash;
for (int i = 0; i < 8; ++i) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}
uint32_t fHash;
uint32_t fGenID;
float fScaleX;
float fScaleY;
SkIRect fBounds;
};
SkScaledImageCache::Key* SkScaledImageCache::Key::clone() const {
size_t size = fCount32 << 2;
void* copy = sk_malloc_throw(size);
memcpy(copy, this, size);
return (Key*)copy;
}
struct SkScaledImageCache::Rec {
Rec(const Key& key, const SkBitmap& bm) : fKey(key), fBitmap(bm) {
Rec(const Key& key, const SkBitmap& bm) : fKey(key.clone()), fBitmap(bm) {
fLockCount = 1;
fMip = NULL;
}
Rec(const Key& key, const SkMipMap* mip) : fKey(key) {
Rec(const Key& key, const SkMipMap* mip) : fKey(key.clone()) {
fLockCount = 1;
fMip = mip;
mip->ref();
@ -88,10 +59,11 @@ struct SkScaledImageCache::Rec {
~Rec() {
SkSafeUnref(fMip);
sk_free(fKey);
}
static const Key& GetKey(const Rec& rec) { return rec.fKey; }
static uint32_t Hash(const Key& key) { return key.fHash; }
static const Key& GetKey(const Rec& rec) { return *rec.fKey; }
static uint32_t Hash(const Key& key) { return key.hash(); }
size_t bytesUsed() const {
return fMip ? fMip->getSize() : fBitmap.getSize();
@ -101,7 +73,7 @@ struct SkScaledImageCache::Rec {
Rec* fPrev;
// this guy wants to be 64bit aligned
Key fKey;
Key* fKey;
int32_t fLockCount;
@ -288,22 +260,33 @@ SkScaledImageCache::~SkScaledImageCache() {
////////////////////////////////////////////////////////////////////////////////
struct GenWHKey : public SkScaledImageCache::Key {
public:
GenWHKey(uint32_t genID, SkScalar scaleX, SkScalar scaleY, const SkIRect& bounds)
: fGenID(genID)
, fScaleX(scaleX)
, fScaleY(scaleY)
, fBounds(bounds) {
this->init(7 * sizeof(uint32_t));
}
uint32_t fGenID;
SkScalar fScaleX;
SkScalar fScaleY;
SkIRect fBounds;
};
SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(uint32_t genID,
SkScalar scaleX,
SkScalar scaleY,
const SkIRect& bounds) {
const Key key(genID, scaleX, scaleY, bounds);
return this->findAndLock(key);
return this->findAndLock(GenWHKey(genID, scaleX, scaleY, bounds));
}
/**
This private method is the fully general record finder. All other
record finders should call this function or the one above. */
SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(const SkScaledImageCache::Key& key) {
if (key.fBounds.isEmpty()) {
return NULL;
}
#ifdef USE_HASH
Rec* rec = fHash->find(key);
#else
@ -382,7 +365,7 @@ SkScaledImageCache::ID* SkScaledImageCache::findAndLockMip(const SkBitmap& orig,
SkScaledImageCache::ID* SkScaledImageCache::addAndLock(SkScaledImageCache::Rec* rec) {
SkASSERT(rec);
// See if we already have this key (racy inserts, etc.)
Rec* existing = this->findAndLock(rec->fKey);
Rec* existing = this->findAndLock(*rec->fKey);
if (NULL != existing) {
// Since we already have a matching entry, just delete the new one and return.
// Call sites cannot assume the passed in object will live past this call.
@ -406,7 +389,7 @@ SkScaledImageCache::ID* SkScaledImageCache::addAndLock(uint32_t genID,
int32_t width,
int32_t height,
const SkBitmap& bitmap) {
Key key(genID, SK_Scalar1, SK_Scalar1, SkIRect::MakeWH(width, height));
GenWHKey key(genID, SK_Scalar1, SK_Scalar1, SkIRect::MakeWH(width, height));
Rec* rec = SkNEW_ARGS(Rec, (key, bitmap));
return this->addAndLock(rec);
}
@ -423,7 +406,7 @@ SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const SkBitmap& orig,
if (bounds.isEmpty()) {
return NULL;
}
Key key(orig.getGenerationID(), scaleX, scaleY, bounds);
GenWHKey key(orig.getGenerationID(), scaleX, scaleY, bounds);
Rec* rec = SkNEW_ARGS(Rec, (key, scaled));
return this->addAndLock(rec);
}
@ -434,7 +417,7 @@ SkScaledImageCache::ID* SkScaledImageCache::addAndLockMip(const SkBitmap& orig,
if (bounds.isEmpty()) {
return NULL;
}
Key key(orig.getGenerationID(), 0, 0, bounds);
GenWHKey key(orig.getGenerationID(), 0, 0, bounds);
Rec* rec = SkNEW_ARGS(Rec, (key, mip));
return this->addAndLock(rec);
}
@ -494,7 +477,7 @@ void SkScaledImageCache::purgeAsNeeded() {
SkASSERT(used <= bytesUsed);
this->detach(rec);
#ifdef USE_HASH
fHash->remove(rec->fKey);
fHash->remove(*rec->fKey);
#endif
SkDELETE(rec);

View File

@ -27,6 +27,41 @@ class SkScaledImageCache {
public:
struct ID;
struct Key {
// Call this to access your private contents. Must not use the address after calling init()
void* writableContents() { return this + 1; }
// must call this after your private data has been written.
// length must be a multiple of 4
void init(size_t length);
// This is only valid after having called init().
uint32_t hash() const { return fHash; }
bool operator==(const Key& other) const {
const uint32_t* a = this->as32();
const uint32_t* b = other.as32();
for (int i = 0; i < fCount32; ++i) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}
// delete using sk_free
Key* clone() const;
private:
// store fCount32 first, so we don't consider it in operator<
int32_t fCount32; // 2 + user contents count32
uint32_t fHash;
/* uint32_t fContents32[] */
const uint32_t* as32() const { return (const uint32_t*)this; }
const uint32_t* as32SkipCount() const { return this->as32() + 1; }
};
/**
* Returns a locked/pinned SkDiscardableMemory instance for the specified
* number of bytes, or NULL on failure.
@ -173,7 +208,6 @@ public:
public:
struct Rec;
struct Key;
private:
Rec* fHead;
Rec* fTail;