• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 #include "src/gpu/text/GrTextBlobRedrawCoordinator.h"
9 
10 #include "src/gpu/v1/SurfaceDrawContext_v1.h"
11 
DECLARE_SKMESSAGEBUS_MESSAGE(GrTextBlobRedrawCoordinator::PurgeBlobMessage,uint32_t,true)12 DECLARE_SKMESSAGEBUS_MESSAGE(GrTextBlobRedrawCoordinator::PurgeBlobMessage, uint32_t, true)
13 
14 // This function is captured by the above macro using implementations from SkMessageBus.h
15 static inline bool SkShouldPostMessageToBus(
16         const GrTextBlobRedrawCoordinator::PurgeBlobMessage& msg, uint32_t msgBusUniqueID) {
17     return msg.fContextID == msgBusUniqueID;
18 }
19 
GrTextBlobRedrawCoordinator(uint32_t messageBusID)20 GrTextBlobRedrawCoordinator::GrTextBlobRedrawCoordinator(uint32_t messageBusID)
21         : fSizeBudget(kDefaultBudget)
22         , fMessageBusID(messageBusID)
23         , fPurgeBlobInbox(messageBusID) { }
24 
drawGlyphRunList(SkCanvas * canvas,const GrClip * clip,const SkMatrixProvider & viewMatrix,const SkGlyphRunList & glyphRunList,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc)25 void GrTextBlobRedrawCoordinator::drawGlyphRunList(SkCanvas* canvas,
26                                                    const GrClip* clip,
27                                                    const SkMatrixProvider& viewMatrix,
28                                                    const SkGlyphRunList& glyphRunList,
29                                                    const SkPaint& paint,
30                                                    skgpu::v1::SurfaceDrawContext* sdc) {
31 
32     SkMatrix positionMatrix{viewMatrix.localToDevice()};
33     positionMatrix.preTranslate(glyphRunList.origin().x(), glyphRunList.origin().y());
34 
35     GrSDFTControl control =
36             sdc->recordingContext()->priv().getSDFTControl(
37                     sdc->surfaceProps().isUseDeviceIndependentFonts());
38 
39     auto [canCache, key] = GrTextBlob::Key::Make(glyphRunList,
40                                                  paint,
41                                                  sdc->surfaceProps(),
42                                                  sdc->colorInfo(),
43                                                  positionMatrix,
44                                                  control);
45     sk_sp<GrTextBlob> blob;
46     if (canCache) {
47         blob = this->find(key);
48     }
49 
50     if (blob == nullptr || !blob->canReuse(paint, positionMatrix)) {
51         if (blob != nullptr) {
52             // We have to remake the blob because changes may invalidate our masks.
53             this->remove(blob.get());
54         }
55 
56         const bool padAtlas =
57                 sdc->recordingContext()->priv().options().fSupportBilerpFromGlyphAtlas;
58         blob = GrTextBlob::Make(
59                 glyphRunList, paint, positionMatrix, padAtlas, control, sdc->glyphRunPainter());
60 
61         if (canCache) {
62             blob->addKey(key);
63             // The blob may already have been created on a different thread. Use the first one
64             // that was there.
65             blob = this->addOrReturnExisting(glyphRunList, blob);
66         }
67     }
68 
69     blob->draw(canvas, clip, viewMatrix, glyphRunList.origin(), paint, sdc);
70 }
71 
addOrReturnExisting(const SkGlyphRunList & glyphRunList,sk_sp<GrTextBlob> blob)72 sk_sp<GrTextBlob> GrTextBlobRedrawCoordinator::addOrReturnExisting(
73         const SkGlyphRunList& glyphRunList, sk_sp<GrTextBlob> blob) {
74     SkAutoSpinlock lock{fSpinLock};
75     blob = this->internalAdd(std::move(blob));
76     glyphRunList.temporaryShuntBlobNotifyAddedToCache(fMessageBusID);
77     return blob;
78 }
79 
find(const GrTextBlob::Key & key)80 sk_sp<GrTextBlob> GrTextBlobRedrawCoordinator::find(const GrTextBlob::Key& key) {
81     SkAutoSpinlock lock{fSpinLock};
82     const BlobIDCacheEntry* idEntry = fBlobIDCache.find(key.fUniqueID);
83     if (idEntry == nullptr) {
84         return nullptr;
85     }
86 
87     sk_sp<GrTextBlob> blob = idEntry->find(key);
88     GrTextBlob* blobPtr = blob.get();
89     if (blobPtr != nullptr && blobPtr != fBlobList.head()) {
90         fBlobList.remove(blobPtr);
91         fBlobList.addToHead(blobPtr);
92     }
93     return blob;
94 }
95 
remove(GrTextBlob * blob)96 void GrTextBlobRedrawCoordinator::remove(GrTextBlob* blob) {
97     SkAutoSpinlock lock{fSpinLock};
98     this->internalRemove(blob);
99 }
100 
internalRemove(GrTextBlob * blob)101 void GrTextBlobRedrawCoordinator::internalRemove(GrTextBlob* blob) {
102     auto  id      = blob->key().fUniqueID;
103     auto* idEntry = fBlobIDCache.find(id);
104 
105     if (idEntry != nullptr) {
106         sk_sp<GrTextBlob> stillExists = idEntry->find(blob->key());
107         if (blob == stillExists.get())  {
108             fCurrentSize -= blob->size();
109             fBlobList.remove(blob);
110             idEntry->removeBlob(blob);
111             if (idEntry->fBlobs.empty()) {
112                 fBlobIDCache.remove(id);
113             }
114         }
115     }
116 }
117 
freeAll()118 void GrTextBlobRedrawCoordinator::freeAll() {
119     SkAutoSpinlock lock{fSpinLock};
120     fBlobIDCache.reset();
121     fBlobList.reset();
122     fCurrentSize = 0;
123 }
124 
PostPurgeBlobMessage(uint32_t blobID,uint32_t cacheID)125 void GrTextBlobRedrawCoordinator::PostPurgeBlobMessage(uint32_t blobID, uint32_t cacheID) {
126     SkASSERT(blobID != SK_InvalidGenID);
127     SkMessageBus<PurgeBlobMessage, uint32_t>::Post(PurgeBlobMessage(blobID, cacheID));
128 }
129 
purgeStaleBlobs()130 void GrTextBlobRedrawCoordinator::purgeStaleBlobs() {
131     SkAutoSpinlock lock{fSpinLock};
132     this->internalPurgeStaleBlobs();
133 }
134 
internalPurgeStaleBlobs()135 void GrTextBlobRedrawCoordinator::internalPurgeStaleBlobs() {
136     SkTArray<PurgeBlobMessage> msgs;
137     fPurgeBlobInbox.poll(&msgs);
138 
139     for (const auto& msg : msgs) {
140         auto* idEntry = fBlobIDCache.find(msg.fBlobID);
141         if (!idEntry) {
142             // no cache entries for id
143             continue;
144         }
145 
146         // remove all blob entries from the LRU list
147         for (const auto& blob : idEntry->fBlobs) {
148             fCurrentSize -= blob->size();
149             fBlobList.remove(blob.get());
150         }
151 
152         // drop the idEntry itself (unrefs all blobs)
153         fBlobIDCache.remove(msg.fBlobID);
154     }
155 }
156 
usedBytes() const157 size_t GrTextBlobRedrawCoordinator::usedBytes() const {
158     SkAutoSpinlock lock{fSpinLock};
159     return fCurrentSize;
160 }
161 
isOverBudget() const162 bool GrTextBlobRedrawCoordinator::isOverBudget() const {
163     SkAutoSpinlock lock{fSpinLock};
164     return fCurrentSize > fSizeBudget;
165 }
166 
internalCheckPurge(GrTextBlob * blob)167 void GrTextBlobRedrawCoordinator::internalCheckPurge(GrTextBlob* blob) {
168     // First, purge all stale blob IDs.
169     this->internalPurgeStaleBlobs();
170 
171     // If we are still over budget, then unref until we are below budget again
172     if (fCurrentSize > fSizeBudget) {
173         TextBlobList::Iter iter;
174         iter.init(fBlobList, TextBlobList::Iter::kTail_IterStart);
175         GrTextBlob* lruBlob = nullptr;
176         while (fCurrentSize > fSizeBudget && (lruBlob = iter.get()) && lruBlob != blob) {
177             // Backup the iterator before removing and unrefing the blob
178             iter.prev();
179 
180             this->internalRemove(lruBlob);
181         }
182 
183     #ifdef SPEW_BUDGET_MESSAGE
184         if (fCurrentSize > fSizeBudget) {
185             SkDebugf("Single textblob is larger than our whole budget");
186         }
187     #endif
188     }
189 }
190 
internalAdd(sk_sp<GrTextBlob> blob)191 sk_sp<GrTextBlob> GrTextBlobRedrawCoordinator::internalAdd(sk_sp<GrTextBlob> blob) {
192     auto  id      = blob->key().fUniqueID;
193     auto* idEntry = fBlobIDCache.find(id);
194     if (!idEntry) {
195         idEntry = fBlobIDCache.set(id, BlobIDCacheEntry(id));
196     }
197 
198     if (sk_sp<GrTextBlob> alreadyIn = idEntry->find(blob->key()); alreadyIn) {
199         blob = std::move(alreadyIn);
200     } else {
201         fBlobList.addToHead(blob.get());
202         fCurrentSize += blob->size();
203         idEntry->addBlob(blob);
204     }
205 
206     this->internalCheckPurge(blob.get());
207     return blob;
208 }
209 
BlobIDCacheEntry()210 GrTextBlobRedrawCoordinator::BlobIDCacheEntry::BlobIDCacheEntry() : fID(SK_InvalidGenID) {}
211 
BlobIDCacheEntry(uint32_t id)212 GrTextBlobRedrawCoordinator::BlobIDCacheEntry::BlobIDCacheEntry(uint32_t id) : fID(id) {}
213 
GetKey(const GrTextBlobRedrawCoordinator::BlobIDCacheEntry & entry)214 uint32_t GrTextBlobRedrawCoordinator::BlobIDCacheEntry::GetKey(
215         const GrTextBlobRedrawCoordinator::BlobIDCacheEntry& entry) {
216     return entry.fID;
217 }
218 
addBlob(sk_sp<GrTextBlob> blob)219 void GrTextBlobRedrawCoordinator::BlobIDCacheEntry::addBlob(sk_sp<GrTextBlob> blob) {
220     SkASSERT(blob);
221     SkASSERT(blob->key().fUniqueID == fID);
222     SkASSERT(!this->find(blob->key()));
223 
224     fBlobs.emplace_back(std::move(blob));
225 }
226 
removeBlob(GrTextBlob * blob)227 void GrTextBlobRedrawCoordinator::BlobIDCacheEntry::removeBlob(GrTextBlob* blob) {
228     SkASSERT(blob);
229     SkASSERT(blob->key().fUniqueID == fID);
230 
231     auto index = this->findBlobIndex(blob->key());
232     SkASSERT(index >= 0);
233 
234     fBlobs.removeShuffle(index);
235 }
236 
237 sk_sp<GrTextBlob>
find(const GrTextBlob::Key & key) const238 GrTextBlobRedrawCoordinator::BlobIDCacheEntry::find(const GrTextBlob::Key& key) const {
239     auto index = this->findBlobIndex(key);
240     return index < 0 ? nullptr : fBlobs[index];
241 }
242 
findBlobIndex(const GrTextBlob::Key & key) const243 int GrTextBlobRedrawCoordinator::BlobIDCacheEntry::findBlobIndex(const GrTextBlob::Key& key) const {
244     for (int i = 0; i < fBlobs.count(); ++i) {
245         if (fBlobs[i]->key() == key) {
246             return i;
247         }
248     }
249     return -1;
250 }
251