blob: 8a329c49690576335b8fd1a469ebd809fed4f1ef [file] [log] [blame]
joshualittb7133be2015-04-08 09:08:31 -07001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/gpu/text/GrTextBlobCache.h"
joshualittb7133be2015-04-08 09:08:31 -07009
Florin Malita4a01ac92017-03-13 16:45:28 -040010DECLARE_SKMESSAGEBUS_MESSAGE(GrTextBlobCache::PurgeBlobMessage)
11
Herb Derby7b4ea9b2020-05-20 17:31:36 -040012// This function is captured by the above macro using implementations from SkMessageBus.h
Chris Dalton9a986cf2018-10-18 15:27:59 -060013static inline bool SkShouldPostMessageToBus(
14 const GrTextBlobCache::PurgeBlobMessage& msg, uint32_t msgBusUniqueID) {
15 return msg.fContextID == msgBusUniqueID;
16}
17
Herb Derbya50830b2020-05-21 14:01:09 -040018GrTextBlobCache::GrTextBlobCache(PurgeMore purgeMore, uint32_t messageBusID)
Herb Derbyd6fe76a2020-05-21 12:05:04 -040019 : fPurgeMore(purgeMore)
Herb Derby7b4ea9b2020-05-20 17:31:36 -040020 , fSizeBudget(kDefaultBudget)
Herb Derbya50830b2020-05-21 14:01:09 -040021 , fMessageBusID(messageBusID)
22 , fPurgeBlobInbox(messageBusID) { }
Herb Derby7b4ea9b2020-05-20 17:31:36 -040023
Herb Derby7b4ea9b2020-05-20 17:31:36 -040024sk_sp<GrTextBlob>
25GrTextBlobCache::makeCachedBlob(const SkGlyphRunList& glyphRunList, const GrTextBlob::Key& key,
26 const SkMaskFilterBase::BlurRec& blurRec,
Herb Derbybe202052020-06-05 17:22:38 -040027 const SkMatrix& viewMatrix) {
28 sk_sp<GrTextBlob> cacheBlob(GrTextBlob::Make(glyphRunList, viewMatrix));
Herb Derby7b4ea9b2020-05-20 17:31:36 -040029 cacheBlob->setupKey(key, blurRec, glyphRunList.paint());
Herb Derbyd0fa3ee2020-06-23 12:23:51 -040030 SkAutoMutexExclusive lock{fMutex};
Herb Derbyc5f25bc2020-06-23 14:02:23 -040031 this->internalAdd(cacheBlob);
Herb Derbya50830b2020-05-21 14:01:09 -040032 glyphRunList.temporaryShuntBlobNotifyAddedToCache(fMessageBusID);
Herb Derby7b4ea9b2020-05-20 17:31:36 -040033 return cacheBlob;
34}
35
36sk_sp<GrTextBlob> GrTextBlobCache::find(const GrTextBlob::Key& key) const {
Herb Derbyd0fa3ee2020-06-23 12:23:51 -040037 SkAutoMutexExclusive lock{fMutex};
Herb Derby7b4ea9b2020-05-20 17:31:36 -040038 const auto* idEntry = fBlobIDCache.find(key.fUniqueID);
39 return idEntry ? idEntry->find(key) : nullptr;
40}
41
42void GrTextBlobCache::remove(GrTextBlob* blob) {
Herb Derbyd0fa3ee2020-06-23 12:23:51 -040043 SkAutoMutexExclusive lock{fMutex};
Herb Derbyc5f25bc2020-06-23 14:02:23 -040044 this->internalRemove(blob);
45}
46
47void GrTextBlobCache::internalRemove(GrTextBlob* blob) {
Herb Derby7b4ea9b2020-05-20 17:31:36 -040048 auto id = GrTextBlob::GetKey(*blob).fUniqueID;
49 auto* idEntry = fBlobIDCache.find(id);
50 SkASSERT(idEntry);
51
52 fCurrentSize -= blob->size();
53 fBlobList.remove(blob);
54 idEntry->removeBlob(blob);
55 if (idEntry->fBlobs.empty()) {
56 fBlobIDCache.remove(id);
57 }
58}
59
60void GrTextBlobCache::makeMRU(GrTextBlob* blob) {
Herb Derbyd0fa3ee2020-06-23 12:23:51 -040061 SkAutoMutexExclusive lock{fMutex};
Herb Derby7b4ea9b2020-05-20 17:31:36 -040062 if (fBlobList.head() == blob) {
63 return;
64 }
65
66 fBlobList.remove(blob);
67 fBlobList.addToHead(blob);
68}
69
joshualitt26ffc002015-04-16 11:24:04 -070070void GrTextBlobCache::freeAll() {
Herb Derbyd0fa3ee2020-06-23 12:23:51 -040071 SkAutoMutexExclusive lock{fMutex};
Florin Malita33fdb8d2017-03-07 16:51:57 -050072 fBlobIDCache.reset();
Herb Derbyadac2882020-06-23 12:45:15 -040073 fBlobList.reset();
Herb Derbyb12175f2018-05-23 16:38:09 -040074 fCurrentSize = 0;
joshualitt26ffc002015-04-16 11:24:04 -070075}
Florin Malita4a01ac92017-03-13 16:45:28 -040076
Herb Derby7b4ea9b2020-05-20 17:31:36 -040077void GrTextBlobCache::setBudget(size_t budget) {
Herb Derbyd0fa3ee2020-06-23 12:23:51 -040078 SkAutoMutexExclusive lock{fMutex};
Herb Derby7b4ea9b2020-05-20 17:31:36 -040079 fSizeBudget = budget;
Herb Derbyc5f25bc2020-06-23 14:02:23 -040080 this->internalCheckPurge();
Herb Derby7b4ea9b2020-05-20 17:31:36 -040081}
82
Jim Van Verth474d6872017-12-14 13:00:05 -050083void GrTextBlobCache::PostPurgeBlobMessage(uint32_t blobID, uint32_t cacheID) {
84 SkASSERT(blobID != SK_InvalidGenID);
Brian Salomon238069b2018-07-11 15:58:57 -040085 SkMessageBus<PurgeBlobMessage>::Post(PurgeBlobMessage(blobID, cacheID));
Florin Malita4a01ac92017-03-13 16:45:28 -040086}
Jim Van Verth76d917c2017-12-13 09:26:37 -050087
88void GrTextBlobCache::purgeStaleBlobs() {
Herb Derbyd0fa3ee2020-06-23 12:23:51 -040089 SkAutoMutexExclusive lock{fMutex};
Herb Derbyc5f25bc2020-06-23 14:02:23 -040090 this->internalPurgeStaleBlobs();
91}
92
93void GrTextBlobCache::internalPurgeStaleBlobs() {
Jim Van Verth76d917c2017-12-13 09:26:37 -050094 SkTArray<PurgeBlobMessage> msgs;
95 fPurgeBlobInbox.poll(&msgs);
96
97 for (const auto& msg : msgs) {
Brian Salomon238069b2018-07-11 15:58:57 -040098 auto* idEntry = fBlobIDCache.find(msg.fBlobID);
Jim Van Verth76d917c2017-12-13 09:26:37 -050099 if (!idEntry) {
100 // no cache entries for id
101 continue;
102 }
103
104 // remove all blob entries from the LRU list
105 for (const auto& blob : idEntry->fBlobs) {
Herb Derbyb12175f2018-05-23 16:38:09 -0400106 fCurrentSize -= blob->size();
Jim Van Verth76d917c2017-12-13 09:26:37 -0500107 fBlobList.remove(blob.get());
108 }
109
110 // drop the idEntry itself (unrefs all blobs)
Brian Salomon238069b2018-07-11 15:58:57 -0400111 fBlobIDCache.remove(msg.fBlobID);
Jim Van Verth76d917c2017-12-13 09:26:37 -0500112 }
113}
114
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400115size_t GrTextBlobCache::usedBytes() const {
Herb Derbyd0fa3ee2020-06-23 12:23:51 -0400116 SkAutoMutexExclusive lock{fMutex};
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400117 return fCurrentSize;
118}
119
120void GrTextBlobCache::internalCheckPurge(GrTextBlob* blob) {
Jim Van Verth76d917c2017-12-13 09:26:37 -0500121 // First, purge all stale blob IDs.
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400122 this->internalPurgeStaleBlobs();
Jim Van Verth76d917c2017-12-13 09:26:37 -0500123
124 // If we are still over budget, then unref until we are below budget again
Herb Derbyb12175f2018-05-23 16:38:09 -0400125 if (fCurrentSize > fSizeBudget) {
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400126 TextBlobList::Iter iter;
127 iter.init(fBlobList, TextBlobList::Iter::kTail_IterStart);
Herb Derby86240592018-05-24 16:12:31 -0400128 GrTextBlob* lruBlob = nullptr;
Herb Derbyb12175f2018-05-23 16:38:09 -0400129 while (fCurrentSize > fSizeBudget && (lruBlob = iter.get()) && lruBlob != blob) {
Jim Van Verth76d917c2017-12-13 09:26:37 -0500130 // Backup the iterator before removing and unrefing the blob
131 iter.prev();
132
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400133 this->internalRemove(lruBlob);
Jim Van Verth76d917c2017-12-13 09:26:37 -0500134 }
135
136 // If we break out of the loop with lruBlob == blob, then we haven't purged enough
137 // use the call back and try to free some more. If we are still overbudget after this,
138 // then this single textblob is over our budget
139 if (blob && lruBlob == blob) {
Herb Derbyd6fe76a2020-05-21 12:05:04 -0400140 fPurgeMore();
Jim Van Verth76d917c2017-12-13 09:26:37 -0500141 }
142
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400143 #ifdef SPEW_BUDGET_MESSAGE
Herb Derbyb12175f2018-05-23 16:38:09 -0400144 if (fCurrentSize > fSizeBudget) {
Jim Van Verth76d917c2017-12-13 09:26:37 -0500145 SkDebugf("Single textblob is larger than our whole budget");
146 }
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400147 #endif
Jim Van Verth76d917c2017-12-13 09:26:37 -0500148 }
149}
150
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400151void GrTextBlobCache::internalAdd(sk_sp<GrTextBlob> blob) {
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400152 auto id = GrTextBlob::GetKey(*blob).fUniqueID;
153 auto* idEntry = fBlobIDCache.find(id);
154 if (!idEntry) {
155 idEntry = fBlobIDCache.set(id, BlobIDCacheEntry(id));
156 }
Jim Van Verth76d917c2017-12-13 09:26:37 -0500157
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400158 // Safe to retain a raw ptr temporarily here, because the cache will hold a ref.
159 GrTextBlob* rawBlobPtr = blob.get();
160 fBlobList.addToHead(rawBlobPtr);
161 fCurrentSize += blob->size();
162 idEntry->addBlob(std::move(blob));
Jim Van Verth76d917c2017-12-13 09:26:37 -0500163
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400164 this->internalCheckPurge(rawBlobPtr);
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400165}
166
167GrTextBlobCache::BlobIDCacheEntry::BlobIDCacheEntry() : fID(SK_InvalidGenID) {}
168
169GrTextBlobCache::BlobIDCacheEntry::BlobIDCacheEntry(uint32_t id) : fID(id) {}
170
171uint32_t GrTextBlobCache::BlobIDCacheEntry::GetKey(const GrTextBlobCache::BlobIDCacheEntry& entry) {
172 return entry.fID;
173}
174
175void GrTextBlobCache::BlobIDCacheEntry::addBlob(sk_sp<GrTextBlob> blob) {
176 SkASSERT(blob);
177 SkASSERT(GrTextBlob::GetKey(*blob).fUniqueID == fID);
178 SkASSERT(!this->find(GrTextBlob::GetKey(*blob)));
179
180 fBlobs.emplace_back(std::move(blob));
181}
182
183void GrTextBlobCache::BlobIDCacheEntry::removeBlob(GrTextBlob* blob) {
184 SkASSERT(blob);
185 SkASSERT(GrTextBlob::GetKey(*blob).fUniqueID == fID);
186
187 auto index = this->findBlobIndex(GrTextBlob::GetKey(*blob));
188 SkASSERT(index >= 0);
189
190 fBlobs.removeShuffle(index);
191}
192
193sk_sp<GrTextBlob> GrTextBlobCache::BlobIDCacheEntry::find(const GrTextBlob::Key& key) const {
194 auto index = this->findBlobIndex(key);
195 return index < 0 ? nullptr : fBlobs[index];
196}
197
198int GrTextBlobCache::BlobIDCacheEntry::findBlobIndex(const GrTextBlob::Key& key) const {
199 for (int i = 0; i < fBlobs.count(); ++i) {
200 if (GrTextBlob::GetKey(*fBlobs[i]) == key) {
201 return i;
202 }
203 }
204 return -1;
205}