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 "GrTextBlobCache.h" 9 10 DECLARE_SKMESSAGEBUS_MESSAGE(GrTextBlobCache::PurgeBlobMessage) 11 12 static inline bool SkShouldPostMessageToBus( 13 const GrTextBlobCache::PurgeBlobMessage& msg, uint32_t msgBusUniqueID) { 14 return msg.fContextID == msgBusUniqueID; 15 } 16 17 GrTextBlobCache::~GrTextBlobCache() { 18 this->freeAll(); 19 } 20 21 void 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 36 void GrTextBlobCache::PostPurgeBlobMessage(uint32_t blobID, uint32_t cacheID) { 37 SkASSERT(blobID != SK_InvalidGenID); 38 SkMessageBus<PurgeBlobMessage>::Post(PurgeBlobMessage(blobID, cacheID)); 39 } 40 41 void 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 63 void 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