blob: 815a775f9c854ba3938006a2a0042804313fa4db [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 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 Derby00b2fdb2020-09-03 11:54:01 -040023void GrTextBlobCache::add(const SkGlyphRunList& glyphRunList, sk_sp<GrTextBlob> blob) {
Herb Derby13e3fae2020-07-23 13:24:53 -040024 SkAutoSpinlock lock{fSpinLock};
Herb Derby00b2fdb2020-09-03 11:54:01 -040025 this->internalAdd(std::move(blob));
Herb Derbya50830b2020-05-21 14:01:09 -040026 glyphRunList.temporaryShuntBlobNotifyAddedToCache(fMessageBusID);
Herb Derby7b4ea9b2020-05-20 17:31:36 -040027}
28
Herb Derby13e3fae2020-07-23 13:24:53 -040029sk_sp<GrTextBlob> GrTextBlobCache::find(const GrTextBlob::Key& key) {
30 SkAutoSpinlock lock{fSpinLock};
31 const BlobIDCacheEntry* idEntry = fBlobIDCache.find(key.fUniqueID);
32 if (idEntry == nullptr) {
33 return nullptr;
34 }
35
36 sk_sp<GrTextBlob> blob = idEntry->find(key);
37 GrTextBlob* blobPtr = blob.get();
38 if (blobPtr != nullptr && blobPtr != fBlobList.head()) {
39 fBlobList.remove(blobPtr);
40 fBlobList.addToHead(blobPtr);
41 }
42 return blob;
Herb Derby7b4ea9b2020-05-20 17:31:36 -040043}
44
45void GrTextBlobCache::remove(GrTextBlob* blob) {
Herb Derby13e3fae2020-07-23 13:24:53 -040046 SkAutoSpinlock lock{fSpinLock};
Herb Derbyc5f25bc2020-06-23 14:02:23 -040047 this->internalRemove(blob);
48}
49
50void GrTextBlobCache::internalRemove(GrTextBlob* blob) {
Herb Derby7b4ea9b2020-05-20 17:31:36 -040051 auto id = GrTextBlob::GetKey(*blob).fUniqueID;
52 auto* idEntry = fBlobIDCache.find(id);
53 SkASSERT(idEntry);
54
55 fCurrentSize -= blob->size();
56 fBlobList.remove(blob);
57 idEntry->removeBlob(blob);
58 if (idEntry->fBlobs.empty()) {
59 fBlobIDCache.remove(id);
60 }
61}
62
joshualitt26ffc002015-04-16 11:24:04 -070063void GrTextBlobCache::freeAll() {
Herb Derby13e3fae2020-07-23 13:24:53 -040064 SkAutoSpinlock lock{fSpinLock};
Florin Malita33fdb8d2017-03-07 16:51:57 -050065 fBlobIDCache.reset();
Herb Derbyadac2882020-06-23 12:45:15 -040066 fBlobList.reset();
Herb Derbyb12175f2018-05-23 16:38:09 -040067 fCurrentSize = 0;
joshualitt26ffc002015-04-16 11:24:04 -070068}
Florin Malita4a01ac92017-03-13 16:45:28 -040069
Jim Van Verth474d6872017-12-14 13:00:05 -050070void GrTextBlobCache::PostPurgeBlobMessage(uint32_t blobID, uint32_t cacheID) {
71 SkASSERT(blobID != SK_InvalidGenID);
Brian Salomon238069b2018-07-11 15:58:57 -040072 SkMessageBus<PurgeBlobMessage>::Post(PurgeBlobMessage(blobID, cacheID));
Florin Malita4a01ac92017-03-13 16:45:28 -040073}
Jim Van Verth76d917c2017-12-13 09:26:37 -050074
75void GrTextBlobCache::purgeStaleBlobs() {
Herb Derby13e3fae2020-07-23 13:24:53 -040076 SkAutoSpinlock lock{fSpinLock};
Herb Derbyc5f25bc2020-06-23 14:02:23 -040077 this->internalPurgeStaleBlobs();
78}
79
80void GrTextBlobCache::internalPurgeStaleBlobs() {
Jim Van Verth76d917c2017-12-13 09:26:37 -050081 SkTArray<PurgeBlobMessage> msgs;
82 fPurgeBlobInbox.poll(&msgs);
83
84 for (const auto& msg : msgs) {
Brian Salomon238069b2018-07-11 15:58:57 -040085 auto* idEntry = fBlobIDCache.find(msg.fBlobID);
Jim Van Verth76d917c2017-12-13 09:26:37 -050086 if (!idEntry) {
87 // no cache entries for id
88 continue;
89 }
90
91 // remove all blob entries from the LRU list
92 for (const auto& blob : idEntry->fBlobs) {
Herb Derbyb12175f2018-05-23 16:38:09 -040093 fCurrentSize -= blob->size();
Jim Van Verth76d917c2017-12-13 09:26:37 -050094 fBlobList.remove(blob.get());
95 }
96
97 // drop the idEntry itself (unrefs all blobs)
Brian Salomon238069b2018-07-11 15:58:57 -040098 fBlobIDCache.remove(msg.fBlobID);
Jim Van Verth76d917c2017-12-13 09:26:37 -050099 }
100}
101
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400102size_t GrTextBlobCache::usedBytes() const {
Herb Derby13e3fae2020-07-23 13:24:53 -0400103 SkAutoSpinlock lock{fSpinLock};
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400104 return fCurrentSize;
105}
106
Herb Derby1ca54d42020-06-26 12:50:38 -0400107bool GrTextBlobCache::isOverBudget() const {
Herb Derby13e3fae2020-07-23 13:24:53 -0400108 SkAutoSpinlock lock{fSpinLock};
Herb Derby1ca54d42020-06-26 12:50:38 -0400109 return fCurrentSize > fSizeBudget;
110}
111
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400112void GrTextBlobCache::internalCheckPurge(GrTextBlob* blob) {
Jim Van Verth76d917c2017-12-13 09:26:37 -0500113 // First, purge all stale blob IDs.
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400114 this->internalPurgeStaleBlobs();
Jim Van Verth76d917c2017-12-13 09:26:37 -0500115
116 // If we are still over budget, then unref until we are below budget again
Herb Derbyb12175f2018-05-23 16:38:09 -0400117 if (fCurrentSize > fSizeBudget) {
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400118 TextBlobList::Iter iter;
119 iter.init(fBlobList, TextBlobList::Iter::kTail_IterStart);
Herb Derby86240592018-05-24 16:12:31 -0400120 GrTextBlob* lruBlob = nullptr;
Herb Derbyb12175f2018-05-23 16:38:09 -0400121 while (fCurrentSize > fSizeBudget && (lruBlob = iter.get()) && lruBlob != blob) {
Jim Van Verth76d917c2017-12-13 09:26:37 -0500122 // Backup the iterator before removing and unrefing the blob
123 iter.prev();
124
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400125 this->internalRemove(lruBlob);
Jim Van Verth76d917c2017-12-13 09:26:37 -0500126 }
127
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400128 #ifdef SPEW_BUDGET_MESSAGE
Herb Derbyb12175f2018-05-23 16:38:09 -0400129 if (fCurrentSize > fSizeBudget) {
Jim Van Verth76d917c2017-12-13 09:26:37 -0500130 SkDebugf("Single textblob is larger than our whole budget");
131 }
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400132 #endif
Jim Van Verth76d917c2017-12-13 09:26:37 -0500133 }
134}
135
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400136void GrTextBlobCache::internalAdd(sk_sp<GrTextBlob> blob) {
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400137 auto id = GrTextBlob::GetKey(*blob).fUniqueID;
138 auto* idEntry = fBlobIDCache.find(id);
139 if (!idEntry) {
140 idEntry = fBlobIDCache.set(id, BlobIDCacheEntry(id));
141 }
Jim Van Verth76d917c2017-12-13 09:26:37 -0500142
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400143 // Safe to retain a raw ptr temporarily here, because the cache will hold a ref.
144 GrTextBlob* rawBlobPtr = blob.get();
145 fBlobList.addToHead(rawBlobPtr);
146 fCurrentSize += blob->size();
147 idEntry->addBlob(std::move(blob));
Jim Van Verth76d917c2017-12-13 09:26:37 -0500148
Herb Derbyc5f25bc2020-06-23 14:02:23 -0400149 this->internalCheckPurge(rawBlobPtr);
Herb Derby7b4ea9b2020-05-20 17:31:36 -0400150}
151
152GrTextBlobCache::BlobIDCacheEntry::BlobIDCacheEntry() : fID(SK_InvalidGenID) {}
153
154GrTextBlobCache::BlobIDCacheEntry::BlobIDCacheEntry(uint32_t id) : fID(id) {}
155
156uint32_t GrTextBlobCache::BlobIDCacheEntry::GetKey(const GrTextBlobCache::BlobIDCacheEntry& entry) {
157 return entry.fID;
158}
159
160void GrTextBlobCache::BlobIDCacheEntry::addBlob(sk_sp<GrTextBlob> blob) {
161 SkASSERT(blob);
162 SkASSERT(GrTextBlob::GetKey(*blob).fUniqueID == fID);
163 SkASSERT(!this->find(GrTextBlob::GetKey(*blob)));
164
165 fBlobs.emplace_back(std::move(blob));
166}
167
168void GrTextBlobCache::BlobIDCacheEntry::removeBlob(GrTextBlob* blob) {
169 SkASSERT(blob);
170 SkASSERT(GrTextBlob::GetKey(*blob).fUniqueID == fID);
171
172 auto index = this->findBlobIndex(GrTextBlob::GetKey(*blob));
173 SkASSERT(index >= 0);
174
175 fBlobs.removeShuffle(index);
176}
177
178sk_sp<GrTextBlob> GrTextBlobCache::BlobIDCacheEntry::find(const GrTextBlob::Key& key) const {
179 auto index = this->findBlobIndex(key);
180 return index < 0 ? nullptr : fBlobs[index];
181}
182
183int GrTextBlobCache::BlobIDCacheEntry::findBlobIndex(const GrTextBlob::Key& key) const {
184 for (int i = 0; i < fBlobs.count(); ++i) {
185 if (GrTextBlob::GetKey(*fBlobs[i]) == key) {
186 return i;
187 }
188 }
189 return -1;
190}