| Index: src/gpu/GrTextStrike.cpp
|
| diff --git a/src/gpu/GrTextStrike.cpp b/src/gpu/GrTextStrike.cpp
|
| index 071c5d272486eadc77a36200e337e6bc15e19088..9373351f227ee0c0076af7016d64f3a772a5f9a3 100644
|
| --- a/src/gpu/GrTextStrike.cpp
|
| +++ b/src/gpu/GrTextStrike.cpp
|
| @@ -16,6 +16,11 @@ SK_DEFINE_INST_COUNT(GrKey)
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| +#define FONT_CACHE_STATS 0
|
| +#if FONT_CACHE_STATS
|
| +static int g_PurgeCount = 0;
|
| +#endif
|
| +
|
| GrFontCache::GrFontCache(GrGpu* gpu) : fGpu(gpu) {
|
| gpu->ref();
|
| fAtlasMgr = NULL;
|
| @@ -27,6 +32,9 @@ GrFontCache::~GrFontCache() {
|
| fCache.deleteAll();
|
| delete fAtlasMgr;
|
| fGpu->unref();
|
| +#if FONT_CACHE_STATS
|
| + GrPrintf("Num purges: %d\n", g_PurgeCount);
|
| +#endif
|
| }
|
|
|
| GrTextStrike* GrFontCache::generateStrike(GrFontScaler* scaler,
|
| @@ -62,19 +70,51 @@ void GrFontCache::freeAll() {
|
|
|
| void GrFontCache::purgeExceptFor(GrTextStrike* preserveStrike) {
|
| GrTextStrike* strike = fTail;
|
| + bool purge = true;
|
| + while (strike) {
|
| + if (strike == preserveStrike) {
|
| + strike = strike->fPrev;
|
| + continue;
|
| + }
|
| + GrTextStrike* strikeToPurge = strike;
|
| + strike = strikeToPurge->fPrev;
|
| + if (purge) {
|
| + // keep purging if we won't free up any atlases with this strike.
|
| + purge = (NULL == strikeToPurge->fAtlas);
|
| + int index = fCache.slowFindIndex(strikeToPurge);
|
| + GrAssert(index >= 0);
|
| + fCache.removeAt(index, strikeToPurge->fFontScalerKey->getHash());
|
| + this->detachStrikeFromList(strikeToPurge);
|
| + delete strikeToPurge;
|
| + } else {
|
| + // for the remaining strikes, we just mark them unused
|
| + GrAtlas::MarkAllUnused(strikeToPurge->fAtlas);
|
| + }
|
| + }
|
| +#if FONT_CACHE_STATS
|
| + ++g_PurgeCount;
|
| +#endif
|
| +}
|
| +
|
| +void GrFontCache::freeAtlasExceptFor(GrTextStrike* preserveStrike) {
|
| + GrTextStrike* strike = fTail;
|
| while (strike) {
|
| if (strike == preserveStrike) {
|
| strike = strike->fPrev;
|
| continue;
|
| }
|
| GrTextStrike* strikeToPurge = strike;
|
| - // keep going if we won't free up any atlases with this strike.
|
| - strike = (NULL == strikeToPurge->fAtlas) ? strikeToPurge->fPrev : NULL;
|
| - int index = fCache.slowFindIndex(strikeToPurge);
|
| - GrAssert(index >= 0);
|
| - fCache.removeAt(index, strikeToPurge->fFontScalerKey->getHash());
|
| - this->detachStrikeFromList(strikeToPurge);
|
| - delete strikeToPurge;
|
| + strike = strikeToPurge->fPrev;
|
| + if (strikeToPurge->removeUnusedAtlases()) {
|
| + if (NULL == strikeToPurge->fAtlas) {
|
| + int index = fCache.slowFindIndex(strikeToPurge);
|
| + GrAssert(index >= 0);
|
| + fCache.removeAt(index, strikeToPurge->fFontScalerKey->getHash());
|
| + this->detachStrikeFromList(strikeToPurge);
|
| + delete strikeToPurge;
|
| + }
|
| + break;
|
| + }
|
| }
|
| }
|
|
|
| @@ -140,12 +180,20 @@ GrTextStrike::GrTextStrike(GrFontCache* cache, const GrKey* key,
|
| #endif
|
| }
|
|
|
| -static void FreeGlyph(GrGlyph*& glyph) { glyph->free(); }
|
| +// these signatures are needed because they're used with
|
| +// SkTDArray::visitAll() (see destructor & removeUnusedAtlases())
|
| +static void free_glyph(GrGlyph*& glyph) { glyph->free(); }
|
| +
|
| +static void invalidate_glyph(GrGlyph*& glyph) {
|
| + if (glyph->fAtlas && !glyph->fAtlas->used()) {
|
| + glyph->fAtlas = NULL;
|
| + }
|
| +}
|
|
|
| GrTextStrike::~GrTextStrike() {
|
| GrAtlas::FreeLList(fAtlas);
|
| fFontScalerKey->unref();
|
| - fCache.getArray().visitAll(FreeGlyph);
|
| + fCache.getArray().visitAll(free_glyph);
|
|
|
| #if GR_DEBUG
|
| gCounter -= 1;
|
| @@ -166,6 +214,13 @@ GrGlyph* GrTextStrike::generateGlyph(GrGlyph::PackedID packed,
|
| return glyph;
|
| }
|
|
|
| +bool GrTextStrike::removeUnusedAtlases() {
|
| + fCache.getArray().visitAll(invalidate_glyph);
|
| + return GrAtlas::RemoveUnusedAtlases(fAtlasMgr, &fAtlas);
|
| +
|
| + return false;
|
| +}
|
| +
|
| bool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
|
| #if 0 // testing hack to force us to flush our cache often
|
| static int gCounter;
|
| @@ -176,6 +231,7 @@ bool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
|
| GrAssert(scaler);
|
| GrAssert(fCache.contains(glyph));
|
| if (glyph->fAtlas) {
|
| + glyph->fAtlas->setUsed(true);
|
| return true;
|
| }
|
|
|
| @@ -191,7 +247,7 @@ bool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
|
| return false;
|
| }
|
|
|
| - GrAtlas* atlas = fAtlasMgr->addToAtlas(fAtlas, glyph->width(),
|
| + GrAtlas* atlas = fAtlasMgr->addToAtlas(&fAtlas, glyph->width(),
|
| glyph->height(), storage.get(),
|
| fMaskFormat,
|
| &glyph->fAtlasLocation);
|
| @@ -199,7 +255,7 @@ bool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
|
| return false;
|
| }
|
|
|
| - // update fAtlas as well, since they may be chained in a linklist
|
| - glyph->fAtlas = fAtlas = atlas;
|
| + glyph->fAtlas = atlas;
|
| + atlas->setUsed(true);
|
| return true;
|
| }
|
|
|