SkStrikeCache.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. /*
  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. #include "src/core/SkStrikeCache.h"
  8. #include <cctype>
  9. #include "include/core/SkGraphics.h"
  10. #include "include/core/SkTraceMemoryDump.h"
  11. #include "include/core/SkTypeface.h"
  12. #include "include/private/SkMutex.h"
  13. #include "include/private/SkTemplates.h"
  14. #include "src/core/SkGlyphRunPainter.h"
  15. #include "src/core/SkStrike.h"
  16. class SkStrikeCache::Node final : public SkStrikeInterface {
  17. public:
  18. Node(SkStrikeCache* strikeCache,
  19. const SkDescriptor& desc,
  20. std::unique_ptr<SkScalerContext> scaler,
  21. const SkFontMetrics& metrics,
  22. std::unique_ptr<SkStrikePinner> pinner)
  23. : fStrikeCache{strikeCache}
  24. , fStrike{desc, std::move(scaler), metrics}
  25. , fPinner{std::move(pinner)} {}
  26. SkVector rounding() const override {
  27. return fStrike.rounding();
  28. }
  29. SkIPoint subpixelMask() const override {
  30. return fStrike.subpixelMask();
  31. }
  32. SkSpan<const SkGlyphPos>
  33. prepareForDrawing(const SkPackedGlyphID packedGlyphIDs[], const SkPoint positions[], size_t n,
  34. int maxDimension, PreparationDetail detail, SkGlyphPos results[]) override {
  35. return fStrike.prepareForDrawing(packedGlyphIDs, positions, n, maxDimension, detail,
  36. results);
  37. }
  38. const SkDescriptor& getDescriptor() const override {
  39. return fStrike.getDescriptor();
  40. }
  41. void onAboutToExitScope() override {
  42. fStrikeCache->attachNode(this);
  43. }
  44. SkStrikeCache* const fStrikeCache;
  45. Node* fNext{nullptr};
  46. Node* fPrev{nullptr};
  47. SkStrike fStrike;
  48. std::unique_ptr<SkStrikePinner> fPinner;
  49. };
  50. SkStrikeCache* SkStrikeCache::GlobalStrikeCache() {
  51. static auto* cache = new SkStrikeCache;
  52. return cache;
  53. }
  54. SkStrikeCache::ExclusiveStrikePtr::ExclusiveStrikePtr(SkStrikeCache::Node* node)
  55. : fNode{node} {}
  56. SkStrikeCache::ExclusiveStrikePtr::ExclusiveStrikePtr()
  57. : fNode{nullptr} {}
  58. SkStrikeCache::ExclusiveStrikePtr::ExclusiveStrikePtr(ExclusiveStrikePtr&& o)
  59. : fNode{o.fNode} {
  60. o.fNode = nullptr;
  61. }
  62. SkStrikeCache::ExclusiveStrikePtr&
  63. SkStrikeCache::ExclusiveStrikePtr::operator = (ExclusiveStrikePtr&& o) {
  64. if (fNode != nullptr) {
  65. fNode->fStrikeCache->attachNode(fNode);
  66. }
  67. fNode = o.fNode;
  68. o.fNode = nullptr;
  69. return *this;
  70. }
  71. SkStrikeCache::ExclusiveStrikePtr::~ExclusiveStrikePtr() {
  72. if (fNode != nullptr) {
  73. fNode->fStrikeCache->attachNode(fNode);
  74. }
  75. }
  76. SkStrike* SkStrikeCache::ExclusiveStrikePtr::get() const {
  77. return &fNode->fStrike;
  78. }
  79. SkStrike* SkStrikeCache::ExclusiveStrikePtr::operator -> () const {
  80. return this->get();
  81. }
  82. SkStrike& SkStrikeCache::ExclusiveStrikePtr::operator * () const {
  83. return *this->get();
  84. }
  85. SkStrikeCache::ExclusiveStrikePtr::operator bool () const {
  86. return fNode != nullptr;
  87. }
  88. bool operator == (const SkStrikeCache::ExclusiveStrikePtr& lhs,
  89. const SkStrikeCache::ExclusiveStrikePtr& rhs) {
  90. return lhs.fNode == rhs.fNode;
  91. }
  92. bool operator == (const SkStrikeCache::ExclusiveStrikePtr& lhs, decltype(nullptr)) {
  93. return lhs.fNode == nullptr;
  94. }
  95. bool operator == (decltype(nullptr), const SkStrikeCache::ExclusiveStrikePtr& rhs) {
  96. return nullptr == rhs.fNode;
  97. }
  98. SkStrikeCache::~SkStrikeCache() {
  99. Node* node = fHead;
  100. while (node) {
  101. Node* next = node->fNext;
  102. delete node;
  103. node = next;
  104. }
  105. }
  106. std::unique_ptr<SkScalerContext> SkStrikeCache::CreateScalerContext(
  107. const SkDescriptor& desc,
  108. const SkScalerContextEffects& effects,
  109. const SkTypeface& typeface) {
  110. auto scaler = typeface.createScalerContext(effects, &desc, true /* can fail */);
  111. // Check if we can create a scaler-context before creating the glyphcache.
  112. // If not, we may have exhausted OS/font resources, so try purging the
  113. // cache once and try again
  114. // pass true the first time, to notice if the scalercontext failed,
  115. if (scaler == nullptr) {
  116. PurgeAll();
  117. scaler = typeface.createScalerContext(effects, &desc, false /* must succeed */);
  118. }
  119. return scaler;
  120. }
  121. SkExclusiveStrikePtr SkStrikeCache::findOrCreateStrikeExclusive(
  122. const SkDescriptor& desc, const SkScalerContextEffects& effects, const SkTypeface& typeface)
  123. {
  124. return SkExclusiveStrikePtr(this->findOrCreateStrike(desc, effects, typeface));
  125. }
  126. auto SkStrikeCache::findOrCreateStrike(const SkDescriptor& desc,
  127. const SkScalerContextEffects& effects,
  128. const SkTypeface& typeface) -> Node* {
  129. Node* node = this->findAndDetachStrike(desc);
  130. if (node == nullptr) {
  131. auto scaler = CreateScalerContext(desc, effects, typeface);
  132. node = this->createStrike(desc, std::move(scaler));
  133. }
  134. return node;
  135. }
  136. SkScopedStrike SkStrikeCache::findOrCreateScopedStrike(const SkDescriptor& desc,
  137. const SkScalerContextEffects& effects,
  138. const SkTypeface& typeface) {
  139. return SkScopedStrike{this->findOrCreateStrike(desc, effects, typeface)};
  140. }
  141. void SkStrikeCache::PurgeAll() {
  142. GlobalStrikeCache()->purgeAll();
  143. }
  144. void SkStrikeCache::Dump() {
  145. SkDebugf("GlyphCache [ used budget ]\n");
  146. SkDebugf(" bytes [ %8zu %8zu ]\n",
  147. SkGraphics::GetFontCacheUsed(), SkGraphics::GetFontCacheLimit());
  148. SkDebugf(" count [ %8zu %8zu ]\n",
  149. SkGraphics::GetFontCacheCountUsed(), SkGraphics::GetFontCacheCountLimit());
  150. int counter = 0;
  151. auto visitor = [&counter](const SkStrike& cache) {
  152. const SkScalerContextRec& rec = cache.getScalerContext()->getRec();
  153. SkDebugf("index %d\n", counter);
  154. SkDebugf("%s", rec.dump().c_str());
  155. counter += 1;
  156. };
  157. GlobalStrikeCache()->forEachStrike(visitor);
  158. }
  159. namespace {
  160. const char gGlyphCacheDumpName[] = "skia/sk_glyph_cache";
  161. } // namespace
  162. void SkStrikeCache::DumpMemoryStatistics(SkTraceMemoryDump* dump) {
  163. dump->dumpNumericValue(gGlyphCacheDumpName, "size", "bytes", SkGraphics::GetFontCacheUsed());
  164. dump->dumpNumericValue(gGlyphCacheDumpName, "budget_size", "bytes",
  165. SkGraphics::GetFontCacheLimit());
  166. dump->dumpNumericValue(gGlyphCacheDumpName, "glyph_count", "objects",
  167. SkGraphics::GetFontCacheCountUsed());
  168. dump->dumpNumericValue(gGlyphCacheDumpName, "budget_glyph_count", "objects",
  169. SkGraphics::GetFontCacheCountLimit());
  170. if (dump->getRequestedDetails() == SkTraceMemoryDump::kLight_LevelOfDetail) {
  171. dump->setMemoryBacking(gGlyphCacheDumpName, "malloc", nullptr);
  172. return;
  173. }
  174. auto visitor = [&dump](const SkStrike& cache) {
  175. const SkTypeface* face = cache.getScalerContext()->getTypeface();
  176. const SkScalerContextRec& rec = cache.getScalerContext()->getRec();
  177. SkString fontName;
  178. face->getFamilyName(&fontName);
  179. // Replace all special characters with '_'.
  180. for (size_t index = 0; index < fontName.size(); ++index) {
  181. if (!std::isalnum(fontName[index])) {
  182. fontName[index] = '_';
  183. }
  184. }
  185. SkString dumpName = SkStringPrintf(
  186. "%s/%s_%d/%p", gGlyphCacheDumpName, fontName.c_str(), rec.fFontID, &cache);
  187. dump->dumpNumericValue(dumpName.c_str(),
  188. "size", "bytes", cache.getMemoryUsed());
  189. dump->dumpNumericValue(dumpName.c_str(),
  190. "glyph_count", "objects", cache.countCachedGlyphs());
  191. dump->setMemoryBacking(dumpName.c_str(), "malloc", nullptr);
  192. };
  193. GlobalStrikeCache()->forEachStrike(visitor);
  194. }
  195. void SkStrikeCache::attachNode(Node* node) {
  196. if (node == nullptr) {
  197. return;
  198. }
  199. SkAutoSpinlock ac(fLock);
  200. this->validate();
  201. node->fStrike.validate();
  202. this->internalAttachToHead(node);
  203. this->internalPurge();
  204. }
  205. SkExclusiveStrikePtr SkStrikeCache::findStrikeExclusive(const SkDescriptor& desc) {
  206. return SkExclusiveStrikePtr(this->findAndDetachStrike(desc));
  207. }
  208. auto SkStrikeCache::findAndDetachStrike(const SkDescriptor& desc) -> Node* {
  209. SkAutoSpinlock ac(fLock);
  210. for (Node* node = internalGetHead(); node != nullptr; node = node->fNext) {
  211. if (node->fStrike.getDescriptor() == desc) {
  212. this->internalDetachCache(node);
  213. return node;
  214. }
  215. }
  216. return nullptr;
  217. }
  218. static bool loose_compare(const SkDescriptor& lhs, const SkDescriptor& rhs) {
  219. uint32_t size;
  220. auto ptr = lhs.findEntry(kRec_SkDescriptorTag, &size);
  221. SkScalerContextRec lhsRec;
  222. std::memcpy(&lhsRec, ptr, size);
  223. ptr = rhs.findEntry(kRec_SkDescriptorTag, &size);
  224. SkScalerContextRec rhsRec;
  225. std::memcpy(&rhsRec, ptr, size);
  226. // If these don't match, there's no way we can use these strikes interchangeably.
  227. // Note that a typeface from each renderer maps to a unique proxy typeface on the GPU,
  228. // keyed in the glyph cache using fontID in the SkDescriptor. By limiting this search
  229. // to descriptors with the same fontID, we ensure that a renderer never uses glyphs
  230. // generated by a different renderer.
  231. return
  232. lhsRec.fFontID == rhsRec.fFontID &&
  233. lhsRec.fTextSize == rhsRec.fTextSize &&
  234. lhsRec.fPreScaleX == rhsRec.fPreScaleX &&
  235. lhsRec.fPreSkewX == rhsRec.fPreSkewX &&
  236. lhsRec.fPost2x2[0][0] == rhsRec.fPost2x2[0][0] &&
  237. lhsRec.fPost2x2[0][1] == rhsRec.fPost2x2[0][1] &&
  238. lhsRec.fPost2x2[1][0] == rhsRec.fPost2x2[1][0] &&
  239. lhsRec.fPost2x2[1][1] == rhsRec.fPost2x2[1][1];
  240. }
  241. bool SkStrikeCache::desperationSearchForImage(const SkDescriptor& desc, SkGlyph* glyph,
  242. SkStrike* targetCache) {
  243. SkAutoSpinlock ac(fLock);
  244. SkGlyphID glyphID = glyph->getGlyphID();
  245. for (Node* node = internalGetHead(); node != nullptr; node = node->fNext) {
  246. if (loose_compare(node->fStrike.getDescriptor(), desc)) {
  247. if (SkGlyph *fallback = node->fStrike.glyphOrNull(glyph->getPackedID())) {
  248. // This desperate-match node may disappear as soon as we drop fLock, so we
  249. // need to copy the glyph from node into this strike, including a
  250. // deep copy of the mask.
  251. targetCache->mergeGlyphAndImage(glyph->getPackedID(), *fallback);
  252. return true;
  253. }
  254. // Look for any sub-pixel pos for this glyph, in case there is a pos mismatch.
  255. if (const auto* fallback = node->fStrike.getCachedGlyphAnySubPix(glyphID)) {
  256. targetCache->mergeGlyphAndImage(glyph->getPackedID(), *fallback);
  257. return true;
  258. }
  259. }
  260. }
  261. return false;
  262. }
  263. bool SkStrikeCache::desperationSearchForPath(
  264. const SkDescriptor& desc, SkGlyphID glyphID, SkPath* path) {
  265. SkAutoSpinlock ac(fLock);
  266. // The following is wrong there is subpixel positioning with paths...
  267. // Paths are only ever at sub-pixel position (0,0), so we can just try that directly rather
  268. // than try our packed position first then search all others on failure like for masks.
  269. //
  270. // This will have to search the sub-pixel positions too.
  271. // There is also a problem with accounting for cache size with shared path data.
  272. for (Node* node = internalGetHead(); node != nullptr; node = node->fNext) {
  273. if (loose_compare(node->fStrike.getDescriptor(), desc)) {
  274. if (SkGlyph *from = node->fStrike.glyphOrNull(SkPackedGlyphID{glyphID})) {
  275. if (from->setPathHasBeenCalled() && from->path() != nullptr) {
  276. // We can just copy the path out by value here, so no need to worry
  277. // about the lifetime of this desperate-match node.
  278. *path = *from->path();
  279. return true;
  280. }
  281. }
  282. }
  283. }
  284. return false;
  285. }
  286. SkExclusiveStrikePtr SkStrikeCache::createStrikeExclusive(
  287. const SkDescriptor& desc,
  288. std::unique_ptr<SkScalerContext> scaler,
  289. SkFontMetrics* maybeMetrics,
  290. std::unique_ptr<SkStrikePinner> pinner)
  291. {
  292. return SkExclusiveStrikePtr(
  293. this->createStrike(desc, std::move(scaler), maybeMetrics, std::move(pinner)));
  294. }
  295. auto SkStrikeCache::createStrike(
  296. const SkDescriptor& desc,
  297. std::unique_ptr<SkScalerContext> scaler,
  298. SkFontMetrics* maybeMetrics,
  299. std::unique_ptr<SkStrikePinner> pinner) -> Node* {
  300. SkFontMetrics fontMetrics;
  301. if (maybeMetrics != nullptr) {
  302. fontMetrics = *maybeMetrics;
  303. } else {
  304. scaler->getFontMetrics(&fontMetrics);
  305. }
  306. return new Node{this, desc, std::move(scaler), fontMetrics, std::move(pinner)};
  307. }
  308. void SkStrikeCache::purgeAll() {
  309. SkAutoSpinlock ac(fLock);
  310. this->internalPurge(fTotalMemoryUsed);
  311. }
  312. size_t SkStrikeCache::getTotalMemoryUsed() const {
  313. SkAutoSpinlock ac(fLock);
  314. return fTotalMemoryUsed;
  315. }
  316. int SkStrikeCache::getCacheCountUsed() const {
  317. SkAutoSpinlock ac(fLock);
  318. return fCacheCount;
  319. }
  320. int SkStrikeCache::getCacheCountLimit() const {
  321. SkAutoSpinlock ac(fLock);
  322. return fCacheCountLimit;
  323. }
  324. size_t SkStrikeCache::setCacheSizeLimit(size_t newLimit) {
  325. static const size_t minLimit = 256 * 1024;
  326. if (newLimit < minLimit) {
  327. newLimit = minLimit;
  328. }
  329. SkAutoSpinlock ac(fLock);
  330. size_t prevLimit = fCacheSizeLimit;
  331. fCacheSizeLimit = newLimit;
  332. this->internalPurge();
  333. return prevLimit;
  334. }
  335. size_t SkStrikeCache::getCacheSizeLimit() const {
  336. SkAutoSpinlock ac(fLock);
  337. return fCacheSizeLimit;
  338. }
  339. int SkStrikeCache::setCacheCountLimit(int newCount) {
  340. if (newCount < 0) {
  341. newCount = 0;
  342. }
  343. SkAutoSpinlock ac(fLock);
  344. int prevCount = fCacheCountLimit;
  345. fCacheCountLimit = newCount;
  346. this->internalPurge();
  347. return prevCount;
  348. }
  349. int SkStrikeCache::getCachePointSizeLimit() const {
  350. SkAutoSpinlock ac(fLock);
  351. return fPointSizeLimit;
  352. }
  353. int SkStrikeCache::setCachePointSizeLimit(int newLimit) {
  354. if (newLimit < 0) {
  355. newLimit = 0;
  356. }
  357. SkAutoSpinlock ac(fLock);
  358. int prevLimit = fPointSizeLimit;
  359. fPointSizeLimit = newLimit;
  360. return prevLimit;
  361. }
  362. void SkStrikeCache::forEachStrike(std::function<void(const SkStrike&)> visitor) const {
  363. SkAutoSpinlock ac(fLock);
  364. this->validate();
  365. for (Node* node = this->internalGetHead(); node != nullptr; node = node->fNext) {
  366. visitor(node->fStrike);
  367. }
  368. }
  369. size_t SkStrikeCache::internalPurge(size_t minBytesNeeded) {
  370. this->validate();
  371. size_t bytesNeeded = 0;
  372. if (fTotalMemoryUsed > fCacheSizeLimit) {
  373. bytesNeeded = fTotalMemoryUsed - fCacheSizeLimit;
  374. }
  375. bytesNeeded = SkTMax(bytesNeeded, minBytesNeeded);
  376. if (bytesNeeded) {
  377. // no small purges!
  378. bytesNeeded = SkTMax(bytesNeeded, fTotalMemoryUsed >> 2);
  379. }
  380. int countNeeded = 0;
  381. if (fCacheCount > fCacheCountLimit) {
  382. countNeeded = fCacheCount - fCacheCountLimit;
  383. // no small purges!
  384. countNeeded = SkMax32(countNeeded, fCacheCount >> 2);
  385. }
  386. // early exit
  387. if (!countNeeded && !bytesNeeded) {
  388. return 0;
  389. }
  390. size_t bytesFreed = 0;
  391. int countFreed = 0;
  392. // Start at the tail and proceed backwards deleting; the list is in LRU
  393. // order, with unimportant entries at the tail.
  394. Node* node = this->internalGetTail();
  395. while (node != nullptr && (bytesFreed < bytesNeeded || countFreed < countNeeded)) {
  396. Node* prev = node->fPrev;
  397. // Only delete if the strike is not pinned.
  398. if (node->fPinner == nullptr || node->fPinner->canDelete()) {
  399. bytesFreed += node->fStrike.getMemoryUsed();
  400. countFreed += 1;
  401. this->internalDetachCache(node);
  402. delete node;
  403. }
  404. node = prev;
  405. }
  406. this->validate();
  407. #ifdef SPEW_PURGE_STATUS
  408. if (countFreed) {
  409. SkDebugf("purging %dK from font cache [%d entries]\n",
  410. (int)(bytesFreed >> 10), countFreed);
  411. }
  412. #endif
  413. return bytesFreed;
  414. }
  415. void SkStrikeCache::internalAttachToHead(Node* node) {
  416. SkASSERT(nullptr == node->fPrev && nullptr == node->fNext);
  417. if (fHead) {
  418. fHead->fPrev = node;
  419. node->fNext = fHead;
  420. }
  421. fHead = node;
  422. if (fTail == nullptr) {
  423. fTail = node;
  424. }
  425. fCacheCount += 1;
  426. fTotalMemoryUsed += node->fStrike.getMemoryUsed();
  427. }
  428. void SkStrikeCache::internalDetachCache(Node* node) {
  429. SkASSERT(fCacheCount > 0);
  430. fCacheCount -= 1;
  431. fTotalMemoryUsed -= node->fStrike.getMemoryUsed();
  432. if (node->fPrev) {
  433. node->fPrev->fNext = node->fNext;
  434. } else {
  435. fHead = node->fNext;
  436. }
  437. if (node->fNext) {
  438. node->fNext->fPrev = node->fPrev;
  439. } else {
  440. fTail = node->fPrev;
  441. }
  442. node->fPrev = node->fNext = nullptr;
  443. }
  444. void SkStrikeCache::ValidateGlyphCacheDataSize() {
  445. #ifdef SK_DEBUG
  446. GlobalStrikeCache()->validateGlyphCacheDataSize();
  447. #endif
  448. }
  449. #ifdef SK_DEBUG
  450. void SkStrikeCache::validateGlyphCacheDataSize() const {
  451. this->forEachStrike(
  452. [](const SkStrike& cache) { cache.forceValidate();
  453. });
  454. }
  455. #endif
  456. #ifdef SK_DEBUG
  457. void SkStrikeCache::validate() const {
  458. size_t computedBytes = 0;
  459. int computedCount = 0;
  460. const Node* node = fHead;
  461. while (node != nullptr) {
  462. computedBytes += node->fStrike.getMemoryUsed();
  463. computedCount += 1;
  464. node = node->fNext;
  465. }
  466. SkASSERTF(fCacheCount == computedCount, "fCacheCount: %d, computedCount: %d", fCacheCount,
  467. computedCount);
  468. SkASSERTF(fTotalMemoryUsed == computedBytes, "fTotalMemoryUsed: %d, computedBytes: %d",
  469. fTotalMemoryUsed, computedBytes);
  470. }
  471. #endif
  472. ////////////////////////////////////////////////////////////////////////////////////////////////////