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/SkStream.cpp",
"$_src/core/SkStreamPriv.h",
"$_src/core/SkStrikeCache.cpp",
"$_src/core/SkStrikeCache.h",
"$_src/core/SkString.cpp",
"$_src/core/SkStringUtils.cpp",

View File

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

View File

@ -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

View File

@ -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() {

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
#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;
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;
size_t getCacheSizeLimit() const;
size_t setCacheSizeLimit(size_t limit);
size_t getTotalMemoryUsed() const;
int getCachePointSizeLimit() const;
int setCachePointSizeLimit(int limit);
#ifdef SK_DEBUG
void validate() const;
#else
void validate() const {}
#endif
int getCacheCountLimit() const;
int setCacheCountLimit(int limit);
size_t getCacheSizeLimit() 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
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