diff options
author | Herbert Derby <herb@google.com> | 2018-04-17 08:04:47 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-04-17 13:55:43 +0000 |
commit | 671e7eea42aeebea55c60c574e8c3ae580f2da53 (patch) | |
tree | 720a8227dc15d7fef4ed50681240317675db8146 | |
parent | c41569a29fde10c6fec43cc4593334e9a4b34b76 (diff) |
Reorganize strike cache and glyph cache code
BUG=skia:7515
Change-Id: I05867890e88de7a7d23b60d9eec989d93d39d333
Reviewed-on: https://skia-review.googlesource.com/121783
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Herb Derby <herb@google.com>
-rw-r--r-- | gn/core.gni | 1 | ||||
-rw-r--r-- | src/core/SkGlyphCache.cpp | 354 | ||||
-rw-r--r-- | src/core/SkGlyphCache.h | 13 | ||||
-rw-r--r-- | src/core/SkGraphics.cpp | 5 | ||||
-rw-r--r-- | src/core/SkStrikeCache.cpp | 350 | ||||
-rw-r--r-- | src/core/SkStrikeCache.h | 80 |
6 files changed, 404 insertions, 399 deletions
diff --git a/gn/core.gni b/gn/core.gni index 620aa23b05..d396105c88 100644 --- a/gn/core.gni +++ b/gn/core.gni @@ -294,6 +294,7 @@ skia_core_sources = [ "$_src/core/SkSpriteBlitter.h", "$_src/core/SkStream.cpp", "$_src/core/SkStreamPriv.h", + "$_src/core/SkStrikeCache.cpp", "$_src/core/SkStrikeCache.h", "$_src/core/SkString.cpp", "$_src/core/SkStringUtils.cpp", diff --git a/src/core/SkGlyphCache.cpp b/src/core/SkGlyphCache.cpp index 11b9728b77..58f0eb355a 100644 --- a/src/core/SkGlyphCache.cpp +++ b/src/core/SkGlyphCache.cpp @@ -5,7 +5,6 @@ * found in the LICENSE file. */ - #include "SkGlyphCache.h" #include "SkGraphics.h" #include "SkMutex.h" @@ -13,27 +12,9 @@ #include "SkPaintPriv.h" #include "SkPath.h" #include "SkTemplates.h" -#include "SkTraceMemoryDump.h" #include "SkTypeface.h" - #include <cctype> -//#define SPEW_PURGE_STATUS - -namespace { -const char gGlyphCacheDumpName[] = "skia/sk_glyph_cache"; -} // namespace - -// Returns the shared globals -static SkStrikeCache& get_globals() { - static SkOnce once; - static SkStrikeCache* globals; - - once([]{ globals = new SkStrikeCache; }); - return *globals; -} - -/////////////////////////////////////////////////////////////////////////////// SkGlyphCache::SkGlyphCache( const SkDescriptor& desc, std::unique_ptr<SkScalerContext> scaler, @@ -62,8 +43,6 @@ SkGlyphCache::CharGlyphRec* SkGlyphCache::getCharGlyphRec(SkPackedUnicharID pack return &fPackedUnicharIDToPackedGlyphID[packedUnicharID.hash() & kHashMask]; } -/////////////////////////////////////////////////////////////////////////////// - #ifdef SK_DEBUG #define VALIDATE() AutoValidate av(this) #else @@ -99,8 +78,6 @@ int SkGlyphCache::countCachedGlyphs() const { return fGlyphMap.count(); } -/////////////////////////////////////////////////////////////////////////////// - bool SkGlyphCache::isGlyphCached(SkGlyphID glyphID, SkFixed x, SkFixed y) const { SkPackedGlyphID packedGlyphID{glyphID, x, y}; return fGlyphMap.find(packedGlyphID) != nullptr; @@ -121,8 +98,6 @@ const SkGlyph& SkGlyphCache::getGlyphIDAdvance(uint16_t glyphID) { return *this->lookupByPackedGlyphID(packedGlyphID, kJustAdvance_MetricsType); } -/////////////////////////////////////////////////////////////////////////////// - const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode) { VALIDATE(); return *this->lookupByChar(charCode, kFull_MetricsType); @@ -412,91 +387,8 @@ void SkGlyphCache::dump() const { SkDebugf("%s\n", msg.c_str()); } -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -size_t SkStrikeCache::getTotalMemoryUsed() const { - SkAutoExclusive ac(fLock); - return fTotalMemoryUsed; -} - -int SkStrikeCache::getCacheCountUsed() const { - SkAutoExclusive ac(fLock); - return fCacheCount; -} - -int SkStrikeCache::getCacheCountLimit() const { - SkAutoExclusive ac(fLock); - return fCacheCountLimit; -} - -size_t SkStrikeCache::setCacheSizeLimit(size_t newLimit) { - static const size_t minLimit = 256 * 1024; - if (newLimit < minLimit) { - newLimit = minLimit; - } - - SkAutoExclusive ac(fLock); - - size_t prevLimit = fCacheSizeLimit; - fCacheSizeLimit = newLimit; - this->internalPurge(); - return prevLimit; -} - -size_t SkStrikeCache::getCacheSizeLimit() const { - SkAutoExclusive ac(fLock); - return fCacheSizeLimit; -} - -int SkStrikeCache::setCacheCountLimit(int newCount) { - if (newCount < 0) { - newCount = 0; - } - - SkAutoExclusive ac(fLock); - - int prevCount = fCacheCountLimit; - fCacheCountLimit = newCount; - this->internalPurge(); - return prevCount; -} - -int SkStrikeCache::getCachePointSizeLimit() const { - SkAutoExclusive ac(fLock); - return fPointSizeLimit; -} - -int SkStrikeCache::setCachePointSizeLimit(int newLimit) { - if (newLimit < 0) { - newLimit = 0; - } - - SkAutoExclusive ac(fLock); - - int prevLimit = fPointSizeLimit; - fPointSizeLimit = newLimit; - return prevLimit; -} - -void SkStrikeCache::purgeAll() { - SkAutoExclusive ac(fLock); - this->internalPurge(fTotalMemoryUsed); -} - SkExclusiveStrikePtr SkGlyphCache::FindStrikeExclusive(const SkDescriptor& desc) { - SkStrikeCache& globals = get_globals(); - SkGlyphCache* cache; - SkAutoExclusive ac(globals.fLock); - - for (cache = globals.internalGetHead(); cache != nullptr; cache = cache->fNext) { - if (*cache->fDesc == desc) { - globals.internalDetachCache(cache); - return SkExclusiveStrikePtr(cache); - } - } - - return SkExclusiveStrikePtr(nullptr); + return SkStrikeCache::FindStrikeExclusive(desc); } std::unique_ptr<SkScalerContext> SkGlyphCache::CreateScalerContext( @@ -510,15 +402,15 @@ std::unique_ptr<SkScalerContext> SkGlyphCache::CreateScalerContext( // cache once and try again // pass true the first time, to notice if the scalercontext failed, if (scaler == nullptr) { - get_globals().purgeAll(); + SkStrikeCache::PurgeAll(); scaler = typeface.createScalerContext(effects, &desc, false /* must succeed */); } return scaler; } SkExclusiveStrikePtr SkGlyphCache::FindOrCreateStrikeExclusive( - const SkDescriptor& desc, const SkScalerContextEffects& effects, const SkTypeface& typeface) { - + const SkDescriptor& desc, const SkScalerContextEffects& effects, const SkTypeface& typeface) +{ auto cache = SkGlyphCache::FindStrikeExclusive(desc); if (cache == nullptr) { auto scaler = CreateScalerContext(desc, effects, typeface); @@ -559,203 +451,6 @@ SkExclusiveStrikePtr SkGlyphCache::CreateStrikeExclusive( return SkExclusiveStrikePtr(new SkGlyphCache(desc, std::move(scaler), fontMetrics)); } -void SkGlyphCache::ForEachStrike(std::function<void(const SkGlyphCache&)> visitor) { - SkStrikeCache& globals = get_globals(); - SkAutoExclusive ac(globals.fLock); - SkGlyphCache* cache; - - globals.validate(); - - for (cache = globals.internalGetHead(); cache != nullptr; cache = cache->fNext) { - visitor(*cache); - } -} - -void SkGlyphCache::Dump() { - SkDebugf("GlyphCache [ used budget ]\n"); - SkDebugf(" bytes [ %8zu %8zu ]\n", - SkGraphics::GetFontCacheUsed(), SkGraphics::GetFontCacheLimit()); - SkDebugf(" count [ %8zu %8zu ]\n", - SkGraphics::GetFontCacheCountUsed(), SkGraphics::GetFontCacheCountLimit()); - - int counter = 0; - - auto visitor = [&counter](const SkGlyphCache& cache) { - const SkScalerContextRec& rec = cache.getScalerContext()->getRec(); - - SkDebugf("index %d\n", counter); - SkDebugf("%s", rec.dump().c_str()); - counter += 1; - }; - - ForEachStrike(visitor); -} - -void SkGlyphCache::DumpMemoryStatistics(SkTraceMemoryDump* dump) { - dump->dumpNumericValue(gGlyphCacheDumpName, "size", "bytes", SkGraphics::GetFontCacheUsed()); - dump->dumpNumericValue(gGlyphCacheDumpName, "budget_size", "bytes", - SkGraphics::GetFontCacheLimit()); - dump->dumpNumericValue(gGlyphCacheDumpName, "glyph_count", "objects", - SkGraphics::GetFontCacheCountUsed()); - dump->dumpNumericValue(gGlyphCacheDumpName, "budget_glyph_count", "objects", - SkGraphics::GetFontCacheCountLimit()); - - if (dump->getRequestedDetails() == SkTraceMemoryDump::kLight_LevelOfDetail) { - dump->setMemoryBacking(gGlyphCacheDumpName, "malloc", nullptr); - return; - } - - auto visitor = [&dump](const SkGlyphCache& cache) { - const SkTypeface* face = cache.getScalerContext()->getTypeface(); - const SkScalerContextRec& rec = cache.getScalerContext()->getRec(); - - SkString fontName; - face->getFamilyName(&fontName); - // Replace all special characters with '_'. - for (size_t index = 0; index < fontName.size(); ++index) { - if (!std::isalnum(fontName[index])) { - fontName[index] = '_'; - } - } - - SkString dumpName = SkStringPrintf( - "%s/%s_%d/%p", gGlyphCacheDumpName, fontName.c_str(), rec.fFontID, &cache); - - dump->dumpNumericValue(dumpName.c_str(), - "size", "bytes", cache.getMemoryUsed()); - dump->dumpNumericValue(dumpName.c_str(), - "glyph_count", "objects", cache.countCachedGlyphs()); - dump->setMemoryBacking(dumpName.c_str(), "malloc", nullptr); - }; - - ForEachStrike(visitor); -} - -/////////////////////////////////////////////////////////////////////////////// - -SkStrikeCache::~SkStrikeCache() { - SkGlyphCache* cache = fHead; - while (cache) { - SkGlyphCache* next = cache->fNext; - delete cache; - cache = next; - } -} - -void SkStrikeCache::AttachCache(SkGlyphCache* cache) { - if (cache == nullptr) { - return; - } - SkASSERT(cache->fNext == nullptr); - - get_globals().attachCacheToHead(cache); -} - - -void SkStrikeCache::attachCacheToHead(SkGlyphCache* cache) { - SkAutoExclusive ac(fLock); - - this->validate(); - cache->validate(); - - this->internalAttachCacheToHead(cache); - this->internalPurge(); -} - -SkGlyphCache* SkStrikeCache::internalGetTail() const { - SkGlyphCache* cache = fHead; - if (cache) { - while (cache->fNext) { - cache = cache->fNext; - } - } - return cache; -} - -size_t SkStrikeCache::internalPurge(size_t minBytesNeeded) { - this->validate(); - - size_t bytesNeeded = 0; - if (fTotalMemoryUsed > fCacheSizeLimit) { - bytesNeeded = fTotalMemoryUsed - fCacheSizeLimit; - } - bytesNeeded = SkTMax(bytesNeeded, minBytesNeeded); - if (bytesNeeded) { - // no small purges! - bytesNeeded = SkTMax(bytesNeeded, fTotalMemoryUsed >> 2); - } - - int countNeeded = 0; - if (fCacheCount > fCacheCountLimit) { - countNeeded = fCacheCount - fCacheCountLimit; - // no small purges! - countNeeded = SkMax32(countNeeded, fCacheCount >> 2); - } - - // early exit - if (!countNeeded && !bytesNeeded) { - return 0; - } - - size_t bytesFreed = 0; - int countFreed = 0; - - // we start at the tail and proceed backwards, as the linklist is in LRU - // order, with unimportant entries at the tail. - SkGlyphCache* cache = this->internalGetTail(); - while (cache != nullptr && - (bytesFreed < bytesNeeded || countFreed < countNeeded)) { - SkGlyphCache* prev = cache->fPrev; - bytesFreed += cache->fMemoryUsed; - countFreed += 1; - - this->internalDetachCache(cache); - delete cache; - cache = prev; - } - - this->validate(); - -#ifdef SPEW_PURGE_STATUS - if (countFreed) { - SkDebugf("purging %dK from font cache [%d entries]\n", - (int)(bytesFreed >> 10), countFreed); - } -#endif - - return bytesFreed; -} - -void SkStrikeCache::internalAttachCacheToHead(SkGlyphCache* cache) { - SkASSERT(nullptr == cache->fPrev && nullptr == cache->fNext); - if (fHead) { - fHead->fPrev = cache; - cache->fNext = fHead; - } - fHead = cache; - - fCacheCount += 1; - fTotalMemoryUsed += cache->fMemoryUsed; -} - -void SkStrikeCache::internalDetachCache(SkGlyphCache* cache) { - SkASSERT(fCacheCount > 0); - fCacheCount -= 1; - fTotalMemoryUsed -= cache->fMemoryUsed; - - if (cache->fPrev) { - cache->fPrev->fNext = cache->fNext; - } else { - fHead = cache->fNext; - } - if (cache->fNext) { - cache->fNext->fPrev = cache->fPrev; - } - cache->fPrev = cache->fNext = nullptr; -} - -/////////////////////////////////////////////////////////////////////////////// - #ifdef SK_DEBUG void SkGlyphCache::validate() const { @@ -790,45 +485,4 @@ void SkStrikeCache::validate() const { #endif -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -#include "SkTypefaceCache.h" - -size_t SkGraphics::GetFontCacheLimit() { - return get_globals().getCacheSizeLimit(); -} - -size_t SkGraphics::SetFontCacheLimit(size_t bytes) { - return get_globals().setCacheSizeLimit(bytes); -} - -size_t SkGraphics::GetFontCacheUsed() { - return get_globals().getTotalMemoryUsed(); -} - -int SkGraphics::GetFontCacheCountLimit() { - return get_globals().getCacheCountLimit(); -} - -int SkGraphics::SetFontCacheCountLimit(int count) { - return get_globals().setCacheCountLimit(count); -} - -int SkGraphics::GetFontCacheCountUsed() { - return get_globals().getCacheCountUsed(); -} - -int SkGraphics::GetFontCachePointSizeLimit() { - return get_globals().getCachePointSizeLimit(); -} - -int SkGraphics::SetFontCachePointSizeLimit(int limit) { - return get_globals().setCachePointSizeLimit(limit); -} - -void SkGraphics::PurgeFontCache() { - get_globals().purgeAll(); - SkTypefaceCache::PurgeAll(); -} diff --git a/src/core/SkGlyphCache.h b/src/core/SkGlyphCache.h index 3143656659..2896be58e0 100644 --- a/src/core/SkGlyphCache.h +++ b/src/core/SkGlyphCache.h @@ -19,10 +19,6 @@ class SkTraceMemoryDump; -class SkGlyphCache; -using SkExclusiveStrikePtr = std::unique_ptr< - SkGlyphCache, - SkFunctionWrapper<void, SkGlyphCache, SkStrikeCache::AttachCache>>; /** \class SkGlyphCache @@ -156,15 +152,6 @@ public: std::unique_ptr<SkScalerContext> scaler, SkPaint::FontMetrics* maybeMetrics = nullptr); - static void Dump(); - - /** Dump memory usage statistics of all the attaches caches in the process using the - SkTraceMemoryDump interface. - */ - static void DumpMemoryStatistics(SkTraceMemoryDump* dump); - - static void ForEachStrike(std::function<void(const SkGlyphCache&)> visitor); - #ifdef SK_DEBUG void validate() const; #else diff --git a/src/core/SkGraphics.cpp b/src/core/SkGraphics.cpp index 803b7435bb..f169092492 100644 --- a/src/core/SkGraphics.cpp +++ b/src/core/SkGraphics.cpp @@ -5,14 +5,12 @@ * found in the LICENSE file. */ - #include "SkGraphics.h" #include "SkBlitter.h" #include "SkCanvas.h" #include "SkCpu.h" #include "SkGeometry.h" -#include "SkGlyphCache.h" #include "SkImageFilter.h" #include "SkMath.h" #include "SkMatrix.h" @@ -25,6 +23,7 @@ #include "SkScalerContext.h" #include "SkShader.h" #include "SkStream.h" +#include "SkStrikeCache.h" #include "SkTSearch.h" #include "SkTime.h" #include "SkUtils.h" @@ -53,7 +52,7 @@ void SkGraphics::Init() { void SkGraphics::DumpMemoryStatistics(SkTraceMemoryDump* dump) { SkResourceCache::DumpMemoryStatistics(dump); - SkGlyphCache::DumpMemoryStatistics(dump); + SkStrikeCache::DumpMemoryStatistics(dump); } void SkGraphics::PurgeAllCaches() { diff --git a/src/core/SkStrikeCache.cpp b/src/core/SkStrikeCache.cpp new file mode 100644 index 0000000000..386be1ce9f --- /dev/null +++ b/src/core/SkStrikeCache.cpp @@ -0,0 +1,350 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkStrikeCache.h" + +#include <cctype> + +#include "SkDeduper.h" +#include "SkGlyphCache.h" +#include "SkGraphics.h" +#include "SkMutex.h" +#include "SkOnce.h" +#include "SkTraceMemoryDump.h" +#include "SkTypeface.h" +#include "SkTypefaceCache.h" + +// Returns the shared globals +static SkStrikeCache& get_globals() { + static SkOnce once; + static SkStrikeCache* globals; + + once([]{ globals = new SkStrikeCache; }); + return *globals; +} + +SkStrikeCache::~SkStrikeCache() { + SkGlyphCache* cache = fHead; + while (cache) { + SkGlyphCache* next = cache->fNext; + delete cache; + cache = next; + } +} + +void SkStrikeCache::AttachCache(SkGlyphCache* cache) { + get_globals().attachCache(cache); +} + +SkExclusiveStrikePtr SkStrikeCache::FindStrikeExclusive(const SkDescriptor& desc) { + return get_globals().findStrikeExclusive(desc); +} + +void SkStrikeCache::PurgeAll() { + get_globals().purgeAll(); +} + +void SkStrikeCache::Dump() { + SkDebugf("GlyphCache [ used budget ]\n"); + SkDebugf(" bytes [ %8zu %8zu ]\n", + SkGraphics::GetFontCacheUsed(), SkGraphics::GetFontCacheLimit()); + SkDebugf(" count [ %8zu %8zu ]\n", + SkGraphics::GetFontCacheCountUsed(), SkGraphics::GetFontCacheCountLimit()); + + int counter = 0; + + auto visitor = [&counter](const SkGlyphCache& cache) { + const SkScalerContextRec& rec = cache.getScalerContext()->getRec(); + + SkDebugf("index %d\n", counter); + SkDebugf("%s", rec.dump().c_str()); + counter += 1; + }; + + get_globals().forEachStrike(visitor); +} + +namespace { + const char gGlyphCacheDumpName[] = "skia/sk_glyph_cache"; +} // namespace + +void SkStrikeCache::DumpMemoryStatistics(SkTraceMemoryDump* dump) { + dump->dumpNumericValue(gGlyphCacheDumpName, "size", "bytes", SkGraphics::GetFontCacheUsed()); + dump->dumpNumericValue(gGlyphCacheDumpName, "budget_size", "bytes", + SkGraphics::GetFontCacheLimit()); + dump->dumpNumericValue(gGlyphCacheDumpName, "glyph_count", "objects", + SkGraphics::GetFontCacheCountUsed()); + dump->dumpNumericValue(gGlyphCacheDumpName, "budget_glyph_count", "objects", + SkGraphics::GetFontCacheCountLimit()); + + if (dump->getRequestedDetails() == SkTraceMemoryDump::kLight_LevelOfDetail) { + dump->setMemoryBacking(gGlyphCacheDumpName, "malloc", nullptr); + return; + } + + auto visitor = [&dump](const SkGlyphCache& cache) { + const SkTypeface* face = cache.getScalerContext()->getTypeface(); + const SkScalerContextRec& rec = cache.getScalerContext()->getRec(); + + SkString fontName; + face->getFamilyName(&fontName); + // Replace all special characters with '_'. + for (size_t index = 0; index < fontName.size(); ++index) { + if (!std::isalnum(fontName[index])) { + fontName[index] = '_'; + } + } + + SkString dumpName = SkStringPrintf( + "%s/%s_%d/%p", gGlyphCacheDumpName, fontName.c_str(), rec.fFontID, &cache); + + dump->dumpNumericValue(dumpName.c_str(), + "size", "bytes", cache.getMemoryUsed()); + dump->dumpNumericValue(dumpName.c_str(), + "glyph_count", "objects", cache.countCachedGlyphs()); + dump->setMemoryBacking(dumpName.c_str(), "malloc", nullptr); + }; + + get_globals().forEachStrike(visitor); +} + + +void SkStrikeCache::attachCache(SkGlyphCache *cache) { + if (cache == nullptr) { + return; + } + SkAutoExclusive ac(fLock); + + this->validate(); + cache->validate(); + + this->internalAttachCacheToHead(cache); + this->internalPurge(); +} + +SkExclusiveStrikePtr SkStrikeCache::findStrikeExclusive(const SkDescriptor& desc) { + SkGlyphCache* cache; + SkAutoExclusive ac(fLock); + + for (cache = internalGetHead(); cache != nullptr; cache = cache->fNext) { + if (*cache->fDesc == desc) { + this->internalDetachCache(cache); + return SkExclusiveStrikePtr(cache); + } + } + + return SkExclusiveStrikePtr(nullptr); +} + +void SkStrikeCache::purgeAll() { + SkAutoExclusive ac(fLock); + this->internalPurge(fTotalMemoryUsed); +} + +size_t SkStrikeCache::getTotalMemoryUsed() const { + SkAutoExclusive ac(fLock); + return fTotalMemoryUsed; +} + +int SkStrikeCache::getCacheCountUsed() const { + SkAutoExclusive ac(fLock); + return fCacheCount; +} + +int SkStrikeCache::getCacheCountLimit() const { + SkAutoExclusive ac(fLock); + return fCacheCountLimit; +} + +size_t SkStrikeCache::setCacheSizeLimit(size_t newLimit) { + static const size_t minLimit = 256 * 1024; + if (newLimit < minLimit) { + newLimit = minLimit; + } + + SkAutoExclusive ac(fLock); + + size_t prevLimit = fCacheSizeLimit; + fCacheSizeLimit = newLimit; + this->internalPurge(); + return prevLimit; +} + +size_t SkStrikeCache::getCacheSizeLimit() const { + SkAutoExclusive ac(fLock); + return fCacheSizeLimit; +} + +int SkStrikeCache::setCacheCountLimit(int newCount) { + if (newCount < 0) { + newCount = 0; + } + + SkAutoExclusive ac(fLock); + + int prevCount = fCacheCountLimit; + fCacheCountLimit = newCount; + this->internalPurge(); + return prevCount; +} + +int SkStrikeCache::getCachePointSizeLimit() const { + SkAutoExclusive ac(fLock); + return fPointSizeLimit; +} + +int SkStrikeCache::setCachePointSizeLimit(int newLimit) { + if (newLimit < 0) { + newLimit = 0; + } + + SkAutoExclusive ac(fLock); + + int prevLimit = fPointSizeLimit; + fPointSizeLimit = newLimit; + return prevLimit; +} + +void SkStrikeCache::forEachStrike(std::function<void(const SkGlyphCache&)> visitor) const { + SkAutoExclusive ac(fLock); + + this->validate(); + + for (SkGlyphCache* cache = this->internalGetHead(); cache != nullptr; cache = cache->fNext) { + visitor(*cache); + } +} + +SkGlyphCache* SkStrikeCache::internalGetTail() const { + SkGlyphCache* cache = fHead; + if (cache) { + while (cache->fNext) { + cache = cache->fNext; + } + } + return cache; +} + +size_t SkStrikeCache::internalPurge(size_t minBytesNeeded) { + this->validate(); + + size_t bytesNeeded = 0; + if (fTotalMemoryUsed > fCacheSizeLimit) { + bytesNeeded = fTotalMemoryUsed - fCacheSizeLimit; + } + bytesNeeded = SkTMax(bytesNeeded, minBytesNeeded); + if (bytesNeeded) { + // no small purges! + bytesNeeded = SkTMax(bytesNeeded, fTotalMemoryUsed >> 2); + } + + int countNeeded = 0; + if (fCacheCount > fCacheCountLimit) { + countNeeded = fCacheCount - fCacheCountLimit; + // no small purges! + countNeeded = SkMax32(countNeeded, fCacheCount >> 2); + } + + // early exit + if (!countNeeded && !bytesNeeded) { + return 0; + } + + size_t bytesFreed = 0; + int countFreed = 0; + + // we start at the tail and proceed backwards, as the linklist is in LRU + // order, with unimportant entries at the tail. + SkGlyphCache* cache = this->internalGetTail(); + while (cache != nullptr && + (bytesFreed < bytesNeeded || countFreed < countNeeded)) { + SkGlyphCache* prev = cache->fPrev; + bytesFreed += cache->fMemoryUsed; + countFreed += 1; + + this->internalDetachCache(cache); + delete cache; + cache = prev; + } + + this->validate(); + +#ifdef SPEW_PURGE_STATUS + if (countFreed) { + SkDebugf("purging %dK from font cache [%d entries]\n", + (int)(bytesFreed >> 10), countFreed); + } +#endif + + return bytesFreed; +} + +void SkStrikeCache::internalAttachCacheToHead(SkGlyphCache* cache) { + SkASSERT(nullptr == cache->fPrev && nullptr == cache->fNext); + if (fHead) { + fHead->fPrev = cache; + cache->fNext = fHead; + } + fHead = cache; + + fCacheCount += 1; + fTotalMemoryUsed += cache->fMemoryUsed; +} + +void SkStrikeCache::internalDetachCache(SkGlyphCache* cache) { + SkASSERT(fCacheCount > 0); + fCacheCount -= 1; + fTotalMemoryUsed -= cache->fMemoryUsed; + + if (cache->fPrev) { + cache->fPrev->fNext = cache->fNext; + } else { + fHead = cache->fNext; + } + if (cache->fNext) { + cache->fNext->fPrev = cache->fPrev; + } + cache->fPrev = cache->fNext = nullptr; +} + +size_t SkGraphics::GetFontCacheLimit() { + return get_globals().getCacheSizeLimit(); +} + +size_t SkGraphics::SetFontCacheLimit(size_t bytes) { + return get_globals().setCacheSizeLimit(bytes); +} + +size_t SkGraphics::GetFontCacheUsed() { + return get_globals().getTotalMemoryUsed(); +} + +int SkGraphics::GetFontCacheCountLimit() { + return get_globals().getCacheCountLimit(); +} + +int SkGraphics::SetFontCacheCountLimit(int count) { + return get_globals().setCacheCountLimit(count); +} + +int SkGraphics::GetFontCacheCountUsed() { + return get_globals().getCacheCountUsed(); +} + +int SkGraphics::GetFontCachePointSizeLimit() { + return get_globals().getCachePointSizeLimit(); +} + +int SkGraphics::SetFontCachePointSizeLimit(int limit) { + return get_globals().setCachePointSizeLimit(limit); +} + +void SkGraphics::PurgeFontCache() { + get_globals().purgeAll(); + SkTypefaceCache::PurgeAll(); +} + diff --git a/src/core/SkStrikeCache.h b/src/core/SkStrikeCache.h index 5efbdc9f01..eaf360b361 100644 --- a/src/core/SkStrikeCache.h +++ b/src/core/SkStrikeCache.h @@ -8,9 +8,12 @@ #ifndef SkStrikeCache_DEFINED #define SkStrikeCache_DEFINED +#include "SkDescriptor.h" #include "SkSpinlock.h" +#include "SkTemplates.h" class SkGlyphCache; +class SkTraceMemoryDump; #ifndef SK_DEFAULT_FONT_CACHE_COUNT_LIMIT #define SK_DEFAULT_FONT_CACHE_COUNT_LIMIT 2048 @@ -26,65 +29,76 @@ class SkGlyphCache; /////////////////////////////////////////////////////////////////////////////// +class SkGlyphCache; + class SkStrikeCache { public: - SkStrikeCache() { - fHead = nullptr; - fTotalMemoryUsed = 0; - fCacheSizeLimit = SK_DEFAULT_FONT_CACHE_LIMIT; - fCacheCount = 0; - fCacheCountLimit = SK_DEFAULT_FONT_CACHE_COUNT_LIMIT; - fPointSizeLimit = SK_DEFAULT_FONT_CACHE_POINT_SIZE_LIMIT; - } - + SkStrikeCache() = default; ~SkStrikeCache(); static void AttachCache(SkGlyphCache* cache); - mutable SkSpinlock fLock; + using ExclusiveStrikePtr = std::unique_ptr< + SkGlyphCache, + SkFunctionWrapper<void, SkGlyphCache, SkStrikeCache::AttachCache>>; - SkGlyphCache* internalGetHead() const { return fHead; } - SkGlyphCache* internalGetTail() const; + static ExclusiveStrikePtr FindStrikeExclusive(const SkDescriptor&); - size_t getTotalMemoryUsed() const; - int getCacheCountUsed() const; + static void PurgeAll(); -#ifdef SK_DEBUG - void validate() const; -#else - void validate() const {} -#endif + static void Dump(); + + // Dump memory usage statistics of all the attaches caches in the process using the + // SkTraceMemoryDump interface. + static void DumpMemoryStatistics(SkTraceMemoryDump* dump); + + // call when a glyphcache is available for caching (i.e. not in use) + void attachCache(SkGlyphCache *cache); + ExclusiveStrikePtr findStrikeExclusive(const SkDescriptor&); + + void purgeAll(); // does not change budget int getCacheCountLimit() const; int setCacheCountLimit(int limit); + int getCacheCountUsed() const; - size_t getCacheSizeLimit() const; - size_t setCacheSizeLimit(size_t limit); + size_t getCacheSizeLimit() const; + size_t setCacheSizeLimit(size_t limit); + size_t getTotalMemoryUsed() const; int getCachePointSizeLimit() const; int setCachePointSizeLimit(int limit); - void purgeAll(); // does not change budget - // call when a glyphcache is available for caching (i.e. not in use) - void attachCacheToHead(SkGlyphCache*); +#ifdef SK_DEBUG + void validate() const; +#else + void validate() const {} +#endif - // can only be called when the mutex is already held +private: + // The following methods can only be called when mutex is already held. + SkGlyphCache* internalGetHead() const { return fHead; } + SkGlyphCache* internalGetTail() const; void internalDetachCache(SkGlyphCache*); void internalAttachCacheToHead(SkGlyphCache*); -private: - SkGlyphCache* fHead; - size_t fTotalMemoryUsed; - size_t fCacheSizeLimit; - int32_t fCacheCountLimit; - int32_t fCacheCount; - int32_t fPointSizeLimit; - // Checkout budgets, modulated by the specified min-bytes-needed-to-purge, // and attempt to purge caches to match. // Returns number of bytes freed. size_t internalPurge(size_t minBytesNeeded = 0); + + void forEachStrike(std::function<void(const SkGlyphCache&)> visitor) const; + + mutable SkSpinlock fLock; + SkGlyphCache* fHead{nullptr}; + size_t fTotalMemoryUsed{0}; + size_t fCacheSizeLimit{SK_DEFAULT_FONT_CACHE_LIMIT}; + int32_t fCacheCountLimit{SK_DEFAULT_FONT_CACHE_COUNT_LIMIT}; + int32_t fCacheCount{0}; + int32_t fPointSizeLimit{SK_DEFAULT_FONT_CACHE_POINT_SIZE_LIMIT}; }; +using SkExclusiveStrikePtr = SkStrikeCache::ExclusiveStrikePtr; + #endif // SkStrikeCache_DEFINED |