1b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt/* 2b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt * Copyright 2015 Google Inc. 3b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt * 4b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt * Use of this source code is governed by a BSD-style license that can be 5b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt * found in the LICENSE file. 6b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt */ 7b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt 8b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt#ifndef GrTextBlobCache_DEFINED 9b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt#define GrTextBlobCache_DEFINED 10b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt 11b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt#include "GrAtlasTextContext.h" 12b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt#include "SkTDynamicHash.h" 13b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt#include "SkTextBlob.h" 14b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt 15b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualittclass GrTextBlobCache { 16b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualittpublic: 17b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt typedef GrAtlasTextContext::BitmapTextBlob BitmapTextBlob; 18b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt 190db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt /** 200db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt * The callback function used by the cache when it is still over budget after a purge. The 210db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt * passed in 'data' is the same 'data' handed to setOverbudgetCallback. 220db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt */ 230db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt typedef void (*PFOverBudgetCB)(void* data); 240db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt 250db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt GrTextBlobCache(PFOverBudgetCB cb, void* data) 260db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt : fPool(kPreAllocSize, kMinGrowthSize) 270db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt , fCallback(cb) 280db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt , fData(data) { 290db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt SkASSERT(cb && data); 300db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt } 31b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt ~GrTextBlobCache(); 32b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt 33b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt // creates an uncached blob 34b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt BitmapTextBlob* createBlob(int glyphCount, int runCount, size_t maxVASize); 352a0e9f36c6e823d2c0472ef23b4c5a247427807fjoshualitt BitmapTextBlob* createBlob(const SkTextBlob* blob, size_t maxVAStride) { 362a0e9f36c6e823d2c0472ef23b4c5a247427807fjoshualitt int glyphCount = 0; 372a0e9f36c6e823d2c0472ef23b4c5a247427807fjoshualitt int runCount = 0; 382a0e9f36c6e823d2c0472ef23b4c5a247427807fjoshualitt BlobGlyphCount(&glyphCount, &runCount, blob); 392a0e9f36c6e823d2c0472ef23b4c5a247427807fjoshualitt BitmapTextBlob* cacheBlob = this->createBlob(glyphCount, runCount, maxVAStride); 402a0e9f36c6e823d2c0472ef23b4c5a247427807fjoshualitt return cacheBlob; 412a0e9f36c6e823d2c0472ef23b4c5a247427807fjoshualitt } 42b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt 4353b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt BitmapTextBlob* createCachedBlob(const SkTextBlob* blob, 4453b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt const BitmapTextBlob::Key& key, 4553b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt const SkMaskFilter::BlurRec& blurRec, 4653b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt const SkPaint& paint, 4753b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt size_t maxVAStride) { 48b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt int glyphCount = 0; 49b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt int runCount = 0; 50b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt BlobGlyphCount(&glyphCount, &runCount, blob); 51b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt BitmapTextBlob* cacheBlob = this->createBlob(glyphCount, runCount, maxVAStride); 5253b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt cacheBlob->fKey = key; 5353b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt if (key.fHasBlur) { 5453b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt cacheBlob->fBlurRec = blurRec; 5553b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt } 5653b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt if (key.fStyle != SkPaint::kFill_Style) { 5753b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt cacheBlob->fStrokeInfo.fFrameWidth = paint.getStrokeWidth(); 5853b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt cacheBlob->fStrokeInfo.fMiterLimit = paint.getStrokeMiter(); 5953b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt cacheBlob->fStrokeInfo.fJoin = paint.getStrokeJoin(); 6053b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt } 61b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt this->add(cacheBlob); 62b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt return cacheBlob; 63b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt } 64b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt 6553b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt BitmapTextBlob* find(const BitmapTextBlob::Key& key) { 6653b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt return fCache.find(key); 67b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt } 68b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt 69b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt void remove(BitmapTextBlob* blob) { 7053b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt fCache.remove(blob->fKey); 71b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt fBlobList.remove(blob); 72b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt blob->unref(); 73b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt } 74b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt 75b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt void add(BitmapTextBlob* blob) { 76b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt fCache.add(blob); 77b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt fBlobList.addToHead(blob); 78b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt 79b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt // If we are overbudget, then unref until we are below budget again 80b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt if (fPool.size() > kBudget) { 81b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt BitmapBlobList::Iter iter; 82b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt iter.init(fBlobList, BitmapBlobList::Iter::kTail_IterStart); 83b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt BitmapTextBlob* lruBlob = iter.get(); 84b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt SkASSERT(lruBlob); 850db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt while (fPool.size() > kBudget && (lruBlob = iter.get()) && lruBlob != blob) { 8653b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt fCache.remove(lruBlob->fKey); 87f6e97e6f62c08042886dc50850c1d8c929418602joshualitt 88f6e97e6f62c08042886dc50850c1d8c929418602joshualitt // Backup the iterator before removing and unrefing the blob 89b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt iter.prev(); 90f6e97e6f62c08042886dc50850c1d8c929418602joshualitt fBlobList.remove(lruBlob); 910db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt lruBlob->unref(); 920db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt } 930db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt 940db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt // If we break out of the loop with lruBlob == blob, then we haven't purged enough 950db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt // use the call back and try to free some more. If we are still overbudget after this, 960db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt // then this single textblob is over our budget 970db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt if (lruBlob == blob) { 980db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt (*fCallback)(fData); 990db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt } 1000db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt 1010db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt#ifdef SK_DEBUG 1020db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt if (fPool.size() > kBudget) { 1030db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt SkDebugf("Single textblob is larger than our whole budget"); 1040db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt } 1050db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt#endif 106b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt } 107b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt } 108b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt 109b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt void makeMRU(BitmapTextBlob* blob) { 110b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt if (fBlobList.head() == blob) { 111b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt return; 112b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt } 113b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt 114b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt fBlobList.remove(blob); 115b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt fBlobList.addToHead(blob); 116b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt } 117b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt 11826ffc00bfa09fe85c22ddcbeb0fc54c0eacb7859joshualitt void freeAll(); 11926ffc00bfa09fe85c22ddcbeb0fc54c0eacb7859joshualitt 120b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualittprivate: 121b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt // TODO move to SkTextBlob 122b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt void BlobGlyphCount(int* glyphCount, int* runCount, const SkTextBlob* blob) { 123b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt SkTextBlob::RunIterator itCounter(blob); 124b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt for (; !itCounter.done(); itCounter.next(), (*runCount)++) { 125b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt *glyphCount += itCounter.glyphCount(); 126b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt } 127b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt } 128b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt 129b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt typedef SkTInternalLList<BitmapTextBlob> BitmapBlobList; 130b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt 131b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt // Budget was chosen to be ~4 megabytes. The min alloc and pre alloc sizes in the pool are 132b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt // based off of the largest cached textblob I have seen in the skps(a couple of kilobytes). 133b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt static const int kPreAllocSize = 1 << 17; 134b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt static const int kMinGrowthSize = 1 << 17; 1350db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt static const int kBudget = 1 << 22; 136b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt BitmapBlobList fBlobList; 13753b5f4488b05c40254b24c718c2df9724a13c54ajoshualitt SkTDynamicHash<BitmapTextBlob, BitmapTextBlob::Key> fCache; 138b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt GrMemoryPool fPool; 1390db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt PFOverBudgetCB fCallback; 1400db6dfaeb2d1376ad393516fb22af7ecf62718fajoshualitt void* fData; 141b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt}; 142b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt 143b7133bed55af8dd4ca9427892bb1a5623dbaccf0joshualitt#endif 144