aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gn/core.gni1
-rw-r--r--src/core/SkGlyphCache.cpp354
-rw-r--r--src/core/SkGlyphCache.h13
-rw-r--r--src/core/SkGraphics.cpp5
-rw-r--r--src/core/SkStrikeCache.cpp350
-rw-r--r--src/core/SkStrikeCache.h80
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