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:
parent
c41569a29f
commit
671e7eea42
@ -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",
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
350
src/core/SkStrikeCache.cpp
Normal 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();
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user