blob: c8cc0ad317f17eb97dd6259fa3a3f57cfa5cb7d0 [file] [log] [blame]
Herbert Derby671e7ee2018-04-17 08:04:47 -04001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/core/SkStrikeCache.h"
Herbert Derby671e7ee2018-04-17 08:04:47 -04009
10#include <cctype>
11
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkGraphics.h"
Herb Derby9102c862020-02-12 15:19:19 -050013#include "include/core/SkRefCnt.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "include/core/SkTraceMemoryDump.h"
15#include "include/core/SkTypeface.h"
16#include "include/private/SkMutex.h"
17#include "include/private/SkTemplates.h"
18#include "src/core/SkGlyphRunPainter.h"
Herb Derby81e84a62020-02-14 11:47:35 -050019#include "src/core/SkScalerCache.h"
Herb Derbydce19a72018-04-18 16:02:17 -040020
Mike Klein1585d7e2019-09-25 10:17:00 -050021bool gSkUseThreadLocalStrikeCaches_IAcknowledgeThisIsIncrediblyExperimental = false;
22
Herb Derbydcdabf32018-11-13 12:26:10 -050023SkStrikeCache* SkStrikeCache::GlobalStrikeCache() {
Mike Klein1585d7e2019-09-25 10:17:00 -050024 if (gSkUseThreadLocalStrikeCaches_IAcknowledgeThisIsIncrediblyExperimental) {
25 static thread_local auto* cache = new SkStrikeCache;
26 return cache;
27 }
Herb Derbydcdabf32018-11-13 12:26:10 -050028 static auto* cache = new SkStrikeCache;
29 return cache;
30}
31
Herb Derbydcdabf32018-11-13 12:26:10 -050032auto SkStrikeCache::findOrCreateStrike(const SkDescriptor& desc,
33 const SkScalerContextEffects& effects,
Herb Derbybcd65f12020-02-19 15:52:30 -050034 const SkTypeface& typeface) -> sk_sp<Strike> {
Herb Derby4ce81892021-05-11 16:14:14 -040035 SkAutoMutexExclusive ac(fLock);
Herb Derbybcd65f12020-02-19 15:52:30 -050036 sk_sp<Strike> strike = this->internalFindStrikeOrNull(desc);
Herb Derby81e84a62020-02-14 11:47:35 -050037 if (strike == nullptr) {
herb660317f2020-02-10 18:54:34 -050038 auto scaler = typeface.createScalerContext(effects, &desc);
Herb Derbybcd65f12020-02-19 15:52:30 -050039 strike = this->internalCreateStrike(desc, std::move(scaler));
Herb Derbye68c4fb2018-04-19 13:12:07 -040040 }
Herb Derby3b946c12020-03-15 12:55:16 -040041 this->internalPurge();
Herb Derby81e84a62020-02-14 11:47:35 -050042 return strike;
Herb Derbye68c4fb2018-04-19 13:12:07 -040043}
44
Herb Derby53eb1ec2019-09-25 13:34:19 -040045SkScopedStrikeForGPU SkStrikeCache::findOrCreateScopedStrike(const SkDescriptor& desc,
46 const SkScalerContextEffects& effects,
47 const SkTypeface& typeface) {
Herb Derbybcd65f12020-02-19 15:52:30 -050048 return SkScopedStrikeForGPU{this->findOrCreateStrike(desc, effects, typeface).release()};
Herb Derby49253642019-02-11 14:20:31 -050049}
50
Herbert Derby671e7ee2018-04-17 08:04:47 -040051void SkStrikeCache::PurgeAll() {
Herb Derbyae167ed2018-06-21 11:36:44 -040052 GlobalStrikeCache()->purgeAll();
Herbert Derby671e7ee2018-04-17 08:04:47 -040053}
54
55void SkStrikeCache::Dump() {
56 SkDebugf("GlyphCache [ used budget ]\n");
57 SkDebugf(" bytes [ %8zu %8zu ]\n",
58 SkGraphics::GetFontCacheUsed(), SkGraphics::GetFontCacheLimit());
John Stiles7bf79992021-06-25 11:05:20 -040059 SkDebugf(" count [ %8d %8d ]\n",
Herbert Derby671e7ee2018-04-17 08:04:47 -040060 SkGraphics::GetFontCacheCountUsed(), SkGraphics::GetFontCacheCountLimit());
61
62 int counter = 0;
63
Herb Derby81e84a62020-02-14 11:47:35 -050064 auto visitor = [&counter](const Strike& strike) {
65 const SkScalerContextRec& rec = strike.fScalerCache.getScalerContext()->getRec();
Herbert Derby671e7ee2018-04-17 08:04:47 -040066
67 SkDebugf("index %d\n", counter);
68 SkDebugf("%s", rec.dump().c_str());
69 counter += 1;
70 };
71
Herb Derbyae167ed2018-06-21 11:36:44 -040072 GlobalStrikeCache()->forEachStrike(visitor);
Herbert Derby671e7ee2018-04-17 08:04:47 -040073}
74
75namespace {
76 const char gGlyphCacheDumpName[] = "skia/sk_glyph_cache";
77} // namespace
78
79void SkStrikeCache::DumpMemoryStatistics(SkTraceMemoryDump* dump) {
80 dump->dumpNumericValue(gGlyphCacheDumpName, "size", "bytes", SkGraphics::GetFontCacheUsed());
81 dump->dumpNumericValue(gGlyphCacheDumpName, "budget_size", "bytes",
82 SkGraphics::GetFontCacheLimit());
83 dump->dumpNumericValue(gGlyphCacheDumpName, "glyph_count", "objects",
84 SkGraphics::GetFontCacheCountUsed());
85 dump->dumpNumericValue(gGlyphCacheDumpName, "budget_glyph_count", "objects",
86 SkGraphics::GetFontCacheCountLimit());
87
88 if (dump->getRequestedDetails() == SkTraceMemoryDump::kLight_LevelOfDetail) {
89 dump->setMemoryBacking(gGlyphCacheDumpName, "malloc", nullptr);
90 return;
91 }
92
Herb Derby81e84a62020-02-14 11:47:35 -050093 auto visitor = [&dump](const Strike& strike) {
94 const SkTypeface* face = strike.fScalerCache.getScalerContext()->getTypeface();
95 const SkScalerContextRec& rec = strike.fScalerCache.getScalerContext()->getRec();
Herbert Derby671e7ee2018-04-17 08:04:47 -040096
97 SkString fontName;
98 face->getFamilyName(&fontName);
99 // Replace all special characters with '_'.
100 for (size_t index = 0; index < fontName.size(); ++index) {
101 if (!std::isalnum(fontName[index])) {
102 fontName[index] = '_';
103 }
104 }
105
106 SkString dumpName = SkStringPrintf(
Herb Derby81e84a62020-02-14 11:47:35 -0500107 "%s/%s_%d/%p", gGlyphCacheDumpName, fontName.c_str(), rec.fFontID, &strike);
Herbert Derby671e7ee2018-04-17 08:04:47 -0400108
109 dump->dumpNumericValue(dumpName.c_str(),
Herb Derby9baef352020-02-19 14:13:27 -0500110 "size", "bytes", strike.fMemoryUsed);
Herbert Derby671e7ee2018-04-17 08:04:47 -0400111 dump->dumpNumericValue(dumpName.c_str(),
Herb Derby81e84a62020-02-14 11:47:35 -0500112 "glyph_count", "objects",
113 strike.fScalerCache.countCachedGlyphs());
Herbert Derby671e7ee2018-04-17 08:04:47 -0400114 dump->setMemoryBacking(dumpName.c_str(), "malloc", nullptr);
115 };
116
Herb Derbyae167ed2018-06-21 11:36:44 -0400117 GlobalStrikeCache()->forEachStrike(visitor);
Herbert Derby671e7ee2018-04-17 08:04:47 -0400118}
119
Herb Derbya64f5b22020-02-24 14:35:51 -0500120sk_sp<SkStrike> SkStrikeCache::findStrike(const SkDescriptor& desc) {
Herb Derby4ce81892021-05-11 16:14:14 -0400121 SkAutoMutexExclusive ac(fLock);
Herb Derby3b946c12020-03-15 12:55:16 -0400122 sk_sp<SkStrike> result = this->internalFindStrikeOrNull(desc);
123 this->internalPurge();
124 return result;
Herb Derby5e5e8482020-02-20 18:29:54 +0000125}
126
Herb Derbybcd65f12020-02-19 15:52:30 -0500127auto SkStrikeCache::internalFindStrikeOrNull(const SkDescriptor& desc) -> sk_sp<Strike> {
Herb Derby73ae40a2020-03-01 17:36:17 -0600128
129 // Check head because it is likely the strike we are looking for.
130 if (fHead != nullptr && fHead->getDescriptor() == desc) { return sk_ref_sp(fHead); }
131
132 // Do the heavy search looking for the strike.
Herb Derby659cc1c2020-02-21 16:49:37 -0500133 sk_sp<Strike>* strikeHandle = fStrikeLookup.find(desc);
134 if (strikeHandle == nullptr) { return nullptr; }
135 Strike* strikePtr = strikeHandle->get();
136 SkASSERT(strikePtr != nullptr);
137 if (fHead != strikePtr) {
Herb Derby6cc2d9f2020-02-20 13:31:27 -0500138 // Make most recently used
Herb Derby659cc1c2020-02-21 16:49:37 -0500139 strikePtr->fPrev->fNext = strikePtr->fNext;
140 if (strikePtr->fNext != nullptr) {
141 strikePtr->fNext->fPrev = strikePtr->fPrev;
Herb Derby6cc2d9f2020-02-20 13:31:27 -0500142 } else {
Herb Derby659cc1c2020-02-21 16:49:37 -0500143 fTail = strikePtr->fPrev;
Herbert Derby671e7ee2018-04-17 08:04:47 -0400144 }
Herb Derby659cc1c2020-02-21 16:49:37 -0500145 fHead->fPrev = strikePtr;
146 strikePtr->fNext = fHead;
147 strikePtr->fPrev = nullptr;
148 fHead = strikePtr;
Herbert Derby671e7ee2018-04-17 08:04:47 -0400149 }
Herb Derby659cc1c2020-02-21 16:49:37 -0500150 return sk_ref_sp(strikePtr);
Herbert Derby671e7ee2018-04-17 08:04:47 -0400151}
152
Herb Derbya64f5b22020-02-24 14:35:51 -0500153sk_sp<SkStrike> SkStrikeCache::createStrike(
Herb Derby71cca672018-06-21 11:53:44 -0400154 const SkDescriptor& desc,
155 std::unique_ptr<SkScalerContext> scaler,
Mike Reedb5784ac2018-11-12 09:35:15 -0500156 SkFontMetrics* maybeMetrics,
Herb Derbya64f5b22020-02-24 14:35:51 -0500157 std::unique_ptr<SkStrikePinner> pinner) {
Herb Derby4ce81892021-05-11 16:14:14 -0400158 SkAutoMutexExclusive ac(fLock);
Herb Derbya64f5b22020-02-24 14:35:51 -0500159 return this->internalCreateStrike(desc, std::move(scaler), maybeMetrics, std::move(pinner));
Herb Derbydcdabf32018-11-13 12:26:10 -0500160}
161
Herb Derbybcd65f12020-02-19 15:52:30 -0500162auto SkStrikeCache::internalCreateStrike(
Herb Derbydcdabf32018-11-13 12:26:10 -0500163 const SkDescriptor& desc,
164 std::unique_ptr<SkScalerContext> scaler,
165 SkFontMetrics* maybeMetrics,
Herb Derbybcd65f12020-02-19 15:52:30 -0500166 std::unique_ptr<SkStrikePinner> pinner) -> sk_sp<Strike> {
167 auto strike =
168 sk_make_sp<Strike>(this, desc, std::move(scaler), maybeMetrics, std::move(pinner));
169 this->internalAttachToHead(strike);
170 return strike;
Herb Derbye68c4fb2018-04-19 13:12:07 -0400171}
172
Herbert Derby671e7ee2018-04-17 08:04:47 -0400173void SkStrikeCache::purgeAll() {
Herb Derby4ce81892021-05-11 16:14:14 -0400174 SkAutoMutexExclusive ac(fLock);
Herbert Derby671e7ee2018-04-17 08:04:47 -0400175 this->internalPurge(fTotalMemoryUsed);
176}
177
178size_t SkStrikeCache::getTotalMemoryUsed() const {
Herb Derby4ce81892021-05-11 16:14:14 -0400179 SkAutoMutexExclusive ac(fLock);
Herbert Derby671e7ee2018-04-17 08:04:47 -0400180 return fTotalMemoryUsed;
181}
182
183int SkStrikeCache::getCacheCountUsed() const {
Herb Derby4ce81892021-05-11 16:14:14 -0400184 SkAutoMutexExclusive ac(fLock);
Herbert Derby671e7ee2018-04-17 08:04:47 -0400185 return fCacheCount;
186}
187
188int SkStrikeCache::getCacheCountLimit() const {
Herb Derby4ce81892021-05-11 16:14:14 -0400189 SkAutoMutexExclusive ac(fLock);
Herbert Derby671e7ee2018-04-17 08:04:47 -0400190 return fCacheCountLimit;
191}
192
193size_t SkStrikeCache::setCacheSizeLimit(size_t newLimit) {
Herb Derby4ce81892021-05-11 16:14:14 -0400194 SkAutoMutexExclusive ac(fLock);
Herbert Derby671e7ee2018-04-17 08:04:47 -0400195
196 size_t prevLimit = fCacheSizeLimit;
197 fCacheSizeLimit = newLimit;
198 this->internalPurge();
199 return prevLimit;
200}
201
202size_t SkStrikeCache::getCacheSizeLimit() const {
Herb Derby4ce81892021-05-11 16:14:14 -0400203 SkAutoMutexExclusive ac(fLock);
Herbert Derby671e7ee2018-04-17 08:04:47 -0400204 return fCacheSizeLimit;
205}
206
207int SkStrikeCache::setCacheCountLimit(int newCount) {
208 if (newCount < 0) {
209 newCount = 0;
210 }
211
Herb Derby4ce81892021-05-11 16:14:14 -0400212 SkAutoMutexExclusive ac(fLock);
Herbert Derby671e7ee2018-04-17 08:04:47 -0400213
214 int prevCount = fCacheCountLimit;
215 fCacheCountLimit = newCount;
216 this->internalPurge();
217 return prevCount;
218}
219
Herb Derby81e84a62020-02-14 11:47:35 -0500220void SkStrikeCache::forEachStrike(std::function<void(const Strike&)> visitor) const {
Herb Derby4ce81892021-05-11 16:14:14 -0400221 SkAutoMutexExclusive ac(fLock);
Herbert Derby671e7ee2018-04-17 08:04:47 -0400222
Herb Derby960d4212018-06-21 12:44:26 +0000223 this->validate();
224
Herb Derby81e84a62020-02-14 11:47:35 -0500225 for (Strike* strike = fHead; strike != nullptr; strike = strike->fNext) {
226 visitor(*strike);
Herbert Derby671e7ee2018-04-17 08:04:47 -0400227 }
228}
229
Herbert Derby671e7ee2018-04-17 08:04:47 -0400230size_t SkStrikeCache::internalPurge(size_t minBytesNeeded) {
Herbert Derby671e7ee2018-04-17 08:04:47 -0400231 size_t bytesNeeded = 0;
232 if (fTotalMemoryUsed > fCacheSizeLimit) {
233 bytesNeeded = fTotalMemoryUsed - fCacheSizeLimit;
234 }
Brian Osman788b9162020-02-07 10:36:46 -0500235 bytesNeeded = std::max(bytesNeeded, minBytesNeeded);
Herbert Derby671e7ee2018-04-17 08:04:47 -0400236 if (bytesNeeded) {
237 // no small purges!
Brian Osman788b9162020-02-07 10:36:46 -0500238 bytesNeeded = std::max(bytesNeeded, fTotalMemoryUsed >> 2);
Herbert Derby671e7ee2018-04-17 08:04:47 -0400239 }
240
241 int countNeeded = 0;
242 if (fCacheCount > fCacheCountLimit) {
243 countNeeded = fCacheCount - fCacheCountLimit;
244 // no small purges!
Brian Osman7f364052020-02-06 11:25:43 -0500245 countNeeded = std::max(countNeeded, fCacheCount >> 2);
Herbert Derby671e7ee2018-04-17 08:04:47 -0400246 }
247
248 // early exit
249 if (!countNeeded && !bytesNeeded) {
250 return 0;
251 }
252
253 size_t bytesFreed = 0;
254 int countFreed = 0;
255
Herb Derbye68c4fb2018-04-19 13:12:07 -0400256 // Start at the tail and proceed backwards deleting; the list is in LRU
Herbert Derby671e7ee2018-04-17 08:04:47 -0400257 // order, with unimportant entries at the tail.
Herb Derby81e84a62020-02-14 11:47:35 -0500258 Strike* strike = fTail;
259 while (strike != nullptr && (bytesFreed < bytesNeeded || countFreed < countNeeded)) {
260 Strike* prev = strike->fPrev;
Herbert Derby671e7ee2018-04-17 08:04:47 -0400261
Herb Derbye68c4fb2018-04-19 13:12:07 -0400262 // Only delete if the strike is not pinned.
Herb Derby81e84a62020-02-14 11:47:35 -0500263 if (strike->fPinner == nullptr || strike->fPinner->canDelete()) {
Herb Derby9baef352020-02-19 14:13:27 -0500264 bytesFreed += strike->fMemoryUsed;
Herb Derbye68c4fb2018-04-19 13:12:07 -0400265 countFreed += 1;
Herb Derbybcd65f12020-02-19 15:52:30 -0500266 this->internalRemoveStrike(strike);
Herb Derbye68c4fb2018-04-19 13:12:07 -0400267 }
Herb Derby81e84a62020-02-14 11:47:35 -0500268 strike = prev;
Herbert Derby671e7ee2018-04-17 08:04:47 -0400269 }
270
Herb Derby960d4212018-06-21 12:44:26 +0000271 this->validate();
Herbert Derby671e7ee2018-04-17 08:04:47 -0400272
273#ifdef SPEW_PURGE_STATUS
274 if (countFreed) {
275 SkDebugf("purging %dK from font cache [%d entries]\n",
276 (int)(bytesFreed >> 10), countFreed);
277 }
278#endif
279
280 return bytesFreed;
281}
282
Herb Derbybcd65f12020-02-19 15:52:30 -0500283void SkStrikeCache::internalAttachToHead(sk_sp<Strike> strike) {
Herb Derby659cc1c2020-02-21 16:49:37 -0500284 SkASSERT(fStrikeLookup.find(strike->getDescriptor()) == nullptr);
285 Strike* strikePtr = strike.get();
286 fStrikeLookup.set(std::move(strike));
287 SkASSERT(nullptr == strikePtr->fPrev && nullptr == strikePtr->fNext);
Herb Derbyd238d2f2018-04-26 12:59:08 -0400288
Herbert Derby671e7ee2018-04-17 08:04:47 -0400289 fCacheCount += 1;
Herb Derby659cc1c2020-02-21 16:49:37 -0500290 fTotalMemoryUsed += strikePtr->fMemoryUsed;
Herb Derbybcd65f12020-02-19 15:52:30 -0500291
Herb Derby659cc1c2020-02-21 16:49:37 -0500292 if (fHead != nullptr) {
293 fHead->fPrev = strikePtr;
294 strikePtr->fNext = fHead;
Herb Derbybcd65f12020-02-19 15:52:30 -0500295 }
296
297 if (fTail == nullptr) {
Herb Derby659cc1c2020-02-21 16:49:37 -0500298 fTail = strikePtr;
Herb Derbybcd65f12020-02-19 15:52:30 -0500299 }
300
Herb Derby659cc1c2020-02-21 16:49:37 -0500301 fHead = strikePtr; // Transfer ownership of strike to the cache list.
Herbert Derby671e7ee2018-04-17 08:04:47 -0400302}
303
Herb Derbybcd65f12020-02-19 15:52:30 -0500304void SkStrikeCache::internalRemoveStrike(Strike* strike) {
Herbert Derby671e7ee2018-04-17 08:04:47 -0400305 SkASSERT(fCacheCount > 0);
306 fCacheCount -= 1;
Herb Derby9baef352020-02-19 14:13:27 -0500307 fTotalMemoryUsed -= strike->fMemoryUsed;
Herbert Derby671e7ee2018-04-17 08:04:47 -0400308
Herb Derby81e84a62020-02-14 11:47:35 -0500309 if (strike->fPrev) {
310 strike->fPrev->fNext = strike->fNext;
Herbert Derby671e7ee2018-04-17 08:04:47 -0400311 } else {
Herb Derby81e84a62020-02-14 11:47:35 -0500312 fHead = strike->fNext;
Herbert Derby671e7ee2018-04-17 08:04:47 -0400313 }
Herb Derby81e84a62020-02-14 11:47:35 -0500314 if (strike->fNext) {
315 strike->fNext->fPrev = strike->fPrev;
Herb Derbyd238d2f2018-04-26 12:59:08 -0400316 } else {
Herb Derby81e84a62020-02-14 11:47:35 -0500317 fTail = strike->fPrev;
Herbert Derby671e7ee2018-04-17 08:04:47 -0400318 }
Herb Derby6cc2d9f2020-02-20 13:31:27 -0500319
Herb Derby81e84a62020-02-14 11:47:35 -0500320 strike->fPrev = strike->fNext = nullptr;
Herb Derbybcd65f12020-02-19 15:52:30 -0500321 strike->fRemoved = true;
Herb Derby659cc1c2020-02-21 16:49:37 -0500322 fStrikeLookup.remove(strike->getDescriptor());
Herbert Derby671e7ee2018-04-17 08:04:47 -0400323}
324
Herb Derby960d4212018-06-21 12:44:26 +0000325void SkStrikeCache::validate() const {
Herb Derbybcd65f12020-02-19 15:52:30 -0500326#ifdef SK_DEBUG
Herb Derbye68c4fb2018-04-19 13:12:07 -0400327 size_t computedBytes = 0;
328 int computedCount = 0;
329
Herb Derby81e84a62020-02-14 11:47:35 -0500330 const Strike* strike = fHead;
331 while (strike != nullptr) {
Herb Derby9baef352020-02-19 14:13:27 -0500332 computedBytes += strike->fMemoryUsed;
Herb Derbye68c4fb2018-04-19 13:12:07 -0400333 computedCount += 1;
Herb Derby6cc2d9f2020-02-20 13:31:27 -0500334 SkASSERT(fStrikeLookup.findOrNull(strike->getDescriptor()) != nullptr);
Herb Derby81e84a62020-02-14 11:47:35 -0500335 strike = strike->fNext;
Herb Derbye68c4fb2018-04-19 13:12:07 -0400336 }
337
Herb Derbyfdb2b7d2019-12-16 12:19:03 -0500338 if (fCacheCount != computedCount) {
339 SkDebugf("fCacheCount: %d, computedCount: %d", fCacheCount, computedCount);
340 SK_ABORT("fCacheCount != computedCount");
341 }
342 if (fTotalMemoryUsed != computedBytes) {
John Stiles7bf79992021-06-25 11:05:20 -0400343 SkDebugf("fTotalMemoryUsed: %zu, computedBytes: %zu", fTotalMemoryUsed, computedBytes);
Herb Derbyfdb2b7d2019-12-16 12:19:03 -0500344 SK_ABORT("fTotalMemoryUsed == computedBytes");
345 }
Herb Derbye68c4fb2018-04-19 13:12:07 -0400346#endif
Herb Derbybcd65f12020-02-19 15:52:30 -0500347}
348
349void SkStrikeCache::Strike::updateDelta(size_t increase) {
350 if (increase != 0) {
Herb Derby4ce81892021-05-11 16:14:14 -0400351 SkAutoMutexExclusive lock{fStrikeCache->fLock};
Herb Derbybcd65f12020-02-19 15:52:30 -0500352 fMemoryUsed += increase;
353 if (!fRemoved) {
354 fStrikeCache->fTotalMemoryUsed += increase;
355 }
356 }
357}