Improve nvpr glyph batching

Batches together path range draws whose view matrices differ by a
simple translation by pre-translating the individual path transforms
during the copy.

BUG=skia:

Review URL: https://codereview.chromium.org/1507203002
diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp
index 77960db..d28f1a8 100644
--- a/src/gpu/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/GrStencilAndCoverTextContext.cpp
@@ -233,7 +233,7 @@
 
 class GrStencilAndCoverTextContext::FallbackBlobBuilder {
 public:
-    FallbackBlobBuilder() : fBuffIdx(0) {}
+    FallbackBlobBuilder() : fBuffIdx(0), fCount(0) {}
 
     bool isInitialized() const { return SkToBool(fBuilder); }
 
@@ -241,7 +241,7 @@
 
     void appendGlyph(uint16_t glyphId, const SkPoint& pos);
 
-    const SkTextBlob* buildIfInitialized();
+    const SkTextBlob* buildIfNeeded(int* count);
 
 private:
     enum { kWriteBufferSize = 1024 };
@@ -251,6 +251,7 @@
     SkAutoTDelete<SkTextBlobBuilder>   fBuilder;
     SkPaint                            fFont;
     int                                fBuffIdx;
+    int                                fCount;
     uint16_t                           fGlyphIds[kWriteBufferSize];
     SkPoint                            fPositions[kWriteBufferSize];
 };
@@ -261,6 +262,7 @@
     : fStroke(fontAndStroke),
       fFont(fontAndStroke),
       fTotalGlyphCount(0),
+      fFallbackGlyphCount(0),
       fDetachedGlyphCache(nullptr),
       fLastDrawnGlyphsID(SK_InvalidUniqueID) {
     SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported.
@@ -339,9 +341,6 @@
             memcpy(&builder[2 + strokeDataCount], desc, desc->getLength());
         }
     }
-
-    // When drawing from canonically sized paths, the actual local coords are fTextRatio * coords.
-    fLocalMatrixTemplate.setScale(fTextRatio, fTextRatio);
 }
 
 GrStencilAndCoverTextContext::TextRun::~TextRun() {
@@ -355,8 +354,9 @@
     SkGlyphCache* glyphCache = this->getGlyphCache();
     SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc();
 
-    fDraw.reset(GrPathRangeDraw::Create(GrPathRendering::kTranslate_PathTransformType,
-                                        fTotalGlyphCount = fFont.countText(text, byteLength)));
+    fTotalGlyphCount = fFont.countText(text, byteLength);
+    fInstanceData.reset(InstanceData::Alloc(GrPathRendering::kTranslate_PathTransformType,
+                                            fTotalGlyphCount));
 
     const char* stop = text + byteLength;
 
@@ -407,7 +407,7 @@
         fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio);
     }
 
-    fFallbackTextBlob.reset(fallback.buildIfInitialized());
+    fFallbackTextBlob.reset(fallback.buildIfNeeded(&fFallbackGlyphCount));
 }
 
 void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t byteLength,
@@ -419,8 +419,9 @@
     SkGlyphCache* glyphCache = this->getGlyphCache();
     SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc();
 
-    fDraw.reset(GrPathRangeDraw::Create(GrPathRendering::kTranslate_PathTransformType,
-                                        fTotalGlyphCount = fFont.countText(text, byteLength)));
+    fTotalGlyphCount = fFont.countText(text, byteLength);
+    fInstanceData.reset(InstanceData::Alloc(GrPathRendering::kTranslate_PathTransformType,
+                                            fTotalGlyphCount));
 
     const char* stop = text + byteLength;
 
@@ -440,7 +441,7 @@
         pos += scalarsPerPosition;
     }
 
-    fFallbackTextBlob.reset(fallback.buildIfInitialized());
+    fFallbackTextBlob.reset(fallback.buildIfNeeded(&fFallbackGlyphCount));
 }
 
 GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx) const {
@@ -470,8 +471,8 @@
         }
         fallback->appendGlyph(glyph.getGlyphID(), pos);
     } else {
-        float translate[] = { fTextInverseRatio * pos.x(), fTextInverseRatio * pos.y() };
-        fDraw->append(glyph.getGlyphID(), translate);
+        fInstanceData->append(glyph.getGlyphID(), fTextInverseRatio * pos.x(),
+                              fTextInverseRatio * pos.y());
     }
 }
 
