Replace use of GrTHashTable in GrFontCache with SkTDynamicHash.
Searching the font cache for existing text strikes was showing up as a hotspot on Android. This change reduces that cost. R=bsalomon@google.com, robertphillips@google.com, mtklein@google.com Author: jvanverth@google.com Review URL: https://codereview.chromium.org/390103002
This commit is contained in:
parent
1c63bf6e90
commit
dd6d22751a
@ -10,6 +10,7 @@
|
||||
|
||||
#include "GrRect.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkChecksum.h"
|
||||
|
||||
class GrPlot;
|
||||
|
||||
@ -72,7 +73,14 @@ struct GrGlyph {
|
||||
static inline uint16_t UnpackID(PackedID packed) {
|
||||
return (uint16_t)packed;
|
||||
}
|
||||
|
||||
static inline const GrGlyph::PackedID& GetKey(const GrGlyph& glyph) {
|
||||
return glyph.fPackedID;
|
||||
}
|
||||
|
||||
static inline uint32_t Hash(GrGlyph::PackedID key) {
|
||||
return SkChecksum::Murmur3(&key, sizeof(key));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -123,7 +123,7 @@ private:
|
||||
static uint32_t ComputeChecksum(const SkDescriptor* desc) {
|
||||
const uint32_t* ptr = (const uint32_t*)desc + 1; // skip the checksum field
|
||||
size_t len = desc->fLength - sizeof(uint32_t);
|
||||
return SkChecksum::Compute(ptr, len);
|
||||
return SkChecksum::Murmur3(ptr, len);
|
||||
}
|
||||
|
||||
// private so no one can create one except our factories
|
||||
|
@ -39,7 +39,11 @@ GrFontCache::GrFontCache(GrGpu* gpu) : fGpu(gpu) {
|
||||
}
|
||||
|
||||
GrFontCache::~GrFontCache() {
|
||||
fCache.deleteAll();
|
||||
SkTDynamicHash<GrTextStrike, GrFontDescKey>::Iter iter(&fCache);
|
||||
while (!iter.done()) {
|
||||
SkDELETE(&(*iter));
|
||||
++iter;
|
||||
}
|
||||
for (int i = 0; i < kAtlasCount; ++i) {
|
||||
delete fAtlases[i];
|
||||
}
|
||||
@ -74,8 +78,7 @@ static int mask_format_to_atlas_index(GrMaskFormat format) {
|
||||
return sAtlasIndices[format];
|
||||
}
|
||||
|
||||
GrTextStrike* GrFontCache::generateStrike(GrFontScaler* scaler,
|
||||
const Key& key) {
|
||||
GrTextStrike* GrFontCache::generateStrike(GrFontScaler* scaler) {
|
||||
GrMaskFormat format = scaler->getMaskFormat();
|
||||
GrPixelConfig config = mask_format_to_pixel_config(format);
|
||||
int atlasIndex = mask_format_to_atlas_index(format);
|
||||
@ -90,7 +93,7 @@ GrTextStrike* GrFontCache::generateStrike(GrFontScaler* scaler,
|
||||
}
|
||||
GrTextStrike* strike = SkNEW_ARGS(GrTextStrike,
|
||||
(this, scaler->getKey(), format, fAtlases[atlasIndex]));
|
||||
fCache.insert(key, strike);
|
||||
fCache.add(strike);
|
||||
|
||||
if (fHead) {
|
||||
fHead->fPrev = strike;
|
||||
@ -106,7 +109,12 @@ GrTextStrike* GrFontCache::generateStrike(GrFontScaler* scaler,
|
||||
}
|
||||
|
||||
void GrFontCache::freeAll() {
|
||||
fCache.deleteAll();
|
||||
SkTDynamicHash<GrTextStrike, GrFontDescKey>::Iter iter(&fCache);
|
||||
while (!iter.done()) {
|
||||
SkDELETE(&(*iter));
|
||||
++iter;
|
||||
}
|
||||
fCache.rewind();
|
||||
for (int i = 0; i < kAtlasCount; ++i) {
|
||||
delete fAtlases[i];
|
||||
fAtlases[i] = NULL;
|
||||
@ -116,8 +124,7 @@ void GrFontCache::freeAll() {
|
||||
}
|
||||
|
||||
void GrFontCache::purgeStrike(GrTextStrike* strike) {
|
||||
const GrFontCache::Key key(strike->fFontScalerKey);
|
||||
fCache.remove(key, strike);
|
||||
fCache.remove(*(strike->fFontScalerKey));
|
||||
this->detachStrikeFromList(strike);
|
||||
delete strike;
|
||||
}
|
||||
@ -237,13 +244,13 @@ GrTextStrike::GrTextStrike(GrFontCache* cache, const GrFontDescKey* key,
|
||||
#endif
|
||||
}
|
||||
|
||||
// this signature is needed because it's used with
|
||||
// SkTDArray::visitAll() (see destructor)
|
||||
static void free_glyph(GrGlyph*& glyph) { glyph->free(); }
|
||||
|
||||
GrTextStrike::~GrTextStrike() {
|
||||
fFontScalerKey->unref();
|
||||
fCache.getArray().visitAll(free_glyph);
|
||||
SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache);
|
||||
while (!iter.done()) {
|
||||
(*iter).free();
|
||||
++iter;
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
gCounter -= 1;
|
||||
@ -266,16 +273,17 @@ GrGlyph* GrTextStrike::generateGlyph(GrGlyph::PackedID packed,
|
||||
|
||||
GrGlyph* glyph = fPool.alloc();
|
||||
glyph->init(packed, bounds);
|
||||
fCache.insert(packed, glyph);
|
||||
fCache.add(glyph);
|
||||
return glyph;
|
||||
}
|
||||
|
||||
void GrTextStrike::removePlot(const GrPlot* plot) {
|
||||
SkTDArray<GrGlyph*>& glyphArray = fCache.getArray();
|
||||
for (int i = 0; i < glyphArray.count(); ++i) {
|
||||
if (plot == glyphArray[i]->fPlot) {
|
||||
glyphArray[i]->fPlot = NULL;
|
||||
SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache);
|
||||
while (!iter.done()) {
|
||||
if (plot == (*iter).fPlot) {
|
||||
(*iter).fPlot = NULL;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
|
||||
GrAtlas::RemovePlot(&fPlotUsage, plot);
|
||||
@ -290,7 +298,7 @@ bool GrTextStrike::addGlyphToAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
|
||||
|
||||
SkASSERT(glyph);
|
||||
SkASSERT(scaler);
|
||||
SkASSERT(fCache.contains(glyph));
|
||||
SkASSERT(fCache.find(glyph->fPackedID));
|
||||
SkASSERT(NULL == glyph->fPlot);
|
||||
|
||||
SkAutoUnref ar(SkSafeRef(scaler));
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
#include "GrAllocPool.h"
|
||||
#include "GrFontScaler.h"
|
||||
#include "GrTHashTable.h"
|
||||
#include "SkTDynamicHash.h"
|
||||
#include "GrGlyph.h"
|
||||
#include "GrDrawTarget.h"
|
||||
#include "GrAtlas.h"
|
||||
@ -39,22 +39,25 @@ public:
|
||||
bool addGlyphToAtlas(GrGlyph*, GrFontScaler*);
|
||||
|
||||
// testing
|
||||
int countGlyphs() const { return fCache.getArray().count(); }
|
||||
const GrGlyph* glyphAt(int index) const {
|
||||
return fCache.getArray()[index];
|
||||
}
|
||||
int countGlyphs() const { return fCache.count(); }
|
||||
|
||||
// remove any references to this plot
|
||||
void removePlot(const GrPlot* plot);
|
||||
|
||||
static const GrFontDescKey& GetKey(const GrTextStrike& ts) {
|
||||
return *(ts.fFontScalerKey);
|
||||
}
|
||||
static uint32_t Hash(const GrFontDescKey& key) {
|
||||
return key.getHash();
|
||||
}
|
||||
|
||||
public:
|
||||
// for easy removal from list
|
||||
GrTextStrike* fPrev;
|
||||
GrTextStrike* fNext;
|
||||
|
||||
private:
|
||||
class Key;
|
||||
GrTHashTable<GrGlyph, Key, 7> fCache;
|
||||
SkTDynamicHash<GrGlyph, GrGlyph::PackedID> fCache;
|
||||
const GrFontDescKey* fFontScalerKey;
|
||||
GrTAllocPool<GrGlyph> fPool;
|
||||
|
||||
@ -83,10 +86,7 @@ public:
|
||||
bool freeUnusedPlot(GrTextStrike* preserveStrike);
|
||||
|
||||
// testing
|
||||
int countStrikes() const { return fCache.getArray().count(); }
|
||||
const GrTextStrike* strikeAt(int index) const {
|
||||
return fCache.getArray()[index];
|
||||
}
|
||||
int countStrikes() const { return fCache.count(); }
|
||||
GrTextStrike* getHeadStrike() const { return fHead; }
|
||||
|
||||
void updateTextures() {
|
||||
@ -117,8 +117,7 @@ public:
|
||||
private:
|
||||
friend class GrFontPurgeListener;
|
||||
|
||||
class Key;
|
||||
GrTHashTable<GrTextStrike, Key, 8> fCache;
|
||||
SkTDynamicHash<GrTextStrike, GrFontDescKey> fCache;
|
||||
// for LRU
|
||||
GrTextStrike* fHead;
|
||||
GrTextStrike* fTail;
|
||||
@ -126,7 +125,7 @@ private:
|
||||
GrGpu* fGpu;
|
||||
GrAtlas* fAtlases[kAtlasCount];
|
||||
|
||||
GrTextStrike* generateStrike(GrFontScaler*, const Key&);
|
||||
GrTextStrike* generateStrike(GrFontScaler*);
|
||||
inline void detachStrikeFromList(GrTextStrike*);
|
||||
void purgeStrike(GrTextStrike* strike);
|
||||
};
|
||||
|
@ -11,25 +11,6 @@
|
||||
#ifndef GrTextStrike_impl_DEFINED
|
||||
#define GrTextStrike_impl_DEFINED
|
||||
|
||||
class GrFontCache::Key {
|
||||
public:
|
||||
explicit Key(const GrFontDescKey* fontScalarKey) {
|
||||
fFontScalerKey = fontScalarKey;
|
||||
}
|
||||
|
||||
intptr_t getHash() const { return fFontScalerKey->getHash(); }
|
||||
|
||||
static bool LessThan(const GrTextStrike& strike, const Key& key) {
|
||||
return *strike.getFontScalerKey() < *key.fFontScalerKey;
|
||||
}
|
||||
static bool Equals(const GrTextStrike& strike, const Key& key) {
|
||||
return *strike.getFontScalerKey() == *key.fFontScalerKey;
|
||||
}
|
||||
|
||||
private:
|
||||
const GrFontDescKey* fFontScalerKey;
|
||||
};
|
||||
|
||||
void GrFontCache::detachStrikeFromList(GrTextStrike* strike) {
|
||||
if (strike->fPrev) {
|
||||
SkASSERT(fHead != strike);
|
||||
@ -51,10 +32,9 @@ void GrFontCache::detachStrikeFromList(GrTextStrike* strike) {
|
||||
GrTextStrike* GrFontCache::getStrike(GrFontScaler* scaler, bool useDistanceField) {
|
||||
this->validate();
|
||||
|
||||
const Key key(scaler->getKey());
|
||||
GrTextStrike* strike = fCache.find(key);
|
||||
GrTextStrike* strike = fCache.find(*(scaler->getKey()));
|
||||
if (NULL == strike) {
|
||||
strike = this->generateStrike(scaler, key);
|
||||
strike = this->generateStrike(scaler);
|
||||
} else if (strike->fPrev) {
|
||||
// Need to put the strike at the head of its dllist, since that is how
|
||||
// we age the strikes for purging (we purge from the back of the list)
|
||||
@ -72,27 +52,6 @@ GrTextStrike* GrFontCache::getStrike(GrFontScaler* scaler, bool useDistanceField
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* This Key just wraps a glyphID, and matches the protocol need for
|
||||
* GrTHashTable
|
||||
*/
|
||||
class GrTextStrike::Key {
|
||||
public:
|
||||
Key(GrGlyph::PackedID id) : fPackedID(id) {}
|
||||
|
||||
uint32_t getHash() const { return fPackedID; }
|
||||
|
||||
static bool LessThan(const GrGlyph& glyph, const Key& key) {
|
||||
return glyph.fPackedID < key.fPackedID;
|
||||
}
|
||||
static bool Equals(const GrGlyph& glyph, const Key& key) {
|
||||
return glyph.fPackedID == key.fPackedID;
|
||||
}
|
||||
|
||||
private:
|
||||
GrGlyph::PackedID fPackedID;
|
||||
};
|
||||
|
||||
GrGlyph* GrTextStrike::getGlyph(GrGlyph::PackedID packed,
|
||||
GrFontScaler* scaler) {
|
||||
GrGlyph* glyph = fCache.find(packed);
|
||||
|
Loading…
Reference in New Issue
Block a user