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/GrTextBlobCache.h"
9
10DECLARE_SKMESSAGEBUS_MESSAGE(GrTextBlobCache::PurgeBlobMessage)
11
12static inline bool SkShouldPostMessageToBus(
13 const GrTextBlobCache::PurgeBlobMessage& msg, uint32_t msgBusUniqueID) {
14 return msg.fContextID == msgBusUniqueID;
15}
16
17GrTextBlobCache::~GrTextBlobCache() {
18 this->freeAll();
19}
20
21void GrTextBlobCache::freeAll() {
22 fBlobIDCache.foreach([this](uint32_t, BlobIDCacheEntry* entry) {
23 for (const auto& blob : entry->fBlobs) {
24 fBlobList.remove(blob.get());
25 }
26 });
27
28 fBlobIDCache.reset();
29
30 fCurrentSize = 0;
31
32 // There should be no allocations in the memory pool at this point
33 SkASSERT(fBlobList.isEmpty());
34}
35
36void GrTextBlobCache::PostPurgeBlobMessage(uint32_t blobID, uint32_t cacheID) {
37 SkASSERT(blobID != SK_InvalidGenID);
38 SkMessageBus<PurgeBlobMessage>::Post(PurgeBlobMessage(blobID, cacheID));
39}
40
41void GrTextBlobCache::purgeStaleBlobs() {
42 SkTArray<PurgeBlobMessage> msgs;
43 fPurgeBlobInbox.poll(&msgs);
44
45 for (const auto& msg : msgs) {
46 auto* idEntry = fBlobIDCache.find(msg.fBlobID);
47 if (!idEntry) {
48 // no cache entries for id
49 continue;
50 }
51
52 // remove all blob entries from the LRU list
53 for (const auto& blob : idEntry->fBlobs) {
54 fCurrentSize -= blob->size();
55 fBlobList.remove(blob.get());
56 }
57
58 // drop the idEntry itself (unrefs all blobs)
59 fBlobIDCache.remove(msg.fBlobID);
60 }
61}
62
63void GrTextBlobCache::checkPurge(GrTextBlob* blob) {
64 // First, purge all stale blob IDs.
65 this->purgeStaleBlobs();
66
67 // If we are still over budget, then unref until we are below budget again
68 if (fCurrentSize > fSizeBudget) {
69 BitmapBlobList::Iter iter;
70 iter.init(fBlobList, BitmapBlobList::Iter::kTail_IterStart);
71 GrTextBlob* lruBlob = nullptr;
72 while (fCurrentSize > fSizeBudget && (lruBlob = iter.get()) && lruBlob != blob) {
73 // Backup the iterator before removing and unrefing the blob
74 iter.prev();
75
76 this->remove(lruBlob);
77 }
78
79 // If we break out of the loop with lruBlob == blob, then we haven't purged enough
80 // use the call back and try to free some more. If we are still overbudget after this,
81 // then this single textblob is over our budget
82 if (blob && lruBlob == blob) {
83 (*fCallback)(fData);
84 }
85
86#ifdef SPEW_BUDGET_MESSAGE
87 if (fCurrentSize > fSizeBudget) {
88 SkDebugf("Single textblob is larger than our whole budget");
89 }
90#endif
91 }
92}
93
94
95
96