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