diff options
author | joshualitt <joshualitt@chromium.org> | 2015-07-21 08:05:03 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-07-21 08:05:03 -0700 |
commit | 374b2f7cea8b1117f0dd17cdecd2b3ec85b141d4 (patch) | |
tree | 5bcf2e1b76742818dfaedc8da610b4b6eeeab949 /src | |
parent | 4ec1ac6a2dc7e43c4179638f3dd801be6f3b386e (diff) |
rename BitmapTextBlob and move it to its own file
BUG=skia:
Review URL: https://codereview.chromium.org/1249663002
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/GrAtlasTextBlob.h | 216 | ||||
-rw-r--r-- | src/gpu/GrAtlasTextContext.cpp | 68 | ||||
-rw-r--r-- | src/gpu/GrAtlasTextContext.h | 245 | ||||
-rw-r--r-- | src/gpu/GrTextBlobCache.cpp | 20 | ||||
-rw-r--r-- | src/gpu/GrTextBlobCache.h | 28 |
5 files changed, 295 insertions, 282 deletions
diff --git a/src/gpu/GrAtlasTextBlob.h b/src/gpu/GrAtlasTextBlob.h new file mode 100644 index 0000000000..a69e430779 --- /dev/null +++ b/src/gpu/GrAtlasTextBlob.h @@ -0,0 +1,216 @@ +/* + * 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 GrAtlasTextBlob_DEFINED +#define GrAtlasTextBlob_DEFINED + +#include "GrBatchAtlas.h" +#include "GrBatchFontCache.h" +#include "SkDescriptor.h" +#include "SkMaskFilter.h" +#include "GrMemoryPool.h" +#include "SkTInternalLList.h" + +/* + * A GrAtlasTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing + * on the GPU. These are initially created with valid positions and colors, but invalid + * texture coordinates. The GrAtlasTextBlob itself has a few Blob-wide properties, and also + * consists of a number of runs. Runs inside a blob are flushed individually so they can be + * reordered. + * + * The only thing(aside from a memcopy) required to flush a GrAtlasTextBlob is to ensure that + * the GrAtlas will not evict anything the Blob needs. + * + * Note: This struct should really be named GrCachedAtasTextBlob, but that is too verbose. + */ +struct GrAtlasTextBlob : public SkRefCnt { + SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrAtlasTextBlob); + + /* + * Each Run inside of the blob can have its texture coordinates regenerated if required. + * To determine if regeneration is necessary, fAtlasGeneration is used. If there have been + * any evictions inside of the atlas, then we will simply regenerate Runs. We could track + * this at a more fine grained level, but its not clear if this is worth it, as evictions + * should be fairly rare. + * + * One additional point, each run can contain glyphs with any of the three mask formats. + * We call these SubRuns. Because a subrun must be a contiguous range, we have to create + * a new subrun each time the mask format changes in a run. In theory, a run can have as + * many SubRuns as it has glyphs, ie if a run alternates between color emoji and A8. In + * practice, the vast majority of runs have only a single subrun. + * + * Finally, for runs where the entire thing is too large for the GrAtlasTextContext to + * handle, we have a bit to mark the run as flusahable via rendering as paths. It is worth + * pointing. It would be a bit expensive to figure out ahead of time whether or not a run + * can flush in this manner, so we always allocate vertices for the run, regardless of + * whether or not it is too large. The benefit of this strategy is that we can always reuse + * a blob allocation regardless of viewmatrix changes. We could store positions for these + * glyphs. However, its not clear if this is a win because we'd still have to either go the + * 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(); + // To ensure we always have one subrun, we push back a fresh run here + fSubRunInfo.push_back(); + } + struct SubRunInfo { + SubRunInfo() + : fAtlasGeneration(GrBatchAtlas::kInvalidAtlasGeneration) + , fVertexStartIndex(0) + , fVertexEndIndex(0) + , fGlyphStartIndex(0) + , fGlyphEndIndex(0) + , fDrawAsDistanceFields(false) {} + // Distance field text cannot draw coloremoji, and so has to fall back. However, + // though the distance field text and the coloremoji may share the same run, they + // will have different descriptors. If fOverrideDescriptor is non-NULL, then it + // will be used in place of the run's descriptor to regen texture coords + // TODO we could have a descriptor cache, it would reduce the size of these blobs + // significantly, and then the subrun could just have a refed pointer to the + // correct descriptor. + GrBatchAtlas::BulkUseTokenUpdater fBulkUseToken; + uint64_t fAtlasGeneration; + size_t fVertexStartIndex; + size_t fVertexEndIndex; + uint32_t fGlyphStartIndex; + uint32_t fGlyphEndIndex; + SkScalar fTextRatio; // df property + GrMaskFormat fMaskFormat; + bool fDrawAsDistanceFields; // df property + bool fUseLCDText; // df property + }; + + SubRunInfo& push_back() { + // Forward glyph / vertex information to seed the new sub run + SubRunInfo& prevSubRun = fSubRunInfo.back(); + SubRunInfo& newSubRun = fSubRunInfo.push_back(); + newSubRun.fGlyphStartIndex = prevSubRun.fGlyphEndIndex; + newSubRun.fGlyphEndIndex = prevSubRun.fGlyphEndIndex; + + newSubRun.fVertexStartIndex = prevSubRun.fVertexEndIndex; + newSubRun.fVertexEndIndex = prevSubRun.fVertexEndIndex; + return newSubRun; + } + static const int kMinSubRuns = 1; + SkAutoTUnref<GrBatchTextStrike> fStrike; + SkAutoTUnref<SkTypeface> fTypeface; + SkRect fVertexBounds; + SkSTArray<kMinSubRuns, SubRunInfo> fSubRunInfo; + SkAutoDescriptor fDescriptor; + SkAutoTDelete<SkAutoDescriptor> fOverrideDescriptor; // df properties + GrColor fColor; + bool fInitialized; + bool fDrawAsPaths; + }; + + struct BigGlyph { + BigGlyph(const SkPath& path, SkScalar vx, SkScalar vy) + : fPath(path) + , fVx(vx) + , fVy(vy) {} + SkPath fPath; + SkScalar fVx; + SkScalar fVy; + }; + + struct Key { + Key() { + sk_bzero(this, sizeof(Key)); + } + uint32_t fUniqueID; + // Color may affect the gamma of the mask we generate, but in a fairly limited way. + // Each color is assigned to on of a fixed number of buckets based on its + // luminance. For each luminance bucket there is a "canonical color" that + // represents the bucket. This functionality is currently only supported for A8 + SkColor fCanonicalColor; + SkPaint::Style fStyle; + SkPixelGeometry fPixelGeometry; + bool fHasBlur; + + bool operator==(const Key& other) const { + return 0 == memcmp(this, &other, sizeof(Key)); + } + }; + + struct StrokeInfo { + SkScalar fFrameWidth; + SkScalar fMiterLimit; + SkPaint::Join fJoin; + }; + + enum TextType { + kHasDistanceField_TextType = 0x1, + kHasBitmap_TextType = 0x2, + }; + + // all glyph / vertex offsets are into these pools. + unsigned char* fVertices; + GrGlyph** fGlyphs; + Run* fRuns; + GrMemoryPool* fPool; + SkMaskFilter::BlurRec fBlurRec; + StrokeInfo fStrokeInfo; + SkTArray<BigGlyph> fBigGlyphs; + Key fKey; + SkMatrix fViewMatrix; + SkColor fPaintColor; + SkScalar fX; + SkScalar fY; + + // We can reuse distance field text, but only if the new viewmatrix would not result in + // a mip change. Because there can be multiple runs in a blob, we track the overall + // maximum minimum scale, and minimum maximum scale, we can support before we need to regen + SkScalar fMaxMinScale; + SkScalar fMinMaxScale; + int fRunCount; + uint8_t fTextType; + + GrAtlasTextBlob() + : fMaxMinScale(-SK_ScalarMax) + , fMinMaxScale(SK_ScalarMax) + , fTextType(0) {} + + ~GrAtlasTextBlob() override { + for (int i = 0; i < fRunCount; i++) { + fRuns[i].~Run(); + } + } + + static const Key& GetKey(const GrAtlasTextBlob& blob) { + return blob.fKey; + } + + static uint32_t Hash(const Key& key) { + return SkChecksum::Murmur3(&key, sizeof(Key)); + } + + void operator delete(void* p) { + GrAtlasTextBlob* blob = reinterpret_cast<GrAtlasTextBlob*>(p); + blob->fPool->release(p); + } + void* operator new(size_t) { + SkFAIL("All blobs are created by placement new."); + return sk_malloc_throw(0); + } + + void* operator new(size_t, void* p) { return p; } + void operator delete(void* target, void* placement) { + ::operator delete(target, placement); + } + + bool hasDistanceField() const { return SkToBool(fTextType & kHasDistanceField_TextType); } + bool hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); } + void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; } + void setHasBitmap() { fTextType |= kHasBitmap_TextType; } +}; + +#endif diff --git a/src/gpu/GrAtlasTextContext.cpp b/src/gpu/GrAtlasTextContext.cpp index 868f8bbe8e..8009e92f93 100644 --- a/src/gpu/GrAtlasTextContext.cpp +++ b/src/gpu/GrAtlasTextContext.cpp @@ -244,7 +244,7 @@ bool GrAtlasTextContext::HasLCD(const SkTextBlob* blob) { } bool GrAtlasTextContext::MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTransY, - const BitmapTextBlob& blob, const SkPaint& paint, + const GrAtlasTextBlob& blob, const SkPaint& paint, const SkMaskFilter::BlurRec& blurRec, const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { // If we have LCD text then our canonical color will be set to transparent, in this case we have @@ -326,15 +326,15 @@ bool GrAtlasTextContext::MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTr (*outTransX) = x - blob.fX; (*outTransY) = y - blob.fY; } + // It is possible that a blob has neither distanceField nor bitmaptext. This is in the case // when all of the runs inside the blob are drawn as paths. In this case, we always regenerate // the blob anyways at flush time, so no need to regenerate explicitly - return false; } -inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run, +inline SkGlyphCache* GrAtlasTextContext::setupCache(GrAtlasTextBlob::Run* run, const SkPaint& skPaint, const SkMatrix* viewMatrix, bool noGamma) { @@ -353,9 +353,9 @@ void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, return; } - SkAutoTUnref<BitmapTextBlob> cacheBlob; + SkAutoTUnref<GrAtlasTextBlob> cacheBlob; SkMaskFilter::BlurRec blurRec; - BitmapTextBlob::Key key; + GrAtlasTextBlob::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(); @@ -470,7 +470,7 @@ inline bool GrAtlasTextContext::canDrawAsDistanceFields(const SkPaint& skPaint, return true; } -void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, +void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, const SkPaint& skPaint, GrColor color, const SkMatrix& viewMatrix, const SkTextBlob* blob, SkScalar x, SkScalar y, @@ -594,7 +594,7 @@ void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, } } -inline void GrAtlasTextContext::initDistanceFieldPaint(BitmapTextBlob* blob, +inline void GrAtlasTextContext::initDistanceFieldPaint(GrAtlasTextBlob* blob, SkPaint* skPaint, SkScalar* textRatio, const SkMatrix& viewMatrix) { @@ -648,7 +648,7 @@ inline void GrAtlasTextContext::initDistanceFieldPaint(BitmapTextBlob* blob, skPaint->setSubpixelText(true); } -inline void GrAtlasTextContext::fallbackDrawPosText(BitmapTextBlob* blob, +inline void GrAtlasTextContext::fallbackDrawPosText(GrAtlasTextBlob* blob, int runIndex, GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, @@ -675,11 +675,11 @@ inline void GrAtlasTextContext::fallbackDrawPosText(BitmapTextBlob* blob, SkGlyphCache::AttachCache(cache); } -inline GrAtlasTextContext::BitmapTextBlob* +inline GrAtlasTextBlob* GrAtlasTextContext::setupDFBlob(int glyphCount, const SkPaint& origPaint, const SkMatrix& viewMatrix, SkGlyphCache** cache, SkPaint* dfPaint, SkScalar* textRatio) { - BitmapTextBlob* blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize); + GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize); *dfPaint = origPaint; this->initDistanceFieldPaint(blob, dfPaint, textRatio, viewMatrix); @@ -693,7 +693,7 @@ GrAtlasTextContext::setupDFBlob(int glyphCount, const SkPaint& origPaint, return blob; } -inline GrAtlasTextContext::BitmapTextBlob* +inline GrAtlasTextBlob* GrAtlasTextContext::createDrawTextBlob(GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, const SkMatrix& viewMatrix, @@ -703,7 +703,7 @@ GrAtlasTextContext::createDrawTextBlob(GrRenderTarget* rt, const GrClip& clip, SkIRect clipRect; clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); - BitmapTextBlob* blob; + GrAtlasTextBlob* blob; if (this->canDrawAsDistanceFields(skPaint, viewMatrix)) { SkPaint dfPaint; SkScalar textRatio; @@ -733,7 +733,7 @@ GrAtlasTextContext::createDrawTextBlob(GrRenderTarget* rt, const GrClip& clip, return blob; } -inline GrAtlasTextContext::BitmapTextBlob* +inline GrAtlasTextBlob* GrAtlasTextContext::createDrawPosTextBlob(GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, const SkMatrix& viewMatrix, @@ -745,7 +745,7 @@ GrAtlasTextContext::createDrawPosTextBlob(GrRenderTarget* rt, const GrClip& clip SkIRect clipRect; clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); - BitmapTextBlob* blob; + GrAtlasTextBlob* blob; if (this->canDrawAsDistanceFields(skPaint, viewMatrix)) { SkPaint dfPaint; SkScalar textRatio; @@ -779,7 +779,7 @@ void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& regionClipBounds) { - SkAutoTUnref<BitmapTextBlob> blob( + SkAutoTUnref<GrAtlasTextBlob> blob( this->createDrawTextBlob(rt, clip, paint, skPaint, viewMatrix, text, byteLength, x, y, regionClipBounds)); this->flush(blob, rt, skPaint, paint, clip, regionClipBounds); @@ -792,7 +792,7 @@ void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& regionClipBounds) { - SkAutoTUnref<BitmapTextBlob> blob( + SkAutoTUnref<GrAtlasTextBlob> blob( this->createDrawPosTextBlob(rt, clip, paint, skPaint, viewMatrix, text, byteLength, pos, scalarsPerPosition, @@ -801,7 +801,7 @@ void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, this->flush(blob, rt, skPaint, paint, clip, regionClipBounds); } -void GrAtlasTextContext::internalDrawBMPText(BitmapTextBlob* blob, int runIndex, +void GrAtlasTextContext::internalDrawBMPText(GrAtlasTextBlob* blob, int runIndex, SkGlyphCache* cache, const SkPaint& skPaint, GrColor color, const SkMatrix& viewMatrix, @@ -892,7 +892,7 @@ void GrAtlasTextContext::internalDrawBMPText(BitmapTextBlob* blob, int runIndex, } } -void GrAtlasTextContext::internalDrawBMPPosText(BitmapTextBlob* blob, int runIndex, +void GrAtlasTextContext::internalDrawBMPPosText(GrAtlasTextBlob* blob, int runIndex, SkGlyphCache* cache, const SkPaint& skPaint, GrColor color, const SkMatrix& viewMatrix, @@ -1057,7 +1057,7 @@ void GrAtlasTextContext::internalDrawBMPPosText(BitmapTextBlob* blob, int runInd } -void GrAtlasTextContext::internalDrawDFText(BitmapTextBlob* blob, int runIndex, +void GrAtlasTextContext::internalDrawDFText(GrAtlasTextBlob* blob, int runIndex, SkGlyphCache* cache, const SkPaint& skPaint, GrColor color, const SkMatrix& viewMatrix, @@ -1131,7 +1131,7 @@ void GrAtlasTextContext::internalDrawDFText(BitmapTextBlob* blob, int runIndex, SkGlyphCache::AttachCache(origPaintCache); } -void GrAtlasTextContext::internalDrawDFPosText(BitmapTextBlob* blob, int runIndex, +void GrAtlasTextContext::internalDrawDFPosText(GrAtlasTextBlob* blob, int runIndex, SkGlyphCache* cache, const SkPaint& skPaint, GrColor color, const SkMatrix& viewMatrix, @@ -1224,7 +1224,7 @@ void GrAtlasTextContext::internalDrawDFPosText(BitmapTextBlob* blob, int runInde } } -void GrAtlasTextContext::bmpAppendGlyph(BitmapTextBlob* blob, int runIndex, +void GrAtlasTextContext::bmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex, GrGlyph::PackedID packed, int vx, int vy, GrColor color, GrFontScaler* scaler, const SkIRect& clipRect) { @@ -1285,7 +1285,7 @@ void GrAtlasTextContext::bmpAppendGlyph(BitmapTextBlob* blob, int runIndex, glyph); } -bool GrAtlasTextContext::dfAppendGlyph(BitmapTextBlob* blob, int runIndex, +bool GrAtlasTextContext::dfAppendGlyph(GrAtlasTextBlob* blob, int runIndex, GrGlyph::PackedID packed, SkScalar sx, SkScalar sy, GrColor color, GrFontScaler* scaler, @@ -1352,7 +1352,7 @@ bool GrAtlasTextContext::dfAppendGlyph(BitmapTextBlob* blob, int runIndex, return true; } -inline void GrAtlasTextContext::appendGlyphPath(BitmapTextBlob* blob, GrGlyph* glyph, +inline void GrAtlasTextContext::appendGlyphPath(GrAtlasTextBlob* blob, GrGlyph* glyph, GrFontScaler* scaler, SkScalar x, SkScalar y) { if (NULL == glyph->fPath) { SkPath* path = SkNEW(SkPath); @@ -1364,10 +1364,10 @@ inline void GrAtlasTextContext::appendGlyphPath(BitmapTextBlob* blob, GrGlyph* g glyph->fPath = path; } SkASSERT(glyph->fPath); - blob->fBigGlyphs.push_back(BitmapTextBlob::BigGlyph(*glyph->fPath, x, y)); + blob->fBigGlyphs.push_back(GrAtlasTextBlob::BigGlyph(*glyph->fPath, x, y)); } -inline void GrAtlasTextContext::appendGlyphCommon(BitmapTextBlob* blob, Run* run, +inline void GrAtlasTextContext::appendGlyphCommon(GrAtlasTextBlob* blob, Run* run, Run::SubRunInfo* subRun, const SkRect& positions, GrColor color, size_t vertexStride, bool useVertexColor, @@ -1433,7 +1433,7 @@ inline void GrAtlasTextContext::appendGlyphCommon(BitmapTextBlob* blob, Run* run class BitmapTextBatch : public GrBatch { public: typedef GrAtlasTextContext::DistanceAdjustTable DistanceAdjustTable; - typedef GrAtlasTextContext::BitmapTextBlob Blob; + typedef GrAtlasTextBlob Blob; typedef Blob::Run Run; typedef Run::SubRunInfo TextInfo; struct Geometry { @@ -2074,7 +2074,7 @@ void GrAtlasTextContext::flushRunAsPaths(GrRenderTarget* rt, const SkTextBlob::R inline BitmapTextBatch* -GrAtlasTextContext::createBatch(BitmapTextBlob* cacheBlob, const PerSubRunInfo& info, +GrAtlasTextContext::createBatch(GrAtlasTextBlob* cacheBlob, const PerSubRunInfo& info, int glyphCount, int run, int subRun, GrColor color, SkScalar transX, SkScalar transY, const SkPaint& skPaint) { @@ -2116,7 +2116,7 @@ GrAtlasTextContext::createBatch(BitmapTextBlob* cacheBlob, const PerSubRunInfo& } inline void GrAtlasTextContext::flushRun(GrPipelineBuilder* pipelineBuilder, - BitmapTextBlob* cacheBlob, int run, GrColor color, + GrAtlasTextBlob* cacheBlob, int run, GrColor color, SkScalar transX, SkScalar transY, const SkPaint& skPaint) { for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); subRun++) { @@ -2133,7 +2133,7 @@ inline void GrAtlasTextContext::flushRun(GrPipelineBuilder* pipelineBuilder, } } -inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRenderTarget* rt, +inline void GrAtlasTextContext::flushBigGlyphs(GrAtlasTextBlob* cacheBlob, GrRenderTarget* rt, const GrClip& clip, const SkPaint& skPaint, SkScalar transX, SkScalar transY, const SkIRect& clipBounds) { @@ -2148,7 +2148,7 @@ inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRend } for (int i = 0; i < cacheBlob->fBigGlyphs.count(); i++) { - BitmapTextBlob::BigGlyph& bigGlyph = cacheBlob->fBigGlyphs[i]; + GrAtlasTextBlob::BigGlyph& bigGlyph = cacheBlob->fBigGlyphs[i]; bigGlyph.fVx += transX; bigGlyph.fVy += transY; SkMatrix translate = cacheBlob->fViewMatrix; @@ -2160,7 +2160,7 @@ inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRend } void GrAtlasTextContext::flush(const SkTextBlob* blob, - BitmapTextBlob* cacheBlob, + GrAtlasTextBlob* cacheBlob, GrRenderTarget* rt, const SkPaint& skPaint, const GrPaint& grPaint, @@ -2192,7 +2192,7 @@ void GrAtlasTextContext::flush(const SkTextBlob* blob, this->flushBigGlyphs(cacheBlob, rt, clip, skPaint, transX, transY, clipBounds); } -void GrAtlasTextContext::flush(BitmapTextBlob* cacheBlob, +void GrAtlasTextContext::flush(GrAtlasTextBlob* cacheBlob, GrRenderTarget* rt, const SkPaint& skPaint, const GrPaint& grPaint, @@ -2265,13 +2265,13 @@ BATCH_TEST_DEFINE(TextBlobBatch) { // right now we don't handle textblobs, nor do we handle drawPosText. Since we only // intend to test the batch with this unit test, that is okay. - SkAutoTUnref<GrAtlasTextContext::BitmapTextBlob> blob( + SkAutoTUnref<GrAtlasTextBlob> blob( gTextContext->createDrawTextBlob(rt, clip, grPaint, skPaint, viewMatrix, text, static_cast<size_t>(textLen), 0, 0, noClip)); SkScalar transX = static_cast<SkScalar>(random->nextU()); SkScalar transY = static_cast<SkScalar>(random->nextU()); - const GrAtlasTextContext::BitmapTextBlob::Run::SubRunInfo& info = blob->fRuns[0].fSubRunInfo[0]; + const GrAtlasTextBlob::Run::SubRunInfo& info = blob->fRuns[0].fSubRunInfo[0]; return gTextContext->createBatch(blob, info, textLen, 0, 0, color, transX, transY, skPaint); } diff --git a/src/gpu/GrAtlasTextContext.h b/src/gpu/GrAtlasTextContext.h index 8094046d5c..9e49bba37e 100644 --- a/src/gpu/GrAtlasTextContext.h +++ b/src/gpu/GrAtlasTextContext.h @@ -10,14 +10,9 @@ #include "GrTextContext.h" -#include "GrBatchAtlas.h" -#include "GrBatchFontCache.h" +#include "GrAtlasTextBlob.h" #include "GrGeometryProcessor.h" -#include "SkDescriptor.h" -#include "GrMemoryPool.h" -#include "SkMaskFilter.h" #include "SkTextBlob.h" -#include "SkTInternalLList.h" #ifdef GR_TEST_UTILS #include "GrBatchTest.h" @@ -56,217 +51,21 @@ private: const SkMatrix& viewMatrix, const SkTextBlob*, SkScalar x, SkScalar y, SkDrawFilter*, const SkIRect& clipBounds) override; - /* - * A BitmapTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing - * on the GPU. These are initially created with valid positions and colors, but invalid - * texture coordinates. The BitmapTextBlob itself has a few Blob-wide properties, and also - * consists of a number of runs. Runs inside a blob are flushed individually so they can be - * reordered. - * - * The only thing(aside from a memcopy) required to flush a BitmapTextBlob is to ensure that - * the GrAtlas will not evict anything the Blob needs. - */ - struct BitmapTextBlob : public SkRefCnt { - SK_DECLARE_INTERNAL_LLIST_INTERFACE(BitmapTextBlob); - - /* - * Each Run inside of the blob can have its texture coordinates regenerated if required. - * To determine if regeneration is necessary, fAtlasGeneration is used. If there have been - * any evictions inside of the atlas, then we will simply regenerate Runs. We could track - * this at a more fine grained level, but its not clear if this is worth it, as evictions - * should be fairly rare. - * - * One additional point, each run can contain glyphs with any of the three mask formats. - * We call these SubRuns. Because a subrun must be a contiguous range, we have to create - * a new subrun each time the mask format changes in a run. In theory, a run can have as - * many SubRuns as it has glyphs, ie if a run alternates between color emoji and A8. In - * practice, the vast majority of runs have only a single subrun. - * - * Finally, for runs where the entire thing is too large for the GrAtlasTextContext to - * handle, we have a bit to mark the run as flusahable via rendering as paths. It is worth - * pointing. It would be a bit expensive to figure out ahead of time whether or not a run - * can flush in this manner, so we always allocate vertices for the run, regardless of - * whether or not it is too large. The benefit of this strategy is that we can always reuse - * a blob allocation regardless of viewmatrix changes. We could store positions for these - * glyphs. However, its not clear if this is a win because we'd still have to either go the - * 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(); - // To ensure we always have one subrun, we push back a fresh run here - fSubRunInfo.push_back(); - } - struct SubRunInfo { - SubRunInfo() - : fAtlasGeneration(GrBatchAtlas::kInvalidAtlasGeneration) - , fVertexStartIndex(0) - , fVertexEndIndex(0) - , fGlyphStartIndex(0) - , fGlyphEndIndex(0) - , fDrawAsDistanceFields(false) {} - // Distance field text cannot draw coloremoji, and so has to fall back. However, - // though the distance field text and the coloremoji may share the same run, they - // will have different descriptors. If fOverrideDescriptor is non-NULL, then it - // will be used in place of the run's descriptor to regen texture coords - // TODO we could have a descriptor cache, it would reduce the size of these blobs - // significantly, and then the subrun could just have a refed pointer to the - // correct descriptor. - GrBatchAtlas::BulkUseTokenUpdater fBulkUseToken; - uint64_t fAtlasGeneration; - size_t fVertexStartIndex; - size_t fVertexEndIndex; - uint32_t fGlyphStartIndex; - uint32_t fGlyphEndIndex; - SkScalar fTextRatio; // df property - GrMaskFormat fMaskFormat; - bool fDrawAsDistanceFields; // df property - bool fUseLCDText; // df property - }; - - SubRunInfo& push_back() { - // Forward glyph / vertex information to seed the new sub run - SubRunInfo& prevSubRun = fSubRunInfo.back(); - SubRunInfo& newSubRun = fSubRunInfo.push_back(); - newSubRun.fGlyphStartIndex = prevSubRun.fGlyphEndIndex; - newSubRun.fGlyphEndIndex = prevSubRun.fGlyphEndIndex; - - newSubRun.fVertexStartIndex = prevSubRun.fVertexEndIndex; - newSubRun.fVertexEndIndex = prevSubRun.fVertexEndIndex; - return newSubRun; - } - static const int kMinSubRuns = 1; - SkAutoTUnref<GrBatchTextStrike> fStrike; - SkAutoTUnref<SkTypeface> fTypeface; - SkRect fVertexBounds; - SkSTArray<kMinSubRuns, SubRunInfo> fSubRunInfo; - SkAutoDescriptor fDescriptor; - SkAutoTDelete<SkAutoDescriptor> fOverrideDescriptor; // df properties - GrColor fColor; - bool fInitialized; - bool fDrawAsPaths; - }; - - struct BigGlyph { - BigGlyph(const SkPath& path, SkScalar vx, SkScalar vy) - : fPath(path) - , fVx(vx) - , fVy(vy) {} - SkPath fPath; - SkScalar fVx; - SkScalar fVy; - }; - - struct Key { - Key() { - sk_bzero(this, sizeof(Key)); - } - uint32_t fUniqueID; - // Color may affect the gamma of the mask we generate, but in a fairly limited way. - // Each color is assigned to on of a fixed number of buckets based on its - // luminance. For each luminance bucket there is a "canonical color" that - // represents the bucket. This functionality is currently only supported for A8 - SkColor fCanonicalColor; - SkPaint::Style fStyle; - SkPixelGeometry fPixelGeometry; - bool fHasBlur; - - bool operator==(const Key& other) const { - return 0 == memcmp(this, &other, sizeof(Key)); - } - }; - - struct StrokeInfo { - SkScalar fFrameWidth; - SkScalar fMiterLimit; - SkPaint::Join fJoin; - }; - - enum TextType { - kHasDistanceField_TextType = 0x1, - kHasBitmap_TextType = 0x2, - }; - - // all glyph / vertex offsets are into these pools. - unsigned char* fVertices; - GrGlyph** fGlyphs; - Run* fRuns; - GrMemoryPool* fPool; - SkMaskFilter::BlurRec fBlurRec; - StrokeInfo fStrokeInfo; - SkTArray<BigGlyph> fBigGlyphs; - Key fKey; - SkMatrix fViewMatrix; - SkColor fPaintColor; - SkScalar fX; - SkScalar fY; - - // We can reuse distance field text, but only if the new viewmatrix would not result in - // a mip change. Because there can be multiple runs in a blob, we track the overall - // maximum minimum scale, and minimum maximum scale, we can support before we need to regen - SkScalar fMaxMinScale; - SkScalar fMinMaxScale; - int fRunCount; - uint8_t fTextType; - - BitmapTextBlob() - : fMaxMinScale(-SK_ScalarMax) - , fMinMaxScale(SK_ScalarMax) - , fTextType(0) {} - - ~BitmapTextBlob() override { - for (int i = 0; i < fRunCount; i++) { - fRuns[i].~Run(); - } - } - - static const Key& GetKey(const BitmapTextBlob& blob) { - return blob.fKey; - } - - static uint32_t Hash(const Key& key) { - return SkChecksum::Murmur3(&key, sizeof(Key)); - } - - void operator delete(void* p) { - BitmapTextBlob* blob = reinterpret_cast<BitmapTextBlob*>(p); - blob->fPool->release(p); - } - void* operator new(size_t) { - SkFAIL("All blobs are created by placement new."); - return sk_malloc_throw(0); - } - - void* operator new(size_t, void* p) { return p; } - void operator delete(void* target, void* placement) { - ::operator delete(target, placement); - } - - bool hasDistanceField() const { return SkToBool(fTextType & kHasDistanceField_TextType); } - bool hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); } - void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; } - void setHasBitmap() { fTextType |= kHasBitmap_TextType; } - }; - - typedef BitmapTextBlob::Run Run; + typedef GrAtlasTextBlob::Run Run; typedef Run::SubRunInfo PerSubRunInfo; inline bool canDrawAsDistanceFields(const SkPaint&, const SkMatrix& viewMatrix); - BitmapTextBlob* setupDFBlob(int glyphCount, const SkPaint& origPaint, + GrAtlasTextBlob* setupDFBlob(int glyphCount, const SkPaint& origPaint, const SkMatrix& viewMatrix, SkGlyphCache** cache, SkPaint* dfPaint, SkScalar* textRatio); - void bmpAppendGlyph(BitmapTextBlob*, int runIndex, GrGlyph::PackedID, int left, int top, + void bmpAppendGlyph(GrAtlasTextBlob*, int runIndex, GrGlyph::PackedID, int left, int top, GrColor color, GrFontScaler*, const SkIRect& clipRect); - bool dfAppendGlyph(BitmapTextBlob*, int runIndex, GrGlyph::PackedID, SkScalar sx, SkScalar sy, + bool dfAppendGlyph(GrAtlasTextBlob*, int runIndex, GrGlyph::PackedID, SkScalar sx, SkScalar sy, GrColor color, GrFontScaler*, const SkIRect& clipRect, SkScalar textRatio, const SkMatrix& viewMatrix); - inline void appendGlyphPath(BitmapTextBlob* blob, GrGlyph* glyph, + inline void appendGlyphPath(GrAtlasTextBlob* blob, GrGlyph* glyph, GrFontScaler* scaler, SkScalar x, SkScalar y); - inline void appendGlyphCommon(BitmapTextBlob*, Run*, Run::SubRunInfo*, + inline void appendGlyphCommon(GrAtlasTextBlob*, Run*, Run::SubRunInfo*, const SkRect& positions, GrColor color, size_t vertexStride, bool useVertexColor, GrGlyph*); @@ -276,26 +75,26 @@ private: const SkPaint&, SkDrawFilter*, const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, SkScalar y); - inline BitmapTextBatch* createBatch(BitmapTextBlob*, const PerSubRunInfo&, + inline BitmapTextBatch* createBatch(GrAtlasTextBlob*, const PerSubRunInfo&, int glyphCount, int run, int subRun, GrColor, SkScalar transX, SkScalar transY, const SkPaint&); - inline void flushRun(GrPipelineBuilder*, BitmapTextBlob*, int run, GrColor, + inline void flushRun(GrPipelineBuilder*, GrAtlasTextBlob*, int run, GrColor, SkScalar transX, SkScalar transY, const SkPaint&); - inline void flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRenderTarget*, + inline void flushBigGlyphs(GrAtlasTextBlob* cacheBlob, GrRenderTarget*, const GrClip& clip, const SkPaint& skPaint, SkScalar transX, SkScalar transY, const SkIRect& clipBounds); // We have to flush SkTextBlobs differently from drawText / drawPosText - void flush(const SkTextBlob*, BitmapTextBlob*, GrRenderTarget*, + void flush(const SkTextBlob*, GrAtlasTextBlob*, GrRenderTarget*, const SkPaint&, const GrPaint&, SkDrawFilter*, const GrClip&, const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, SkScalar y, SkScalar transX, SkScalar transY); - void flush(BitmapTextBlob*, GrRenderTarget*, const SkPaint&, + void flush(GrAtlasTextBlob*, GrRenderTarget*, const SkPaint&, const GrPaint&, const GrClip&, const SkIRect& clipBounds); // A helper for drawing BitmapText in a run of distance fields - inline void fallbackDrawPosText(BitmapTextBlob*, int runIndex, + inline void fallbackDrawPosText(GrAtlasTextBlob*, int runIndex, GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix, @@ -305,17 +104,17 @@ private: const SkPoint& offset, const SkIRect& clipRect); - void internalDrawBMPText(BitmapTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&, + void internalDrawBMPText(GrAtlasTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&, GrColor color, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipRect); - void internalDrawBMPPosText(BitmapTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&, + void internalDrawBMPPosText(GrAtlasTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&, GrColor color, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& clipRect); - void internalDrawDFText(BitmapTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&, + void internalDrawDFText(GrAtlasTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&, GrColor color, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipRect, @@ -323,7 +122,7 @@ private: SkTDArray<char>* fallbackTxt, SkTDArray<SkScalar>* fallbackPos, SkPoint* offset, const SkPaint& origPaint); - void internalDrawDFPosText(BitmapTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&, + void internalDrawDFPosText(GrAtlasTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&, GrColor color, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, @@ -336,26 +135,26 @@ private: inline static GrColor ComputeCanonicalColor(const SkPaint&, bool lcd); inline SkGlyphCache* setupCache(Run*, const SkPaint&, const SkMatrix* viewMatrix, bool noGamma); static inline bool MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTransY, - const BitmapTextBlob&, const SkPaint&, + const GrAtlasTextBlob&, const SkPaint&, const SkMaskFilter::BlurRec&, const SkMatrix& viewMatrix, SkScalar x, SkScalar y); - void regenerateTextBlob(BitmapTextBlob* bmp, const SkPaint& skPaint, GrColor, + void regenerateTextBlob(GrAtlasTextBlob* bmp, const SkPaint& skPaint, GrColor, const SkMatrix& viewMatrix, const SkTextBlob* blob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipRect, GrRenderTarget*, const GrClip&, const GrPaint&); inline static bool HasLCD(const SkTextBlob*); - inline void initDistanceFieldPaint(BitmapTextBlob*, SkPaint*, SkScalar* textRatio, + inline void initDistanceFieldPaint(GrAtlasTextBlob*, SkPaint*, SkScalar* textRatio, const SkMatrix&); // Test methods // TODO this is really ugly. It'd be much nicer if positioning could be moved to batch - inline BitmapTextBlob* createDrawTextBlob(GrRenderTarget*, const GrClip&, const GrPaint&, + inline GrAtlasTextBlob* createDrawTextBlob(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& regionClipBounds); - inline BitmapTextBlob* createDrawPosTextBlob(GrRenderTarget*, const GrClip&, const GrPaint&, + inline GrAtlasTextBlob* createDrawPosTextBlob(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, diff --git a/src/gpu/GrTextBlobCache.cpp b/src/gpu/GrTextBlobCache.cpp index 6f171779fc..b1a13a866f 100644 --- a/src/gpu/GrTextBlobCache.cpp +++ b/src/gpu/GrTextBlobCache.cpp @@ -13,26 +13,26 @@ GrTextBlobCache::~GrTextBlobCache() { this->freeAll(); } -GrAtlasTextContext::BitmapTextBlob* GrTextBlobCache::createBlob(int glyphCount, int runCount, +GrAtlasTextBlob* GrTextBlobCache::createBlob(int glyphCount, int runCount, size_t maxVASize) { - // We allocate size for the BitmapTextBlob itself, plus size for the vertices array, + // We allocate size for the GrAtlasTextBlob itself, plus size for the vertices array, // and size for the glyphIds array. size_t verticesCount = glyphCount * kVerticesPerGlyph * maxVASize; - size_t size = sizeof(BitmapTextBlob) + + size_t size = sizeof(GrAtlasTextBlob) + verticesCount + glyphCount * sizeof(GrGlyph**) + - sizeof(BitmapTextBlob::Run) * runCount; + sizeof(GrAtlasTextBlob::Run) * runCount; - BitmapTextBlob* cacheBlob = SkNEW_PLACEMENT(fPool.allocate(size), BitmapTextBlob); + GrAtlasTextBlob* cacheBlob = SkNEW_PLACEMENT(fPool.allocate(size), GrAtlasTextBlob); // setup offsets for vertices / glyphs - cacheBlob->fVertices = sizeof(BitmapTextBlob) + reinterpret_cast<unsigned char*>(cacheBlob); + cacheBlob->fVertices = sizeof(GrAtlasTextBlob) + reinterpret_cast<unsigned char*>(cacheBlob); cacheBlob->fGlyphs = reinterpret_cast<GrGlyph**>(cacheBlob->fVertices + verticesCount); - cacheBlob->fRuns = reinterpret_cast<BitmapTextBlob::Run*>(cacheBlob->fGlyphs + glyphCount); + cacheBlob->fRuns = reinterpret_cast<GrAtlasTextBlob::Run*>(cacheBlob->fGlyphs + glyphCount); // Initialize runs for (int i = 0; i < runCount; i++) { - SkNEW_PLACEMENT(&cacheBlob->fRuns[i], BitmapTextBlob::Run); + SkNEW_PLACEMENT(&cacheBlob->fRuns[i], GrAtlasTextBlob::Run); } cacheBlob->fRunCount = runCount; cacheBlob->fPool = &fPool; @@ -40,9 +40,9 @@ GrAtlasTextContext::BitmapTextBlob* GrTextBlobCache::createBlob(int glyphCount, } void GrTextBlobCache::freeAll() { - SkTDynamicHash<BitmapTextBlob, BitmapTextBlob::Key>::Iter iter(&fCache); + SkTDynamicHash<GrAtlasTextBlob, GrAtlasTextBlob::Key>::Iter iter(&fCache); while (!iter.done()) { - BitmapTextBlob* blob = &(*iter); + GrAtlasTextBlob* blob = &(*iter); fBlobList.remove(blob); blob->unref(); ++iter; diff --git a/src/gpu/GrTextBlobCache.h b/src/gpu/GrTextBlobCache.h index 1776c69e7a..ca12411f7d 100644 --- a/src/gpu/GrTextBlobCache.h +++ b/src/gpu/GrTextBlobCache.h @@ -14,8 +14,6 @@ class GrTextBlobCache { public: - typedef GrAtlasTextContext::BitmapTextBlob BitmapTextBlob; - /** * 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. @@ -31,24 +29,24 @@ public: ~GrTextBlobCache(); // creates an uncached blob - BitmapTextBlob* createBlob(int glyphCount, int runCount, size_t maxVASize); - BitmapTextBlob* createBlob(const SkTextBlob* blob, size_t maxVAStride) { + 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); - BitmapTextBlob* cacheBlob = this->createBlob(glyphCount, runCount, maxVAStride); + GrAtlasTextBlob* cacheBlob = this->createBlob(glyphCount, runCount, maxVAStride); return cacheBlob; } - BitmapTextBlob* createCachedBlob(const SkTextBlob* blob, - const BitmapTextBlob::Key& key, + 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); - BitmapTextBlob* cacheBlob = this->createBlob(glyphCount, runCount, maxVAStride); + GrAtlasTextBlob* cacheBlob = this->createBlob(glyphCount, runCount, maxVAStride); cacheBlob->fKey = key; if (key.fHasBlur) { cacheBlob->fBlurRec = blurRec; @@ -62,17 +60,17 @@ public: return cacheBlob; } - BitmapTextBlob* find(const BitmapTextBlob::Key& key) { + GrAtlasTextBlob* find(const GrAtlasTextBlob::Key& key) { return fCache.find(key); } - void remove(BitmapTextBlob* blob) { + void remove(GrAtlasTextBlob* blob) { fCache.remove(blob->fKey); fBlobList.remove(blob); blob->unref(); } - void add(BitmapTextBlob* blob) { + void add(GrAtlasTextBlob* blob) { fCache.add(blob); fBlobList.addToHead(blob); @@ -80,7 +78,7 @@ public: if (fPool.size() > kBudget) { BitmapBlobList::Iter iter; iter.init(fBlobList, BitmapBlobList::Iter::kTail_IterStart); - BitmapTextBlob* lruBlob = iter.get(); + GrAtlasTextBlob* lruBlob = iter.get(); SkASSERT(lruBlob); while (fPool.size() > kBudget && (lruBlob = iter.get()) && lruBlob != blob) { fCache.remove(lruBlob->fKey); @@ -106,7 +104,7 @@ public: } } - void makeMRU(BitmapTextBlob* blob) { + void makeMRU(GrAtlasTextBlob* blob) { if (fBlobList.head() == blob) { return; } @@ -126,7 +124,7 @@ private: } } - typedef SkTInternalLList<BitmapTextBlob> BitmapBlobList; + typedef SkTInternalLList<GrAtlasTextBlob> BitmapBlobList; // 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). @@ -134,7 +132,7 @@ private: static const int kMinGrowthSize = 1 << 17; static const int kBudget = 1 << 22; BitmapBlobList fBlobList; - SkTDynamicHash<BitmapTextBlob, BitmapTextBlob::Key> fCache; + SkTDynamicHash<GrAtlasTextBlob, GrAtlasTextBlob::Key> fCache; GrMemoryPool fPool; PFOverBudgetCB fCallback; void* fData; |