Purge GrTextBlobCache entries on SkTextBlob deletion

Similar to the SkImage purge mechanism.

Change-Id: I0b7fb1bad507a3c7f30a4f7514bedd894d1748ac
Reviewed-on: https://skia-review.googlesource.com/9631
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Florin Malita <fmalita@chromium.org>
This commit is contained in:
Florin Malita 2017-03-13 16:45:28 -04:00 committed by Skia Commit-Bot
parent b66b42f174
commit 4a01ac9e41
4 changed files with 63 additions and 5 deletions

View File

@ -9,6 +9,7 @@
#define SkTextBlob_DEFINED
#include "../private/SkTemplates.h"
#include "../private/SkAtomics.h"
#include "SkPaint.h"
#include "SkString.h"
#include "SkRefCnt.h"
@ -75,11 +76,19 @@ private:
static unsigned ScalarsPerGlyph(GlyphPositioning pos);
// Call when this blob is part of the key to a cache entry. This allows the cache
// to know automatically those entries can be purged when this SkTextBlob is deleted.
void notifyAddedToCache() const {
fAddedToCache.store(true);
}
friend class GrTextBlobCache;
friend class SkTextBlobBuilder;
friend class SkTextBlobRunIterator;
const SkRect fBounds;
const uint32_t fUniqueID;
const SkRect fBounds;
const uint32_t fUniqueID;
mutable SkAtomic<bool> fAddedToCache;
SkDEBUGCODE(size_t fStorageSize;)

View File

@ -11,6 +11,10 @@
#include "SkTypeface.h"
#include "SkWriteBuffer.h"
#if SK_SUPPORT_GPU
#include "text/GrTextBlobCache.h"
#endif
namespace {
// TODO(fmalita): replace with SkFont.
@ -286,10 +290,16 @@ static int32_t next_id() {
SkTextBlob::SkTextBlob(const SkRect& bounds)
: fBounds(bounds)
, fUniqueID(next_id()) {
}
, fUniqueID(next_id())
, fAddedToCache(false) {}
SkTextBlob::~SkTextBlob() {
#if SK_SUPPORT_GPU
if (fAddedToCache.load()) {
GrTextBlobCache::PostPurgeBlobMessage(fUniqueID);
}
#endif
const auto* run = RunRecord::First(this);
do {
const auto* nextRun = RunRecord::Next(run);

View File

@ -7,6 +7,8 @@
#include "GrTextBlobCache.h"
DECLARE_SKMESSAGEBUS_MESSAGE(GrTextBlobCache::PurgeBlobMessage)
GrTextBlobCache::~GrTextBlobCache() {
SkDEBUGCODE(this->freeAll();)
}
@ -24,3 +26,8 @@ void GrTextBlobCache::freeAll() {
SkASSERT(fPool.isEmpty());
SkASSERT(fBlobList.isEmpty());
}
void GrTextBlobCache::PostPurgeBlobMessage(uint32_t id) {
SkASSERT(id != SK_InvalidGenID);
SkMessageBus<PurgeBlobMessage>::Post(PurgeBlobMessage({id}));
}

View File

@ -9,6 +9,7 @@
#define GrTextBlobCache_DEFINED
#include "GrAtlasTextContext.h"
#include "SkMessageBus.h"
#include "SkRefCnt.h"
#include "SkTArray.h"
#include "SkTextBlobRunIterator.h"
@ -50,6 +51,7 @@ public:
sk_sp<GrAtlasTextBlob> cacheBlob(this->makeBlob(blob));
cacheBlob->setupKey(key, blurRec, paint);
this->add(cacheBlob);
blob->notifyAddedToCache();
return cacheBlob;
}
@ -94,6 +96,12 @@ public:
this->checkPurge();
}
struct PurgeBlobMessage {
uint32_t fID;
};
static void PostPurgeBlobMessage(uint32_t);
private:
using BitmapBlobList = SkTInternalLList<GrAtlasTextBlob>;
@ -159,7 +167,30 @@ private:
}
void checkPurge(GrAtlasTextBlob* blob = nullptr) {
// If we are overbudget, then unref until we are below budget again
// First, purge all stale blob IDs.
{
// TODO: tweak poll to allow mem-movable arrays, and update.
SkSTArray<128, PurgeBlobMessage, false> msgs;
fPurgeBlobInbox.poll(&msgs);
for (const auto& msg : msgs) {
auto* idEntry = fBlobIDCache.find(msg.fID);
if (!idEntry) {
// no cache entries for id
continue;
}
// remove all blob entries from the LRU list
for (const auto& blob : idEntry->fBlobs) {
fBlobList.remove(blob.get());
}
// drop the idEntry itself (unrefs all blobs)
fBlobIDCache.remove(msg.fID);
}
}
// If we are still overbudget, then unref until we are below budget again
if (fPool.size() > fBudget) {
BitmapBlobList::Iter iter;
iter.init(fBlobList, BitmapBlobList::Iter::kTail_IterStart);
@ -197,6 +228,7 @@ private:
PFOverBudgetCB fCallback;
void* fData;
size_t fBudget;
SkMessageBus<PurgeBlobMessage>::Inbox fPurgeBlobInbox;
};
#endif