From: joshualitt Date: Mon, 13 Apr 2015 13:33:59 +0000 (-0700) Subject: Start caching masks / stroke fills for textblobs X-Git-Tag: accepted/tizen/5.0/unified/20181102.025319~2804 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=53b5f4488b05c40254b24c718c2df9724a13c54a;p=platform%2Fupstream%2FlibSkiaSharp.git Start caching masks / stroke fills for textblobs BUG=skia: Review URL: https://codereview.chromium.org/1065293003 --- diff --git a/src/gpu/GrAtlasTextContext.cpp b/src/gpu/GrAtlasTextContext.cpp index 3a1bc31..9dbe631 100644 --- a/src/gpu/GrAtlasTextContext.cpp +++ b/src/gpu/GrAtlasTextContext.cpp @@ -60,10 +60,10 @@ static size_t get_vertex_stride(GrMaskFormat maskFormat) { }; // TODO -// More tests -// move to SkCache -// handle textblobs where the whole run is larger than the cache size -// TODO implement micro speedy hash map for fast refing of glyphs +// Gamma slotting to preserve color +// Better reuse on regeneration +// Telemetry tests +// possibly consider having a regeneration ratio on the textblob itself for animated textblobs GrAtlasTextContext::GrAtlasTextContext(GrContext* context, SkGpuDevice* gpuDevice, @@ -93,6 +93,7 @@ bool GrAtlasTextContext::canDraw(const GrRenderTarget*, bool GrAtlasTextContext::MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTransY, const BitmapTextBlob& blob, const SkPaint& paint, + const SkMaskFilter::BlurRec& blurRec, const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { // Color can affect the mask // TODO we can adjust the color within specific gamma slots @@ -115,6 +116,22 @@ bool GrAtlasTextContext::MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTr return true; } + // We only cache one masked version + if (blob.fKey.fHasBlur && + (blob.fBlurRec.fSigma != blurRec.fSigma || + blob.fBlurRec.fStyle != blurRec.fStyle || + blob.fBlurRec.fQuality != blurRec.fQuality)) { + return true; + } + + // Similarly, we only cache one version for each style + if (blob.fKey.fStyle != SkPaint::kFill_Style && + (blob.fStrokeInfo.fFrameWidth != paint.getStrokeWidth() || + blob.fStrokeInfo.fMiterLimit != paint.getStrokeMiter() || + blob.fStrokeInfo.fJoin != paint.getStrokeJoin())) { + return true; + } + // We can update the positions in the cachedtextblobs without regenerating the whole blob, but // only for integer translations. // This cool bit of math will determine the necessary translation to apply to the already @@ -162,17 +179,22 @@ void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkTextBlob* blob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipBounds) { - uint32_t uniqueID = blob->uniqueID(); SkAutoTUnref cacheBlob; - // TODO start caching these, mix bits into the key + + SkMaskFilter::BlurRec blurRec; + BitmapTextBlob::Key key; + // It might be worth caching these things, but its not clear at this time + // TODO for animated mask filters, this will fill up our cache. We need a safeguard here + const SkMaskFilter* mf = skPaint.getMaskFilter(); bool canCache = !(skPaint.getPathEffect() || - skPaint.getMaskFilter() || - skPaint.getColorFilter() || - skPaint.getStyle() != SkPaint::kFill_Style || + (mf && !mf->asABlur(&blurRec)) || drawFilter); if (canCache) { - cacheBlob.reset(SkSafeRef(fCache->find(uniqueID))); + key.fUniqueID = blob->uniqueID(); + key.fStyle = skPaint.getStyle(); + key.fHasBlur = SkToBool(mf); + cacheBlob.reset(SkSafeRef(fCache->find(key))); } SkIRect clipRect; @@ -182,12 +204,13 @@ void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, SkScalar transY = 0.f; if (cacheBlob) { - if (MustRegenerateBlob(&transX, &transY, *cacheBlob, skPaint, viewMatrix, x, y)) { + if (MustRegenerateBlob(&transX, &transY, *cacheBlob, skPaint, blurRec, viewMatrix, x, y)) { // We have to remake the blob because changes may invalidate our masks. // TODO we could probably get away reuse most of the time if the pointer is unique, // but we'd have to clear the subrun information fCache->remove(cacheBlob); - cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, kGrayTextVASize))); + cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, skPaint, + kGrayTextVASize))); this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, drawFilter, clipRect); } else { @@ -200,7 +223,8 @@ void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, } } else { if (canCache) { - cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, kGrayTextVASize))); + cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, skPaint, + kGrayTextVASize))); } else { cacheBlob.reset(fCache->createBlob(blob, kGrayTextVASize)); } @@ -224,7 +248,6 @@ void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, cacheBlob->fX = x; cacheBlob->fY = y; cacheBlob->fColor = skPaint.getColor(); - cacheBlob->fStyle = skPaint.getStyle(); // Regenerate textblob SkPaint runPaint = skPaint; @@ -302,7 +325,6 @@ void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip, blob->fViewMatrix = viewMatrix; blob->fX = x; blob->fY = y; - blob->fStyle = skPaint.getStyle(); SkIRect clipRect; clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); @@ -413,7 +435,6 @@ void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip, const SkPoint& offset, const SkIRect& regionClipBounds) { int glyphCount = skPaint.countText(text, byteLength); SkAutoTUnref blob(fCache->createBlob(glyphCount, 1, kGrayTextVASize)); - blob->fStyle = skPaint.getStyle(); blob->fViewMatrix = viewMatrix; SkIRect clipRect; diff --git a/src/gpu/GrAtlasTextContext.h b/src/gpu/GrAtlasTextContext.h index 7859c04..c999e1f 100644 --- a/src/gpu/GrAtlasTextContext.h +++ b/src/gpu/GrAtlasTextContext.h @@ -14,6 +14,7 @@ #include "GrGeometryProcessor.h" #include "SkDescriptor.h" #include "GrMemoryPool.h" +#include "SkMaskFilter.h" #include "SkTextBlob.h" #include "SkTInternalLList.h" @@ -84,7 +85,6 @@ private: * glyph cache to get the path at flush time, or hold onto the path in the cache, which * would greatly increase the memory of these cached items. */ - struct Run { Run() : fColor(GrColor_ILLEGAL), fInitialized(false), fDrawAsPaths(false) { fVertexBounds.setLargestInverted(); @@ -132,9 +132,14 @@ private: SkMatrix fViewMatrix; SkScalar fX; SkScalar fY; - SkPaint::Style fStyle; int fRunCount; - uint32_t fUniqueID; + SkMaskFilter::BlurRec fBlurRec; + struct StrokeInfo { + SkScalar fFrameWidth; + SkScalar fMiterLimit; + SkPaint::Join fJoin; + }; + StrokeInfo fStrokeInfo; GrMemoryPool* fPool; // all glyph / vertex offsets are into these pools. @@ -142,12 +147,26 @@ private: GrGlyph::PackedID* fGlyphIDs; Run* fRuns; - static const uint32_t& GetKey(const BitmapTextBlob& blob) { - return blob.fUniqueID; + struct Key { + Key() { + memset(this, 0, sizeof(Key)); + } + uint32_t fUniqueID; + SkPaint::Style fStyle; + bool fHasBlur; + + bool operator==(const Key& other) const { + return 0 == memcmp(this, &other, sizeof(Key)); + } + }; + Key fKey; + + static const Key& GetKey(const BitmapTextBlob& blob) { + return blob.fKey; } - static uint32_t Hash(const uint32_t& key) { - return SkChecksum::Mix(key); + static uint32_t Hash(const Key& key) { + return SkChecksum::Murmur3(&key, sizeof(Key)); } void operator delete(void* p) { @@ -200,6 +219,7 @@ private: inline SkGlyphCache* setupCache(Run*, const SkPaint&, const SkMatrix& viewMatrix); static inline bool MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTransY, const BitmapTextBlob&, const SkPaint&, + const SkMaskFilter::BlurRec&, const SkMatrix& viewMatrix, SkScalar x, SkScalar y); void regenerateTextBlob(BitmapTextBlob* bmp, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkTextBlob* blob, SkScalar x, SkScalar y, diff --git a/src/gpu/GrTextBlobCache.cpp b/src/gpu/GrTextBlobCache.cpp index a5ef07c..fe0ccf6 100644 --- a/src/gpu/GrTextBlobCache.cpp +++ b/src/gpu/GrTextBlobCache.cpp @@ -10,7 +10,7 @@ static const int kVerticesPerGlyph = 4; GrTextBlobCache::~GrTextBlobCache() { - SkTDynamicHash::Iter iter(&fCache); + SkTDynamicHash::Iter iter(&fCache); while (!iter.done()) { (&(*iter))->unref(); ++iter; diff --git a/src/gpu/GrTextBlobCache.h b/src/gpu/GrTextBlobCache.h index 0d0320e..a110a03 100644 --- a/src/gpu/GrTextBlobCache.h +++ b/src/gpu/GrTextBlobCache.h @@ -40,22 +40,34 @@ public: return cacheBlob; } - BitmapTextBlob* createCachedBlob(const SkTextBlob* blob, size_t maxVAStride) { + BitmapTextBlob* createCachedBlob(const SkTextBlob* blob, + const BitmapTextBlob::Key& key, + const SkMaskFilter::BlurRec& blurRec, + const SkPaint& paint, + size_t maxVAStride) { int glyphCount = 0; int runCount = 0; BlobGlyphCount(&glyphCount, &runCount, blob); BitmapTextBlob* cacheBlob = this->createBlob(glyphCount, runCount, maxVAStride); - cacheBlob->fUniqueID = blob->uniqueID(); + 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(); + } this->add(cacheBlob); return cacheBlob; } - BitmapTextBlob* find(uint32_t uniqueID) { - return fCache.find(uniqueID); + BitmapTextBlob* find(const BitmapTextBlob::Key& key) { + return fCache.find(key); } void remove(BitmapTextBlob* blob) { - fCache.remove(blob->fUniqueID); + fCache.remove(blob->fKey); fBlobList.remove(blob); blob->unref(); } @@ -71,7 +83,7 @@ public: BitmapTextBlob* lruBlob = iter.get(); SkASSERT(lruBlob); while (fPool.size() > kBudget && (lruBlob = iter.get()) && lruBlob != blob) { - fCache.remove(lruBlob->fUniqueID); + fCache.remove(lruBlob->fKey); // Backup the iterator before removing and unrefing the blob iter.prev(); @@ -120,7 +132,7 @@ private: static const int kMinGrowthSize = 1 << 17; static const int kBudget = 1 << 22; BitmapBlobList fBlobList; - SkTDynamicHash fCache; + SkTDynamicHash fCache; GrMemoryPool fPool; PFOverBudgetCB fCallback; void* fData;