From 67ed64e9aa70f5a95a2d309f9b73dc0009f3ed8c Mon Sep 17 00:00:00 2001 From: "commit-bot@chromium.org" Date: Mon, 5 Aug 2013 19:42:56 +0000 Subject: GPU Font Cache improvements: - If a strike has multiple atlases, check all for room for a new glyph - Mark remaining atlases unused after a purge, then check for an unused atlas before purging (reduces TextContext flushes and ghosting) - Hide Atlas management a little better inside AtlasMgr R=robertphillips@google.com, bsalomon@google.com Author: jvanverth@google.com Review URL: https://chromiumcodereview.appspot.com/21594005 git-svn-id: http://skia.googlecode.com/svn/trunk@10544 2bbb7eff-a529-9590-31e7-b0007b416f81 --- src/gpu/GrTextStrike.cpp | 80 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 12 deletions(-) (limited to 'src/gpu/GrTextStrike.cpp') diff --git a/src/gpu/GrTextStrike.cpp b/src/gpu/GrTextStrike.cpp index 071c5d2724..9373351f22 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, @@ -61,6 +69,34 @@ 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) { @@ -68,13 +104,17 @@ void GrFontCache::purgeExceptFor(GrTextStrike* preserveStrike) { 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; } -- cgit v1.2.3