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/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",
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
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
|
#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
|
||||||
|
Loading…
Reference in New Issue
Block a user