diff options
author | joshualitt <joshualitt@chromium.org> | 2015-12-11 06:11:21 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-12-11 06:11:21 -0800 |
commit | e804292e805917002cc3d7baa7f967fb20d2c7cb (patch) | |
tree | 5470bacbebdec462e03929dd07d1955249b31230 /src/gpu/text/GrTextBlobCache.h | |
parent | 296779832fd6175547d991ca67c735a824cadb66 (diff) |
Move all text stuff to its own folder
BUG=skia:
Review URL: https://codereview.chromium.org/1521453002
Diffstat (limited to 'src/gpu/text/GrTextBlobCache.h')
-rw-r--r-- | src/gpu/text/GrTextBlobCache.h | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/src/gpu/text/GrTextBlobCache.h b/src/gpu/text/GrTextBlobCache.h new file mode 100644 index 0000000000..8eee9d13db --- /dev/null +++ b/src/gpu/text/GrTextBlobCache.h @@ -0,0 +1,158 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTextBlobCache_DEFINED +#define GrTextBlobCache_DEFINED + +#include "GrAtlasTextContext.h" +#include "SkTDynamicHash.h" +#include "SkTextBlobRunIterator.h" + +class GrTextBlobCache { +public: + /** + * The callback function used by the cache when it is still over budget after a purge. The + * passed in 'data' is the same 'data' handed to setOverbudgetCallback. + */ + typedef void (*PFOverBudgetCB)(void* data); + + GrTextBlobCache(PFOverBudgetCB cb, void* data) + : fPool(kPreAllocSize, kMinGrowthSize) + , fCallback(cb) + , fData(data) + , fBudget(kDefaultBudget) { + SkASSERT(cb && data); + } + ~GrTextBlobCache(); + + // creates an uncached blob + GrAtlasTextBlob* createBlob(int glyphCount, int runCount, size_t maxVASize); + GrAtlasTextBlob* createBlob(const SkTextBlob* blob, size_t maxVAStride) { + int glyphCount = 0; + int runCount = 0; + BlobGlyphCount(&glyphCount, &runCount, blob); + GrAtlasTextBlob* cacheBlob = this->createBlob(glyphCount, runCount, maxVAStride); + return cacheBlob; + } + + static void SetupCacheBlobKey(GrAtlasTextBlob* cacheBlob, + const GrAtlasTextBlob::Key& key, + const SkMaskFilter::BlurRec& blurRec, + const SkPaint& paint) { + cacheBlob->fKey = key; + if (key.fHasBlur) { + cacheBlob->fBlurRec = blurRec; + } + if (key.fStyle != SkPaint::kFill_Style) { + cacheBlob->fStrokeInfo.fFrameWidth = paint.getStrokeWidth(); + cacheBlob->fStrokeInfo.fMiterLimit = paint.getStrokeMiter(); + cacheBlob->fStrokeInfo.fJoin = paint.getStrokeJoin(); + } + } + + GrAtlasTextBlob* createCachedBlob(const SkTextBlob* blob, + const GrAtlasTextBlob::Key& key, + const SkMaskFilter::BlurRec& blurRec, + const SkPaint& paint, + size_t maxVAStride) { + int glyphCount = 0; + int runCount = 0; + BlobGlyphCount(&glyphCount, &runCount, blob); + GrAtlasTextBlob* cacheBlob = this->createBlob(glyphCount, runCount, maxVAStride); + SetupCacheBlobKey(cacheBlob, key, blurRec, paint); + this->add(cacheBlob); + return cacheBlob; + } + + GrAtlasTextBlob* find(const GrAtlasTextBlob::Key& key) { + return fCache.find(key); + } + + void remove(GrAtlasTextBlob* blob) { + fCache.remove(blob->fKey); + fBlobList.remove(blob); + blob->unref(); + } + + void add(GrAtlasTextBlob* blob) { + fCache.add(blob); + fBlobList.addToHead(blob); + + this->checkPurge(blob); + } + + void makeMRU(GrAtlasTextBlob* blob) { + if (fBlobList.head() == blob) { + return; + } + + fBlobList.remove(blob); + fBlobList.addToHead(blob); + } + + void freeAll(); + + // TODO move to SkTextBlob + static void BlobGlyphCount(int* glyphCount, int* runCount, const SkTextBlob* blob) { + SkTextBlobRunIterator itCounter(blob); + for (; !itCounter.done(); itCounter.next(), (*runCount)++) { + *glyphCount += itCounter.glyphCount(); + } + } + + void setBudget(size_t budget) { + fBudget = budget; + this->checkPurge(); + } + +private: + typedef SkTInternalLList<GrAtlasTextBlob> BitmapBlobList; + + void checkPurge(GrAtlasTextBlob* blob = nullptr) { + // If we are overbudget, then unref until we are below budget again + if (fPool.size() > fBudget) { + BitmapBlobList::Iter iter; + iter.init(fBlobList, BitmapBlobList::Iter::kTail_IterStart); + GrAtlasTextBlob* lruBlob = nullptr; + while (fPool.size() > fBudget && (lruBlob = iter.get()) && lruBlob != blob) { + fCache.remove(lruBlob->fKey); + + // Backup the iterator before removing and unrefing the blob + iter.prev(); + fBlobList.remove(lruBlob); + lruBlob->unref(); + } + + // If we break out of the loop with lruBlob == blob, then we haven't purged enough + // use the call back and try to free some more. If we are still overbudget after this, + // then this single textblob is over our budget + if (blob && lruBlob == blob) { + (*fCallback)(fData); + } + +#ifdef SPEW_BUDGET_MESSAGE + if (fPool.size() > fBudget) { + SkDebugf("Single textblob is larger than our whole budget"); + } +#endif + } + } + + // Budget was chosen to be ~4 megabytes. The min alloc and pre alloc sizes in the pool are + // based off of the largest cached textblob I have seen in the skps(a couple of kilobytes). + static const int kPreAllocSize = 1 << 17; + static const int kMinGrowthSize = 1 << 17; + static const int kDefaultBudget = 1 << 22; + BitmapBlobList fBlobList; + SkTDynamicHash<GrAtlasTextBlob, GrAtlasTextBlob::Key> fCache; + GrMemoryPool fPool; + PFOverBudgetCB fCallback; + void* fData; + size_t fBudget; +}; + +#endif |