@@ -484,10 +485,10 @@
                                                  const SkIRect& clipBounds,
                                                  GrTextContext* fallbackTextContext,
                                                  const SkPaint& originalSkPaint) const {
-    SkASSERT(fDraw);
+    SkASSERT(fInstanceData);
     SkASSERT(dc->accessRenderTarget()->isStencilBufferMultisampled() || !fFont.isAntiAlias());
 
-    if (fDraw->count()) {
+    if (fInstanceData->count()) {
         pipelineBuilder->setState(GrPipelineBuilder::kHWAntialias_Flag, fFont.isAntiAlias());
 
         GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
@@ -503,18 +504,10 @@
         SkAutoTUnref<GrPathRange> glyphs(this->createGlyphs(ctx));
         if (fLastDrawnGlyphsID != glyphs->getUniqueID()) {
             // Either this is the first draw or the glyphs object was purged since last draw.
-            glyphs->loadPathsIfNeeded(fDraw->indices(), fDraw->count());
+            glyphs->loadPathsIfNeeded(fInstanceData->indices(), fInstanceData->count());
             fLastDrawnGlyphsID = glyphs->getUniqueID();
         }
 
-        SkMatrix drawMatrix(viewMatrix);
-        drawMatrix.preTranslate(x, y);
-        drawMatrix.preScale(fTextRatio, fTextRatio);
-
-        SkMatrix& localMatrix = fLocalMatrixTemplate;
-        localMatrix.setTranslateX(x);
-        localMatrix.setTranslateY(y);
-
         // Don't compute a bounding box. For dst copy texture, we'll opt instead for it to just copy
         // the entire dst. Realistically this is a moot point, because any context that supports
         // NV_path_rendering will also support NV_blend_equation_advanced.
@@ -524,8 +517,9 @@
                                         pipelineBuilder->getRenderTarget()->height());
 
         SkAutoTUnref<GrDrawPathBatchBase> batch(
-            GrDrawPathRangeBatch::Create(drawMatrix, localMatrix, color,
-                                         GrPathRendering::kWinding_FillType, glyphs, fDraw,
+            GrDrawPathRangeBatch::Create(viewMatrix, fTextRatio, fTextInverseRatio * x,
+                                         fTextInverseRatio * y, color,
+                                         GrPathRendering::kWinding_FillType, glyphs, fInstanceData,
                                          bounds));
 
         dc->drawPathBatch(*pipelineBuilder, batch);
@@ -559,11 +553,11 @@
 }
 
 size_t GrStencilAndCoverTextContext::TextRun::computeSizeInCache() const {
-    size_t size = sizeof(TextRun) +
-               fGlyphPathsKey.size() +
-               fTotalGlyphCount * (sizeof(uint16_t) + 2 * sizeof(float));
-    if (fDraw) {
-        size += sizeof(GrPathRangeDraw);
+    size_t size = sizeof(TextRun) + fGlyphPathsKey.size();
+    // The instance data always reserves enough space for every glyph.
+    size += (fTotalGlyphCount + fFallbackGlyphCount) * (sizeof(uint16_t) + 2 * sizeof(float));
+    if (fInstanceData) {
+        size += sizeof(InstanceData);
     }
     if (fFallbackTextBlob) {
         size += sizeof(SkTextBlob);
@@ -596,6 +590,7 @@
     fGlyphIds[fBuffIdx] = glyphId;
     fPositions[fBuffIdx] = pos;
     fBuffIdx++;
+    fCount++;
 }
 
 void GrStencilAndCoverTextContext::FallbackBlobBuilder::flush() {
@@ -611,10 +606,11 @@
     fBuffIdx = 0;
 }
 
-const SkTextBlob* GrStencilAndCoverTextContext::FallbackBlobBuilder::buildIfInitialized() {
-    if (!this->isInitialized()) {
-        return nullptr;
+const SkTextBlob* GrStencilAndCoverTextContext::FallbackBlobBuilder::buildIfNeeded(int *count) {
+    *count = fCount;
+    if (fCount) {
+        this->flush();
+        return fBuilder->build();
     }
-    this->flush();
-    return fBuilder->build();
+    return nullptr;
 }