GrTextBlobCache.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * Copyright 2015 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. #ifndef GrTextBlobCache_DEFINED
  8. #define GrTextBlobCache_DEFINED
  9. #include "include/core/SkRefCnt.h"
  10. #include "include/private/SkTArray.h"
  11. #include "include/private/SkTHash.h"
  12. #include "src/core/SkMessageBus.h"
  13. #include "src/core/SkTextBlobPriv.h"
  14. #include "src/gpu/text/GrTextBlob.h"
  15. class GrTextBlobCache {
  16. public:
  17. /**
  18. * The callback function used by the cache when it is still over budget after a purge. The
  19. * passed in 'data' is the same 'data' handed to setOverbudgetCallback.
  20. */
  21. typedef void (*PFOverBudgetCB)(void* data);
  22. GrTextBlobCache(PFOverBudgetCB cb, void* data, uint32_t uniqueID)
  23. : fCallback(cb)
  24. , fData(data)
  25. , fSizeBudget(kDefaultBudget)
  26. , fUniqueID(uniqueID)
  27. , fPurgeBlobInbox(uniqueID) {
  28. SkASSERT(cb && data);
  29. }
  30. ~GrTextBlobCache();
  31. sk_sp<GrTextBlob> makeBlob(const SkGlyphRunList& glyphRunList,
  32. GrColor color,
  33. GrStrikeCache* strikeCache) {
  34. return GrTextBlob::Make(
  35. glyphRunList.totalGlyphCount(), glyphRunList.size(), color, strikeCache);
  36. }
  37. sk_sp<GrTextBlob> makeCachedBlob(const SkGlyphRunList& glyphRunList,
  38. const GrTextBlob::Key& key,
  39. const SkMaskFilterBase::BlurRec& blurRec,
  40. const SkPaint& paint,
  41. GrColor color,
  42. GrStrikeCache* strikeCache) {
  43. sk_sp<GrTextBlob> cacheBlob(makeBlob(glyphRunList, color, strikeCache));
  44. cacheBlob->setupKey(key, blurRec, paint);
  45. this->add(cacheBlob);
  46. glyphRunList.temporaryShuntBlobNotifyAddedToCache(fUniqueID);
  47. return cacheBlob;
  48. }
  49. sk_sp<GrTextBlob> find(const GrTextBlob::Key& key) const {
  50. const auto* idEntry = fBlobIDCache.find(key.fUniqueID);
  51. return idEntry ? idEntry->find(key) : nullptr;
  52. }
  53. void remove(GrTextBlob* blob) {
  54. auto id = GrTextBlob::GetKey(*blob).fUniqueID;
  55. auto* idEntry = fBlobIDCache.find(id);
  56. SkASSERT(idEntry);
  57. fCurrentSize -= blob->size();
  58. fBlobList.remove(blob);
  59. idEntry->removeBlob(blob);
  60. if (idEntry->fBlobs.empty()) {
  61. fBlobIDCache.remove(id);
  62. }
  63. }
  64. void makeMRU(GrTextBlob* blob) {
  65. if (fBlobList.head() == blob) {
  66. return;
  67. }
  68. fBlobList.remove(blob);
  69. fBlobList.addToHead(blob);
  70. }
  71. void freeAll();
  72. // TODO move to SkTextBlob
  73. static void BlobGlyphCount(int* glyphCount, int* runCount, const SkTextBlob* blob) {
  74. SkTextBlobRunIterator itCounter(blob);
  75. for (; !itCounter.done(); itCounter.next(), (*runCount)++) {
  76. *glyphCount += itCounter.glyphCount();
  77. }
  78. }
  79. void setBudget(size_t budget) {
  80. fSizeBudget = budget;
  81. this->checkPurge();
  82. }
  83. struct PurgeBlobMessage {
  84. PurgeBlobMessage(uint32_t blobID, uint32_t contextUniqueID)
  85. : fBlobID(blobID), fContextID(contextUniqueID) {}
  86. uint32_t fBlobID;
  87. uint32_t fContextID;
  88. };
  89. static void PostPurgeBlobMessage(uint32_t blobID, uint32_t cacheID);
  90. void purgeStaleBlobs();
  91. size_t usedBytes() const { return fCurrentSize; }
  92. private:
  93. using BitmapBlobList = SkTInternalLList<GrTextBlob>;
  94. struct BlobIDCacheEntry {
  95. BlobIDCacheEntry() : fID(SK_InvalidGenID) {}
  96. explicit BlobIDCacheEntry(uint32_t id) : fID(id) {}
  97. static uint32_t GetKey(const BlobIDCacheEntry& entry) {
  98. return entry.fID;
  99. }
  100. void addBlob(sk_sp<GrTextBlob> blob) {
  101. SkASSERT(blob);
  102. SkASSERT(GrTextBlob::GetKey(*blob).fUniqueID == fID);
  103. SkASSERT(!this->find(GrTextBlob::GetKey(*blob)));
  104. fBlobs.emplace_back(std::move(blob));
  105. }
  106. void removeBlob(GrTextBlob* blob) {
  107. SkASSERT(blob);
  108. SkASSERT(GrTextBlob::GetKey(*blob).fUniqueID == fID);
  109. auto index = this->findBlobIndex(GrTextBlob::GetKey(*blob));
  110. SkASSERT(index >= 0);
  111. fBlobs.removeShuffle(index);
  112. }
  113. sk_sp<GrTextBlob> find(const GrTextBlob::Key& key) const {
  114. auto index = this->findBlobIndex(key);
  115. return index < 0 ? nullptr : fBlobs[index];
  116. }
  117. int findBlobIndex(const GrTextBlob::Key& key) const{
  118. for (int i = 0; i < fBlobs.count(); ++i) {
  119. if (GrTextBlob::GetKey(*fBlobs[i]) == key) {
  120. return i;
  121. }
  122. }
  123. return -1;
  124. }
  125. uint32_t fID;
  126. // Current clients don't generate multiple GrAtlasTextBlobs per SkTextBlob, so an array w/
  127. // linear search is acceptable. If usage changes, we should re-evaluate this structure.
  128. SkSTArray<1, sk_sp<GrTextBlob>, true> fBlobs;
  129. };
  130. void add(sk_sp<GrTextBlob> blob) {
  131. auto id = GrTextBlob::GetKey(*blob).fUniqueID;
  132. auto* idEntry = fBlobIDCache.find(id);
  133. if (!idEntry) {
  134. idEntry = fBlobIDCache.set(id, BlobIDCacheEntry(id));
  135. }
  136. // Safe to retain a raw ptr temporarily here, because the cache will hold a ref.
  137. GrTextBlob* rawBlobPtr = blob.get();
  138. fBlobList.addToHead(rawBlobPtr);
  139. fCurrentSize += blob->size();
  140. idEntry->addBlob(std::move(blob));
  141. this->checkPurge(rawBlobPtr);
  142. }
  143. void checkPurge(GrTextBlob* blob = nullptr);
  144. static const int kMinGrowthSize = 1 << 16;
  145. static const int kDefaultBudget = 1 << 22;
  146. BitmapBlobList fBlobList;
  147. SkTHashMap<uint32_t, BlobIDCacheEntry> fBlobIDCache;
  148. PFOverBudgetCB fCallback;
  149. void* fData;
  150. size_t fSizeBudget;
  151. size_t fCurrentSize{0};
  152. uint32_t fUniqueID; // unique id to use for messaging
  153. SkMessageBus<PurgeBlobMessage>::Inbox fPurgeBlobInbox;
  154. };
  155. #endif