aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar joshualitt <joshualitt@chromium.org>2015-04-06 10:53:36 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-04-06 10:53:36 -0700
commit9a27e639481882b59a8ef123e0b69a9a719f08b9 (patch)
tree1ca6f42eaa7c535f52d907a722a38280abab7a37
parent94e50100eb747b2dfd659bacc9cf4246f6f20278 (diff)
Handle large paths in textblobs
-rw-r--r--src/gpu/GrAtlasTextContext.cpp175
-rw-r--r--src/gpu/GrAtlasTextContext.h59
2 files changed, 169 insertions, 65 deletions
diff --git a/src/gpu/GrAtlasTextContext.cpp b/src/gpu/GrAtlasTextContext.cpp
index b2de1cf154..08e6a9a25e 100644
--- a/src/gpu/GrAtlasTextContext.cpp
+++ b/src/gpu/GrAtlasTextContext.cpp
@@ -93,14 +93,6 @@ bool GrAtlasTextContext::canDraw(const GrRenderTarget*,
return !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix);
}
-inline void GrAtlasTextContext::init(GrRenderTarget* rt, const GrClip& clip,
- const GrPaint& paint, const SkPaint& skPaint,
- const SkIRect& regionClipBounds) {
- INHERITED::init(rt, clip, paint, skPaint, regionClipBounds);
-
- fCurrStrike = NULL;
-}
-
bool GrAtlasTextContext::MustRegenerateBlob(const BitmapTextBlob& blob, const SkPaint& paint,
const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
// We always regenerate blobs with patheffects or mask filters we could cache these
@@ -192,8 +184,8 @@ void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip,
GrPaint grPaint;
SkPaint2GrPaintShader(fContext, rt, skPaint, viewMatrix, true, &grPaint);
- this->flush(fContext->getTextTarget(), cacheBlob, rt, grPaint, clip, viewMatrix,
- fSkPaint.getAlpha());
+ this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint, drawFilter,
+ clip, viewMatrix, clipBounds, x, y);
}
void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob,
@@ -238,6 +230,12 @@ void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob,
newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex;
}
+ if (SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix)) {
+ cacheBlob->fRuns[run].fDrawAsPaths = true;
+ continue;
+ }
+ cacheBlob->fRuns[run].fDrawAsPaths = false;
+
switch (it.positioning()) {
case SkTextBlob::kDefault_Positioning:
this->internalDrawText(cacheBlob, run, cache, runPaint, viewMatrix,
@@ -285,7 +283,7 @@ void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip,
this->internalDrawText(blob, 0, cache, skPaint, viewMatrix, text, byteLength, x, y, clipRect);
SkGlyphCache::AttachCache(cache);
- this->flush(fContext->getTextTarget(), blob, rt, paint, clip, viewMatrix, skPaint.getAlpha());
+ this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip, viewMatrix);
}
void GrAtlasTextContext::internalDrawText(BitmapTextBlob* blob, int runIndex,
@@ -398,7 +396,7 @@ void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip,
scalarsPerPosition, offset, clipRect);
SkGlyphCache::AttachCache(cache);
- this->flush(fContext->getTextTarget(), blob, rt, paint, clip, viewMatrix, fSkPaint.getAlpha());
+ this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip, viewMatrix);
}
void GrAtlasTextContext::internalDrawPosText(BitmapTextBlob* blob, int runIndex,
@@ -694,9 +692,9 @@ public:
GrColor fColor;
};
- static GrBatch* Create(const Geometry& geometry, GrColor color, GrMaskFormat maskFormat,
+ static GrBatch* Create(const Geometry& geometry, GrMaskFormat maskFormat,
int glyphCount, GrBatchFontCache* fontCache) {
- return SkNEW_ARGS(BitmapTextBatch, (geometry, color, maskFormat, glyphCount, fontCache));
+ return SkNEW_ARGS(BitmapTextBatch, (geometry, maskFormat, glyphCount, fontCache));
}
const char* name() const override { return "BitmapTextBatch"; }
@@ -893,14 +891,14 @@ public:
SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
private:
- BitmapTextBatch(const Geometry& geometry, GrColor color, GrMaskFormat maskFormat,
+ BitmapTextBatch(const Geometry& geometry, GrMaskFormat maskFormat,
int glyphCount, GrBatchFontCache* fontCache)
: fMaskFormat(maskFormat)
, fPixelConfig(fontCache->getPixelConfig(maskFormat))
, fFontCache(fontCache) {
this->initClassID<BitmapTextBatch>();
fGeoData.push_back(geometry);
- fBatch.fColor = color;
+ fBatch.fColor = geometry.fColor;
fBatch.fViewMatrix = geometry.fBlob->fViewMatrix;
fBatch.fNumGlyphs = glyphCount;
}
@@ -1015,47 +1013,128 @@ private:
GrBatchFontCache* fFontCache;
};
-void GrAtlasTextContext::flush(GrDrawTarget* target, BitmapTextBlob* blob, GrRenderTarget* rt,
- const GrPaint& paint, const GrClip& clip,
- const SkMatrix& viewMatrix, int paintAlpha) {
- GrPipelineBuilder pipelineBuilder;
- pipelineBuilder.setFromPaint(paint, rt, clip);
+void GrAtlasTextContext::flushRunAsPaths(const SkTextBlob::RunIterator& it, const SkPaint& skPaint,
+ SkDrawFilter* drawFilter, const SkMatrix& viewMatrix,
+ const SkIRect& clipBounds, SkScalar x, SkScalar y) {
+ SkPaint runPaint = skPaint;
- GrColor color = paint.getColor();
- for (uint32_t run = 0; run < blob->fRunCount; run++) {
- for (int subRun = 0; subRun < blob->fRuns[run].fSubRunInfo.count(); subRun++) {
- PerSubRunInfo& info = blob->fRuns[run].fSubRunInfo[subRun];
- int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
- if (0 == glyphCount) {
- continue;
- }
+ size_t textLen = it.glyphCount() * sizeof(uint16_t);
+ const SkPoint& offset = it.offset();
- GrMaskFormat format = info.fMaskFormat;
- GrColor subRunColor = kARGB_GrMaskFormat == format ?
- SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha) :
- color;
-
- BitmapTextBatch::Geometry geometry;
- geometry.fBlob.reset(SkRef(blob));
- geometry.fRun = run;
- geometry.fSubRun = subRun;
- geometry.fColor = color;
- SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, subRunColor, format,
- glyphCount,
- fContext->getBatchFontCache()));
-
- target->drawBatch(&pipelineBuilder, batch, &blob->fRuns[run].fVertexBounds);
+ it.applyFontToPaint(&runPaint);
+
+ if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Type)) {
+ return;
+ }
+
+ runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint));
+
+ switch (it.positioning()) {
+ case SkTextBlob::kDefault_Positioning:
+ this->drawTextAsPath(runPaint, viewMatrix, (const char *)it.glyphs(),
+ textLen, x + offset.x(), y + offset.y(), clipBounds);
+ break;
+ case SkTextBlob::kHorizontal_Positioning:
+ this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs(),
+ textLen, it.pos(), 1, SkPoint::Make(x, y + offset.y()),
+ clipBounds);
+ break;
+ case SkTextBlob::kFull_Positioning:
+ this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs(),
+ textLen, it.pos(), 2, SkPoint::Make(x, y), clipBounds);
+ break;
+ }
+}
+
+inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder* pipelineBuilder,
+ BitmapTextBlob* cacheBlob, int run, GrColor color,
+ uint8_t paintAlpha) {
+ for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); subRun++) {
+ const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun];
+ int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
+ if (0 == glyphCount) {
+ continue;
}
+
+ GrMaskFormat format = info.fMaskFormat;
+ GrColor subRunColor = kARGB_GrMaskFormat == format ?
+ SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha) :
+ color;
+
+ BitmapTextBatch::Geometry geometry;
+ geometry.fBlob.reset(SkRef(cacheBlob));
+ geometry.fRun = run;
+ geometry.fSubRun = subRun;
+ geometry.fColor = subRunColor;
+ SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, format, glyphCount,
+ fContext->getBatchFontCache()));
+
+ target->drawBatch(pipelineBuilder, batch, &cacheBlob->fRuns[run].fVertexBounds);
}
+}
- // Now flush big glyphs
- for (int i = 0; i < blob->fBigGlyphs.count(); i++) {
- BitmapTextBlob::BigGlyph& bigGlyph = blob->fBigGlyphs[i];
+inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRenderTarget* rt,
+ const GrPaint& grPaint, const GrClip& clip) {
+ for (int i = 0; i < cacheBlob->fBigGlyphs.count(); i++) {
+ const BitmapTextBlob::BigGlyph& bigGlyph = cacheBlob->fBigGlyphs[i];
SkMatrix translate;
translate.setTranslate(SkIntToScalar(bigGlyph.fVx), SkIntToScalar(bigGlyph.fVy));
SkPath tmpPath(bigGlyph.fPath);
tmpPath.transform(translate);
GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
- fContext->drawPath(rt, clip, paint, SkMatrix::I(), tmpPath, strokeInfo);
+ fContext->drawPath(rt, clip, grPaint, SkMatrix::I(), tmpPath, strokeInfo);
}
}
+
+void GrAtlasTextContext::flush(GrDrawTarget* target,
+ const SkTextBlob* blob,
+ BitmapTextBlob* cacheBlob,
+ GrRenderTarget* rt,
+ const SkPaint& skPaint,
+ const GrPaint& grPaint,
+ SkDrawFilter* drawFilter,
+ const GrClip& clip,
+ const SkMatrix& viewMatrix,
+ const SkIRect& clipBounds,
+ SkScalar x,
+ SkScalar y) {
+ // We loop through the runs of the blob, flushing each. If any run is too large, then we flush
+ // it as paths
+ GrPipelineBuilder pipelineBuilder;
+ pipelineBuilder.setFromPaint(grPaint, rt, clip);
+
+ GrColor color = grPaint.getColor();
+ uint8_t paintAlpha = skPaint.getAlpha();
+
+ SkTextBlob::RunIterator it(blob);
+ for (int run = 0; !it.done(); it.next(), run++) {
+ if (cacheBlob->fRuns[run].fDrawAsPaths) {
+ this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBounds, x, y);
+ continue;
+ }
+ this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlpha);
+ }
+
+ // Now flush big glyphs
+ this->flushBigGlyphs(cacheBlob, rt, grPaint, clip);
+}
+
+void GrAtlasTextContext::flush(GrDrawTarget* target,
+ BitmapTextBlob* cacheBlob,
+ GrRenderTarget* rt,
+ const SkPaint& skPaint,
+ const GrPaint& grPaint,
+ const GrClip& clip,
+ const SkMatrix& viewMatrix) {
+ GrPipelineBuilder pipelineBuilder;
+ pipelineBuilder.setFromPaint(grPaint, rt, clip);
+
+ GrColor color = grPaint.getColor();
+ uint8_t paintAlpha = skPaint.getAlpha();
+ for (int run = 0; run < cacheBlob->fRunCount; run++) {
+ this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlpha);
+ }
+
+ // Now flush big glyphs
+ this->flushBigGlyphs(cacheBlob, rt, grPaint, clip);
+}
diff --git a/src/gpu/GrAtlasTextContext.h b/src/gpu/GrAtlasTextContext.h
index eb1abbac42..de07d1f474 100644
--- a/src/gpu/GrAtlasTextContext.h
+++ b/src/gpu/GrAtlasTextContext.h
@@ -12,6 +12,7 @@
#include "GrGeometryProcessor.h"
#include "SkDescriptor.h"
+#include "SkTextBlob.h"
#include "SkTHash.h"
class GrBatchTextStrike;
@@ -45,9 +46,6 @@ private:
const SkMatrix& viewMatrix, const SkTextBlob*, SkScalar x, SkScalar y,
SkDrawFilter*, const SkIRect& clipBounds) override;
- void init(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&,
- const SkIRect& regionClipBounds);
-
/*
* 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
@@ -60,19 +58,32 @@ private:
* TODO this is currently a bug
*/
struct BitmapTextBlob : public SkRefCnt {
- // 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.
+ /*
+ * 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) {
+ Run() : fColor(GrColor_ILLEGAL), fInitialized(false), fDrawAsPaths(false) {
fVertexBounds.setLargestInverted();
// We insert the first subrun to gurantee a run always has atleast one subrun.
// We do this to simplify things when we 'hand off' data from one subrun to the
@@ -99,6 +110,7 @@ private:
SkRect fVertexBounds;
GrColor fColor;
bool fInitialized;
+ bool fDrawAsPaths;
};
struct BigGlyph {
@@ -113,7 +125,7 @@ private:
SkScalar fX;
SkScalar fY;
SkPaint::Style fStyle;
- uint32_t fRunCount;
+ int fRunCount;
// all glyph / vertex offsets are into these pools.
unsigned char* fVertices;
@@ -143,8 +155,21 @@ private:
void appendGlyph(BitmapTextBlob*, int runIndex, GrGlyph::PackedID, int left, int top,
GrColor color, GrFontScaler*, const SkIRect& clipRect);
- void flush(GrDrawTarget*, BitmapTextBlob*, GrRenderTarget*, const GrPaint&, const GrClip&,
- const SkMatrix& viewMatrix, int paintAlpha);
+
+ inline void flushRunAsPaths(const SkTextBlob::RunIterator&, const SkPaint&, SkDrawFilter*,
+ const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x,
+ SkScalar y);
+ inline void flushRun(GrDrawTarget*, GrPipelineBuilder*, BitmapTextBlob*, int run, GrColor,
+ uint8_t paintAlpha);
+ inline void flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRenderTarget* rt,
+ const GrPaint& grPaint, const GrClip& clip);
+
+ // We have to flush SkTextBlobs differently from drawText / drawPosText
+ void flush(GrDrawTarget*, const SkTextBlob*, BitmapTextBlob*, GrRenderTarget*, const SkPaint&,
+ const GrPaint&, SkDrawFilter*, const GrClip&, const SkMatrix& viewMatrix,
+ const SkIRect& clipBounds, SkScalar x, SkScalar y);
+ void flush(GrDrawTarget*, BitmapTextBlob*, GrRenderTarget*, const SkPaint&,
+ const GrPaint&, const GrClip&, const SkMatrix& viewMatrix);
void internalDrawText(BitmapTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&,
const SkMatrix& viewMatrix, const char text[], size_t byteLength,