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>
This commit is contained in:
Herbert Derby 2018-04-17 08:04:47 -04:00 committed by Skia Commit-Bot
parent c41569a29f
commit 671e7eea42
6 changed files with 407 additions and 402 deletions

View File

@ -294,6 +294,7 @@ skia_core_sources = [
"$_src/core/SkSpriteBlitter.h", "$_src/core/SkSpriteBlitter.h",
"$_src/core/SkStream.cpp", "$_src/core/SkStream.cpp",
"$_src/core/SkStreamPriv.h", "$_src/core/SkStreamPriv.h",
"$_src/core/SkStrikeCache.cpp",
"$_src/core/SkStrikeCache.h", "$_src/core/SkStrikeCache.h",
"$_src/core/SkString.cpp", "$_src/core/SkString.cpp",
"$_src/core/SkStringUtils.cpp", "$_src/core/SkStringUtils.cpp",

View File

@ -5,7 +5,6 @@
* found in the LICENSE file. * found in the LICENSE file.
*/ */
#include "SkGlyphCache.h" #include "SkGlyphCache.h"
#include "SkGraphics.h" #include "SkGraphics.h"
#include "SkMutex.h" #include "SkMutex.h"
@ -13,27 +12,9 @@
#include "SkPaintPriv.h" #include "SkPaintPriv.h"
#include "SkPath.h" #include "SkPath.h"
#include "SkTemplates.h" #include "SkTemplates.h"
#include "SkTraceMemoryDump.h"
#include "SkTypeface.h" #include "SkTypeface.h"
#include <cctype> #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( SkGlyphCache::SkGlyphCache(
const SkDescriptor& desc, const SkDescriptor& desc,
std::unique_ptr<SkScalerContext> scaler, std::unique_ptr<SkScalerContext> scaler,
@ -62,8 +43,6 @@ SkGlyphCache::CharGlyphRec* SkGlyphCache::getCharGlyphRec(SkPackedUnicharID pack
return &fPackedUnicharIDToPackedGlyphID[packedUnicharID.hash() & kHashMask]; return &fPackedUnicharIDToPackedGlyphID[packedUnicharID.hash() & kHashMask];
} }
///////////////////////////////////////////////////////////////////////////////
#ifdef SK_DEBUG #ifdef SK_DEBUG
#define VALIDATE() AutoValidate av(this) #define VALIDATE() AutoValidate av(this)
#else #else
@ -99,8 +78,6 @@ int SkGlyphCache::countCachedGlyphs() const {
return fGlyphMap.count(); return fGlyphMap.count();
} }
///////////////////////////////////////////////////////////////////////////////
bool SkGlyphCache::isGlyphCached(SkGlyphID glyphID, SkFixed x, SkFixed y) const { bool SkGlyphCache::isGlyphCached(SkGlyphID glyphID, SkFixed x, SkFixed y) const {
SkPackedGlyphID packedGlyphID{glyphID, x, y}; SkPackedGlyphID packedGlyphID{glyphID, x, y};
return fGlyphMap.find(packedGlyphID) != nullptr; return fGlyphMap.find(packedGlyphID) != nullptr;
@ -121,8 +98,6 @@ const SkGlyph& SkGlyphCache::getGlyphIDAdvance(uint16_t glyphID) {
return *this->lookupByPackedGlyphID(packedGlyphID, kJustAdvance_MetricsType); return *this->lookupByPackedGlyphID(packedGlyphID, kJustAdvance_MetricsType);
} }
///////////////////////////////////////////////////////////////////////////////
const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode) { const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode) {
VALIDATE(); VALIDATE();
return *this->lookupByChar(charCode, kFull_MetricsType); return *this->lookupByChar(charCode, kFull_MetricsType);
@ -412,91 +387,8 @@ void SkGlyphCache::dump() const {
SkDebugf("%s\n", msg.c_str()); 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) { SkExclusiveStrikePtr SkGlyphCache::FindStrikeExclusive(const SkDescriptor& desc) {
SkStrikeCache& globals = get_globals(); return SkStrikeCache::FindStrikeExclusive(desc);
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);
} }
std::unique_ptr<SkScalerContext> SkGlyphCache::CreateScalerContext( std::unique_ptr<SkScalerContext> SkGlyphCache::CreateScalerContext(
@ -510,15 +402,15 @@ std::unique_ptr<SkScalerContext> SkGlyphCache::CreateScalerContext(
// cache once and try again // cache once and try again
// pass true the first time, to notice if the scalercontext failed, // pass true the first time, to notice if the scalercontext failed,
if (scaler == nullptr) { if (scaler == nullptr) {
get_globals().purgeAll(); SkStrikeCache::PurgeAll();
scaler = typeface.createScalerContext(effects, &desc, false /* must succeed */); scaler = typeface.createScalerContext(effects, &desc, false /* must succeed */);
} }
return scaler; return scaler;
} }
SkExclusiveStrikePtr SkGlyphCache::FindOrCreateStrikeExclusive( 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); auto cache = SkGlyphCache::FindStrikeExclusive(desc);
if (cache == nullptr) { if (cache == nullptr) {
auto scaler = CreateScalerContext(desc, effects, typeface); auto scaler = CreateScalerContext(desc, effects, typeface);
@ -559,203 +451,6 @@ SkExclusiveStrikePtr SkGlyphCache::CreateStrikeExclusive(
return SkExclusiveStrikePtr(new SkGlyphCache(desc, std::move(scaler), fontMetrics)); 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 #ifdef SK_DEBUG
void SkGlyphCache::validate() const { void SkGlyphCache::validate() const {
@ -790,45 +485,4 @@ void SkStrikeCache::validate() const {
#endif #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();
}

View File

@ -19,10 +19,6 @@
class SkTraceMemoryDump; class SkTraceMemoryDump;
class SkGlyphCache;
using SkExclusiveStrikePtr = std::unique_ptr<
SkGlyphCache,
SkFunctionWrapper<void, SkGlyphCache, SkStrikeCache::AttachCache>>;
/** \class SkGlyphCache /** \class SkGlyphCache
@ -156,15 +152,6 @@ public:
std::unique_ptr<SkScalerContext> scaler, std::unique_ptr<SkScalerContext> scaler,
SkPaint::FontMetrics* maybeMetrics = nullptr); 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 #ifdef SK_DEBUG
void validate() const; void validate() const;
#else #else

View File

@ -5,14 +5,12 @@
* found in the LICENSE file. * found in the LICENSE file.
*/ */
#include "SkGraphics.h" #include "SkGraphics.h"
#include "SkBlitter.h" #include "SkBlitter.h"
#include "SkCanvas.h" #include "SkCanvas.h"
#include "SkCpu.h" #include "SkCpu.h"
#include "SkGeometry.h" #include "SkGeometry.h"
#include "SkGlyphCache.h"
#include "SkImageFilter.h" #include "SkImageFilter.h"
#include "SkMath.h" #include "SkMath.h"
#include "SkMatrix.h" #include "SkMatrix.h"
@ -25,6 +23,7 @@
#include "SkScalerContext.h" #include "SkScalerContext.h"
#include "SkShader.h" #include "SkShader.h"
#include "SkStream.h" #include "SkStream.h"
#include "SkStrikeCache.h"
#include "SkTSearch.h" #include "SkTSearch.h"
#include "SkTime.h" #include "SkTime.h"
#include "SkUtils.h" #include "SkUtils.h"
@ -53,7 +52,7 @@ void SkGraphics::Init() {
void SkGraphics::DumpMemoryStatistics(SkTraceMemoryDump* dump) { void SkGraphics::DumpMemoryStatistics(SkTraceMemoryDump* dump) {
SkResourceCache::DumpMemoryStatistics(dump); SkResourceCache::DumpMemoryStatistics(dump);
SkGlyphCache::DumpMemoryStatistics(dump); SkStrikeCache::DumpMemoryStatistics(dump);
} }
void SkGraphics::PurgeAllCaches() { void SkGraphics::PurgeAllCaches() {

350
src/core/SkStrikeCache.cpp Normal file
View File

@ -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();
}

View File

@ -8,9 +8,12 @@
#ifndef SkStrikeCache_DEFINED #ifndef SkStrikeCache_DEFINED
#define SkStrikeCache_DEFINED #define SkStrikeCache_DEFINED
#include "SkDescriptor.h"
#include "SkSpinlock.h" #include "SkSpinlock.h"
#include "SkTemplates.h"
class SkGlyphCache; class SkGlyphCache;
class SkTraceMemoryDump;
#ifndef SK_DEFAULT_FONT_CACHE_COUNT_LIMIT #ifndef SK_DEFAULT_FONT_CACHE_COUNT_LIMIT
#define SK_DEFAULT_FONT_CACHE_COUNT_LIMIT 2048 #define SK_DEFAULT_FONT_CACHE_COUNT_LIMIT 2048
@ -26,65 +29,76 @@ class SkGlyphCache;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
class SkGlyphCache;
class SkStrikeCache { class SkStrikeCache {
public: public:
SkStrikeCache() { SkStrikeCache() = default;
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(); ~SkStrikeCache();
static void AttachCache(SkGlyphCache* cache); static void AttachCache(SkGlyphCache* cache);
mutable SkSpinlock fLock; using ExclusiveStrikePtr = std::unique_ptr<
SkGlyphCache,
SkFunctionWrapper<void, SkGlyphCache, SkStrikeCache::AttachCache>>;
SkGlyphCache* internalGetHead() const { return fHead; } static ExclusiveStrikePtr FindStrikeExclusive(const SkDescriptor&);
SkGlyphCache* internalGetTail() const;
size_t getTotalMemoryUsed() const; static void PurgeAll();
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; int getCacheCountUsed() const;
size_t getCacheSizeLimit() const;
size_t setCacheSizeLimit(size_t limit);
size_t getTotalMemoryUsed() const;
int getCachePointSizeLimit() const;
int setCachePointSizeLimit(int limit);
#ifdef SK_DEBUG #ifdef SK_DEBUG
void validate() const; void validate() const;
#else #else
void validate() const {} void validate() const {}
#endif #endif
int getCacheCountLimit() const; private:
int setCacheCountLimit(int limit); // The following methods can only be called when mutex is already held.
SkGlyphCache* internalGetHead() const { return fHead; }
size_t getCacheSizeLimit() const; SkGlyphCache* internalGetTail() const;
size_t setCacheSizeLimit(size_t limit);
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*);
// can only be called when the mutex is already held
void internalDetachCache(SkGlyphCache*); void internalDetachCache(SkGlyphCache*);
void internalAttachCacheToHead(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, // Checkout budgets, modulated by the specified min-bytes-needed-to-purge,
// and attempt to purge caches to match. // and attempt to purge caches to match.
// Returns number of bytes freed. // Returns number of bytes freed.
size_t internalPurge(size_t minBytesNeeded = 0); 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 #endif // SkStrikeCache_DEFINED