41 sk_sp<SkStrike> strike = this->internalFindStrikeOrNull(strikeSpec.descriptor());
42 if (strike ==
nullptr) {
43 strike = this->internalCreateStrike(strikeSpec);
45 this->internalPurge();
58 SkDebugf(
"GlyphCache [ used budget ]\n");
64 auto visitor = [](
const SkStrike& strike) {
73 dump->dumpNumericValue(kGlyphCacheDumpName,
"budget_size",
"bytes",
75 dump->dumpNumericValue(kGlyphCacheDumpName,
"glyph_count",
"objects",
77 dump->dumpNumericValue(kGlyphCacheDumpName,
"budget_glyph_count",
"objects",
81 dump->setMemoryBacking(kGlyphCacheDumpName,
"malloc",
nullptr);
85 auto visitor = [&](
const SkStrike& strike) {
86 strike.dumpMemoryStatistics(
dump);
95 this->internalPurge();
102 if (fHead !=
nullptr && fHead->getDescriptor() == desc) {
return sk_ref_sp(fHead); }
106 if (strikeHandle ==
nullptr) {
return nullptr; }
109 if (fHead != strikePtr) {
111 strikePtr->fPrev->fNext = strikePtr->fNext;
112 if (strikePtr->fNext !=
nullptr) {
113 strikePtr->fNext->fPrev = strikePtr->fPrev;
115 fTail = strikePtr->fPrev;
117 fHead->fPrev = strikePtr;
118 strikePtr->fNext = fHead;
119 strikePtr->fPrev =
nullptr;
128 std::unique_ptr<SkStrikePinner> pinner) {
130 return this->internalCreateStrike(strikeSpec, maybeMetrics, std::move(pinner));
133auto SkStrikeCache::internalCreateStrike(
137 std::unique_ptr<SkScalerContext> scaler = strikeSpec.createScalerContext();
139 sk_make_sp<SkStrike>(
this, strikeSpec, std::move(scaler), maybeMetrics, std::move(pinner));
140 this->internalAttachToHead(strike);
146 this->internalPurge(minBytesNeeded,
true);
151 this->internalPurge(fTotalMemoryUsed,
true);
156 return fTotalMemoryUsed;
166 return fCacheCountLimit;
172 size_t prevLimit = fCacheSizeLimit;
173 fCacheSizeLimit = newLimit;
174 this->internalPurge();
180 return fCacheSizeLimit;
190 int prevCount = fCacheCountLimit;
191 fCacheCountLimit = newCount;
192 this->internalPurge();
196void SkStrikeCache::forEachStrike(std::function<
void(
const SkStrike&)> visitor)
const {
201 for (
SkStrike* strike = fHead; strike !=
nullptr; strike = strike->fNext) {
206size_t SkStrikeCache::internalPurge(
size_t minBytesNeeded,
bool checkPinners) {
207#ifndef SK_STRIKE_CACHE_DOESNT_AUTO_CHECK_PINNERS
212 if (fPinnerCount == fCacheCount && !checkPinners)
215 size_t bytesNeeded = 0;
216 if (fTotalMemoryUsed > fCacheSizeLimit) {
217 bytesNeeded = fTotalMemoryUsed - fCacheSizeLimit;
219 bytesNeeded = std::max(bytesNeeded, minBytesNeeded);
222 bytesNeeded = std::max(bytesNeeded, fTotalMemoryUsed >> 2);
226 if (fCacheCount > fCacheCountLimit) {
227 countNeeded = fCacheCount - fCacheCountLimit;
229 countNeeded = std::max(countNeeded, fCacheCount >> 2);
233 if (!countNeeded && !bytesNeeded) {
237 size_t bytesFreed = 0;
243 while (strike !=
nullptr && (bytesFreed < bytesNeeded || countFreed < countNeeded)) {
247 if (strike->fPinner ==
nullptr || (checkPinners && strike->fPinner->canDelete())) {
248 bytesFreed += strike->fMemoryUsed;
250 this->internalRemoveStrike(strike);
257#ifdef SPEW_PURGE_STATUS
259 SkDebugf(
"purging %dK from font cache [%d entries]\n",
260 (
int)(bytesFreed >> 10), countFreed);
268 SkASSERT(fStrikeLookup.find(strike->getDescriptor()) ==
nullptr);
270 fStrikeLookup.set(std::move(strike));
271 SkASSERT(
nullptr == strikePtr->fPrev &&
nullptr == strikePtr->fNext);
274 fPinnerCount += strikePtr->fPinner !=
nullptr ? 1 : 0;
275 fTotalMemoryUsed += strikePtr->fMemoryUsed;
277 if (fHead !=
nullptr) {
278 fHead->fPrev = strikePtr;
279 strikePtr->fNext = fHead;
282 if (fTail ==
nullptr) {
289void SkStrikeCache::internalRemoveStrike(
SkStrike* strike) {
292 fPinnerCount -= strike->fPinner !=
nullptr ? 1 : 0;
293 fTotalMemoryUsed -= strike->fMemoryUsed;
296 strike->fPrev->fNext = strike->fNext;
298 fHead = strike->fNext;
301 strike->fNext->fPrev = strike->fPrev;
303 fTail = strike->fPrev;
306 strike->fPrev = strike->fNext =
nullptr;
307 strike->fRemoved =
true;
311void SkStrikeCache::validate()
const {
313 size_t computedBytes = 0;
314 int computedCount = 0;
317 while (strike !=
nullptr) {
318 computedBytes += strike->fMemoryUsed;
321 strike = strike->fNext;
324 if (fCacheCount != computedCount) {
325 SkDebugf(
"fCacheCount: %d, computedCount: %d", fCacheCount, computedCount);
326 SK_ABORT(
"fCacheCount != computedCount");
328 if (fTotalMemoryUsed != computedBytes) {
329 SkDebugf(
"fTotalMemoryUsed: %zu, computedBytes: %zu", fTotalMemoryUsed, computedBytes);
330 SK_ABORT(
"fTotalMemoryUsed == computedBytes");
336 return strike->getDescriptor();
339uint32_t SkStrikeCache::StrikeTraits::Hash(
const SkDescriptor& descriptor) {
static float prev(float f)
#define SK_ABORT(message,...)
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
sk_sp< T > sk_ref_sp(T *obj)
bool gSkUseThreadLocalStrikeCaches_IAcknowledgeThisIsIncrediblyExperimental
static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv)
uint32_t getChecksum() const
static int GetFontCacheCountLimit()
static size_t GetFontCacheLimit()
static int GetFontCacheCountUsed()
static size_t GetFontCacheUsed()
static void DumpMemoryStatistics(SkTraceMemoryDump *dump)
size_t getCacheSizeLimit() const SK_EXCLUDES(fLock)
size_t setCacheSizeLimit(size_t limit) SK_EXCLUDES(fLock)
int setCacheCountLimit(int limit) SK_EXCLUDES(fLock)
sk_sp< SkStrike > createStrike(const SkStrikeSpec &strikeSpec, SkFontMetrics *maybeMetrics=nullptr, std::unique_ptr< SkStrikePinner >=nullptr) SK_EXCLUDES(fLock)
sk_sp< SkStrike > findOrCreateStrike(const SkStrikeSpec &strikeSpec) SK_EXCLUDES(fLock)
sk_sp< SkStrike > findStrike(const SkDescriptor &desc) SK_EXCLUDES(fLock)
void purgePinned(size_t minBytesNeeded=0) SK_EXCLUDES(fLock)
void purgeAll() SK_EXCLUDES(fLock)
sk_sp< sktext::StrikeForGPU > findOrCreateScopedStrike(const SkStrikeSpec &strikeSpec) override SK_EXCLUDES(fLock)
int getCacheCountLimit() const SK_EXCLUDES(fLock)
size_t getTotalMemoryUsed() const SK_EXCLUDES(fLock)
int getCacheCountUsed() const SK_EXCLUDES(fLock)
static SkStrikeCache * GlobalStrikeCache()
const SkDescriptor & getDescriptor() const override