blob: e7cca260b9c293f99f2c0132981eb6f2aeff23c1 [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
Robert Phillipse7a959d2021-03-11 14:44:42 -050010DECLARE_SKMESSAGEBUS_MESSAGE(GrTextBlobCache::PurgeBlobMessage, uint32_t, true)
Florin Malita4a01ac92017-03-13 16:45:28 -040011
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 Derby1ca54d42020-06-26 12:50:38 -040018GrTextBlobCache::GrTextBlobCache(uint32_t messageBusID)
19 : fSizeBudget(kDefaultBudget)
Herb Derbya50830b2020-05-21 14:01:09 -040020 , fMessageBusID(messageBusID)
21 , fPurgeBlobInbox(messageBusID) { }
Herb Derby7b4ea9b2020-05-20 17:31:36 -040022
Herb Derby9553a572021-02-24 09:28:31 -050023sk_sp<GrTextBlob> GrTextBlobCache::addOrReturnExisting(
24 const SkGlyphRunList& glyphRunList, sk_sp<GrTextBlob> blob) {
Herb Derby13e3fae2020-07-23 13:24:53 -040025 SkAutoSpinlock lock{fSpinLock};
Herb Derby9553a572021-02-24 09:28:31 -050026 blob = this->internalAdd(std::move(blob));
Herb Derbya50830b2020-05-21 14:01:09 -040027 glyphRunList.temporaryShuntBlobNotifyAddedToCache(fMessageBusID);
Herb Derby9553a572021-02-24 09:28:31 -050028 return blob;
Herb Derby7b4ea9b2020-05-20 17:31:36 -040029}
30
Herb Derby13e3fae2020-07-23 13:24:53 -040031sk_sp<GrTextBlob> GrTextBlobCache::find(const GrTextBlob::Key& key) {
32 SkAutoSpinlock lock{fSpinLock};
33 const BlobIDCacheEntry* idEntry = fBlobIDCache.find(key.fUniqueID);
34 if (idEntry == nullptr) {
35 return nullptr;
36 }
37
38 sk_sp<GrTextBlob> blob = idEntry->find(key);
39 GrTextBlob* blobPtr = blob.get();
40 if (blobPtr != nullptr && blobPtr != fBlobList.head()) {
41 fBlobList.remove(blobPtr);
42 fBlobList.addToHead(blobPtr);
43 }
44 return blob;
Herb Derby7b4ea9b2020-05-20 17:31:36 -040045}
46
47void GrTextBlobCache::remove(GrTextBlob* blob) {
Herb Derby13e3fae2020-07-23 13:24:53 -040048 SkAutoSpinlock lock{fSpinLock};
Herb Derbyc5f25bc2020-06-23 14:02:23 -040049 this->internalRemove(blob);
50}
51
52void GrTextBlobCache::internalRemove(GrTextBlob* blob) {
Herb Derbyc8e31ea2021-03-08 12:42:17 -050053 auto id = blob->key().fUniqueID;
Herb Derby7b4ea9b2020-05-20 17:31:36 -040054 auto* idEntry = fBlobIDCache.find(id);
Herb Derby7b4ea9b2020-05-20 17:31:36 -040055
Herb Derbyc15c19c2021-02-24 14:54:24 -050056 if (idEntry != nullptr) {
57 sk_sp<GrTextBlob> stillExists = idEntry->find(blob->key());
58 if (blob == stillExists.get()) {
59 fCurrentSize -= blob->size();
60 fBlobList.remove(blob);
61 idEntry->removeBlob(blob);
62 if (idEntry->fBlobs.empty()) {
63 fBlobIDCache.remove(id);
64 }
65 }
Herb Derby7b4ea9b2020-05-20 17:31:36 -040066 }
67}
68
joshualitt26ffc002015-04-16 11:24:04 -070069void GrTextBlobCache::freeAll() {
Herb Derby13e3fae2020-07-23 13:24:53 -040070 SkAutoSpinlock lock{fSpinLock};
Florin Malita33fdb8d2017-03-07 16:51:57 -050071 fBlobIDCache.reset();
Herb Derbyadac2882020-06-23 12:45:15 -040072 fBlobList.reset();
Herb Derbyb12175f2018-05-23 16:38:09 -040073 fCurrentSize = 0;
joshualitt26ffc002015-04-16 11:24:04 -070074}
Florin Malita4a01ac92017-03-13 16:45:28 -040075
Jim Van Verth474d6872017-12-14 13:00:05 -050076void GrTextBlobCache::PostPurgeBlobMessage(uint32_t blobID, uint32_t cacheID) {
77 SkASSERT(blobID != SK_InvalidGenID);
Robert Phillipse7a959d2021-03-11 14:44:42 -050078 SkMessageBus<PurgeBlobMessage, uint32_t>::Post(PurgeBlobMessage(blobID, cacheID));
Florin Malita4a01ac92017-03-13 16:45:28 -040079}
Jim Van Verth76d917c2017-12-13 09:26:37 -050080
81void GrTextBlobCache::purgeStaleBlobs() {
Herb Derby13e3fae2020-07-23 13:24:53 -040082 SkAutoSpinlock lock{fSpinLock};
Herb Derbyc5f25bc2020-06-23 14:02:23 -040083 this->internalPurgeStaleBlobs();
84}
85
86void GrTextBlobCache::internalPurgeStaleBlobs() {
Jim Van Verth76d917c2017-12-13 09:26:37 -050087 SkTArray<PurgeBlobMessage> msgs;
88 fPurgeBlobInbox.poll(&msgs);
89
90 for (const auto& msg : msgs) {
Brian Salomon238069b2018-07-11 15:58:57 -040091 auto* idEntry = fBlobIDCache.find(msg.fBlobID);
Jim Van Verth76d917c2017-12-13 09:26:37 -050092 if (!idEntry) {
93 // no cache entries for id
94 continue;
95 }
96
97 // remove all blob entries from the LRU list
98 for (const auto& blob : idEntry->fBlobs) {
Herb Derbyb12175f2018-05-23 16:38:09 -040099 fCurrentSize -= blob->size();
Jim Van Verth76d917c2017-12-13 09:26:37 -0500100 fBlobList.remove(blob.get());
101 }
102
103 // drop the idEntry itself (unrefs all blobs)
Brian Salomon238069b2018-07-11 15:58:57 -0400104 fBlobIDCache.remove(msg.fBlobID);
Jim Van Verth76d917c2017-12-13 09:26:37 -0500105 }
106}
107
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400108size_t GrTextBlobCache::usedBytes() const {
Herb Derby13e3fae2020-07-23 13:24:53 -0400109 SkAutoSpinlock lock{fSpinLock};
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400110 return fCurrentSize;
111}
112
Herb Derby1ca54d42020-06-26 12:50:38 -0400113bool GrTextBlobCache::isOverBudget() const {
Herb Derby13e3fae2020-07-23 13:24:53 -0400114 SkAutoSpinlock lock{fSpinLock};
Herb Derby1ca54d42020-06-26 12:50:38 -0400115 return fCurrentSize > fSizeBudget;
116}
117
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400118void GrTextBlobCache::internalCheckPurge(GrTextBlob* blob) {
Jim Van Verth76d917c2017-12-13 09:26:37 -0500119 // First, purge all stale blob IDs.
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400120 this->internalPurgeStaleBlobs();
Jim Van Verth76d917c2017-12-13 09:26:37 -0500121
122 // If we are still over budget, then unref until we are below budget again
Herb Derbyb12175f2018-05-23 16:38:09 -0400123 if (fCurrentSize > fSizeBudget) {
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400124 TextBlobList::Iter iter;
125 iter.init(fBlobList, TextBlobList::Iter::kTail_IterStart);
Herb Derby86240592018-05-24 16:12:31 -0400126 GrTextBlob* lruBlob = nullptr;
Herb Derbyb12175f2018-05-23 16:38:09 -0400127 while (fCurrentSize > fSizeBudget && (lruBlob = iter.get()) && lruBlob != blob) {
Jim Van Verth76d917c2017-12-13 09:26:37 -0500128 // Backup the iterator before removing and unrefing the blob
129 iter.prev();
130
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400131 this->internalRemove(lruBlob);
Jim Van Verth76d917c2017-12-13 09:26:37 -0500132 }
133
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400134 #ifdef SPEW_BUDGET_MESSAGE
Herb Derbyb12175f2018-05-23 16:38:09 -0400135 if (fCurrentSize > fSizeBudget) {
Jim Van Verth76d917c2017-12-13 09:26:37 -0500136 SkDebugf("Single textblob is larger than our whole budget");
137 }
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400138 #endif
Jim Van Verth76d917c2017-12-13 09:26:37 -0500139 }
140}
141
Herb Derby9553a572021-02-24 09:28:31 -0500142sk_sp<GrTextBlob> GrTextBlobCache::internalAdd(sk_sp<GrTextBlob> blob) {
Herb Derbyc8e31ea2021-03-08 12:42:17 -0500143 auto id = blob->key().fUniqueID;
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400144 auto* idEntry = fBlobIDCache.find(id);
145 if (!idEntry) {
146 idEntry = fBlobIDCache.set(id, BlobIDCacheEntry(id));
147 }
Jim Van Verth76d917c2017-12-13 09:26:37 -0500148
Herb Derbyc8e31ea2021-03-08 12:42:17 -0500149 if (sk_sp<GrTextBlob> alreadyIn = idEntry->find(blob->key()); alreadyIn) {
Herb Derby9553a572021-02-24 09:28:31 -0500150 blob = std::move(alreadyIn);
151 } else {
152 fBlobList.addToHead(blob.get());
153 fCurrentSize += blob->size();
154 idEntry->addBlob(blob);
155 }
Jim Van Verth76d917c2017-12-13 09:26:37 -0500156
Herb Derby9553a572021-02-24 09:28:31 -0500157 this->internalCheckPurge(blob.get());
158 return blob;
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400159}
160
161GrTextBlobCache::BlobIDCacheEntry::BlobIDCacheEntry() : fID(SK_InvalidGenID) {}
162
163GrTextBlobCache::BlobIDCacheEntry::BlobIDCacheEntry(uint32_t id) : fID(id) {}
164
165uint32_t GrTextBlobCache::BlobIDCacheEntry::GetKey(const GrTextBlobCache::BlobIDCacheEntry& entry) {
166 return entry.fID;
167}
168
169void GrTextBlobCache::BlobIDCacheEntry::addBlob(sk_sp<GrTextBlob> blob) {
170 SkASSERT(blob);
Herb Derbyc8e31ea2021-03-08 12:42:17 -0500171 SkASSERT(blob->key().fUniqueID == fID);
172 SkASSERT(!this->find(blob->key()));
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400173
174 fBlobs.emplace_back(std::move(blob));
175}
176
177void GrTextBlobCache::BlobIDCacheEntry::removeBlob(GrTextBlob* blob) {
178 SkASSERT(blob);
Herb Derbyc8e31ea2021-03-08 12:42:17 -0500179 SkASSERT(blob->key().fUniqueID == fID);
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400180
Herb Derbyc8e31ea2021-03-08 12:42:17 -0500181 auto index = this->findBlobIndex(blob->key());
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400182 SkASSERT(index >= 0);
183
184 fBlobs.removeShuffle(index);
185}
186
187sk_sp<GrTextBlob> GrTextBlobCache::BlobIDCacheEntry::find(const GrTextBlob::Key& key) const {
188 auto index = this->findBlobIndex(key);
189 return index < 0 ? nullptr : fBlobs[index];
190}
191
192int GrTextBlobCache::BlobIDCacheEntry::findBlobIndex(const GrTextBlob::Key& key) const {
193 for (int i = 0; i < fBlobs.count(); ++i) {
Herb Derbyc8e31ea2021-03-08 12:42:17 -0500194 if (fBlobs[i]->key() == key) {
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400195 return i;
196 }
197 }
198 return -1;
199}