Rename GrAtlasTextBatch files to GrAtlasTextOp
authorBrian Salomon <bsalomon@google.com>
Thu, 15 Dec 2016 15:20:35 +0000 (10:20 -0500)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Thu, 15 Dec 2016 16:28:59 +0000 (16:28 +0000)
Change-Id: I3ce7321577c236a95811d7a2da798d4eb2e0cbd3
Reviewed-on: https://skia-review.googlesource.com/6116
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>

gn/gpu.gni
src/gpu/batches/GrAtlasTextBatch.cpp [deleted file]
src/gpu/batches/GrAtlasTextBatch.h [deleted file]
src/gpu/batches/GrAtlasTextOp.cpp [new file with mode: 0644]
src/gpu/batches/GrAtlasTextOp.h [new file with mode: 0644]
src/gpu/text/GrAtlasTextBlob.cpp
src/gpu/text/GrAtlasTextBlob_regenInBatch.cpp

index 805a062c4cda46af246e893737cadd029ebb6baf..23ee07eac643d6f6da45d4cdca60633554656f8c 100644 (file)
@@ -241,8 +241,8 @@ skia_gpu_sources = [
   "$_src/gpu/batches/GrAAStrokeRectOp.h",
   "$_src/gpu/batches/GrAnalyticRectOp.cpp",
   "$_src/gpu/batches/GrAnalyticRectOp.h",
-  "$_src/gpu/batches/GrAtlasTextBatch.cpp",
-  "$_src/gpu/batches/GrAtlasTextBatch.h",
+  "$_src/gpu/batches/GrAtlasTextOp.cpp",
+  "$_src/gpu/batches/GrAtlasTextOp.h",
   "$_src/gpu/batches/GrClearOp.h",
   "$_src/gpu/batches/GrClearStencilClipOp.h",
   "$_src/gpu/batches/GrCopySurfaceOp.cpp",
diff --git a/src/gpu/batches/GrAtlasTextBatch.cpp b/src/gpu/batches/GrAtlasTextBatch.cpp
deleted file mode 100644 (file)
index 1b45095..0000000
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrAtlasTextBatch.h"
-
-#include "GrOpFlushState.h"
-#include "GrResourceProvider.h"
-
-#include "SkGlyphCache.h"
-#include "SkMathPriv.h"
-
-#include "effects/GrBitmapTextGeoProc.h"
-#include "effects/GrDistanceFieldGeoProc.h"
-#include "text/GrBatchFontCache.h"
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
-    unsigned r = SkColorGetR(c);
-    unsigned g = SkColorGetG(c);
-    unsigned b = SkColorGetB(c);
-    return GrColorPackRGBA(r, g, b, 0xff);
-}
-
-static const int kDistanceAdjustLumShift = 5;
-
-SkString GrAtlasTextBatch::dumpInfo() const {
-    SkString str;
-
-    for (int i = 0; i < fGeoCount; ++i) {
-        str.appendf("%d: Color: 0x%08x Trans: %.2f,%.2f Runs: %d\n",
-                    i,
-                    fGeoData[i].fColor,
-                    fGeoData[i].fX,
-                    fGeoData[i].fY,
-                    fGeoData[i].fBlob->runCount());
-    }
-
-    str.append(DumpPipelineInfo(*this->pipeline()));
-    str.append(INHERITED::dumpInfo());
-    return str;
-}
-
-void GrAtlasTextBatch::computePipelineOptimizations(GrInitInvariantOutput* color,
-                                                    GrInitInvariantOutput* coverage,
-                                                    GrBatchToXPOverrides* overrides) const {
-    if (kColorBitmapMask_MaskType == fMaskType) {
-        color->setUnknownFourComponents();
-    } else {
-        color->setKnownFourComponents(fBatch.fColor);
-    }
-    switch (fMaskType) {
-        case kGrayscaleDistanceField_MaskType:
-        case kGrayscaleCoverageMask_MaskType:
-            coverage->setUnknownSingleComponent();
-            break;
-        case kLCDCoverageMask_MaskType:
-        case kLCDDistanceField_MaskType:
-            coverage->setUnknownOpaqueFourComponents();
-            coverage->setUsingLCDCoverage();
-            break;
-        case kColorBitmapMask_MaskType:
-            coverage->setKnownSingleComponent(0xff);
-    }
-}
-
-void GrAtlasTextBatch::initBatchTracker(const GrXPOverridesForBatch& overrides) {
-    // Handle any color overrides
-    if (!overrides.readsColor()) {
-        fGeoData[0].fColor = GrColor_ILLEGAL;
-    }
-    overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
-
-    // setup batch properties
-    fBatch.fColorIgnored = !overrides.readsColor();
-    fBatch.fColor = fGeoData[0].fColor;
-    fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
-    fBatch.fCoverageIgnored = !overrides.readsCoverage();
-}
-
-void GrAtlasTextBatch::onPrepareDraws(Target* target) const {
-    // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix.
-    // TODO actually only invert if we don't have RGBA
-    SkMatrix localMatrix;
-    if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
-        SkDebugf("Cannot invert viewmatrix\n");
-        return;
-    }
-
-    GrTexture* texture = fFontCache->getTexture(this->maskFormat());
-    if (!texture) {
-        SkDebugf("Could not allocate backing texture for atlas\n");
-        return;
-    }
-
-    GrMaskFormat maskFormat = this->maskFormat();
-
-    FlushInfo flushInfo;
-    if (this->usesDistanceFields()) {
-        flushInfo.fGeometryProcessor =
-            this->setupDfProcessor(this->viewMatrix(), fFilteredColor, this->color(), texture);
-    } else {
-        GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
-        flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(this->color(),
-                                                                 texture,
-                                                                 params,
-                                                                 maskFormat,
-                                                                 localMatrix,
-                                                                 this->usesLocalCoords());
-    }
-
-    flushInfo.fGlyphsToFlush = 0;
-    size_t vertexStride = flushInfo.fGeometryProcessor->getVertexStride();
-    SkASSERT(vertexStride == GrAtlasTextBlob::GetVertexStride(maskFormat));
-
-    int glyphCount = this->numGlyphs();
-    const GrBuffer* vertexBuffer;
-
-    void* vertices = target->makeVertexSpace(vertexStride,
-                                             glyphCount * kVerticesPerGlyph,
-                                             &vertexBuffer,
-                                             &flushInfo.fVertexOffset);
-    flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer));
-    flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer());
-    if (!vertices || !flushInfo.fVertexBuffer) {
-        SkDebugf("Could not allocate vertices\n");
-        return;
-    }
-
-    unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices);
-
-    GrBlobRegenHelper helper(this, target, &flushInfo);
-    SkAutoGlyphCache glyphCache;
-    for (int i = 0; i < fGeoCount; i++) {
-        const Geometry& args = fGeoData[i];
-        Blob* blob = args.fBlob;
-        size_t byteCount;
-        void* blobVertices;
-        int subRunGlyphCount;
-        blob->regenInBatch(target, fFontCache, &helper, args.fRun, args.fSubRun, &glyphCache,
-                           vertexStride, args.fViewMatrix, args.fX, args.fY, args.fColor,
-                           &blobVertices, &byteCount, &subRunGlyphCount);
-
-        // now copy all vertices
-        memcpy(currVertex, blobVertices, byteCount);
-
-#ifdef SK_DEBUG
-        // bounds sanity check
-        SkRect rect;
-        rect.setLargestInverted();
-        SkPoint* vertex = (SkPoint*) ((char*)blobVertices);
-        rect.growToInclude(vertex, vertexStride, kVerticesPerGlyph * subRunGlyphCount);
-
-        if (this->usesDistanceFields()) {
-            args.fViewMatrix.mapRect(&rect);
-        }
-        // Allow for small numerical error in the bounds.
-        SkRect bounds = this->bounds();
-        bounds.outset(0.001f, 0.001f);
-        SkASSERT(bounds.contains(rect));
-#endif
-
-        currVertex += byteCount;
-    }
-
-    this->flush(target, &flushInfo);
-}
-
-void GrAtlasTextBatch::flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const {
-    GrMesh mesh;
-    int maxGlyphsPerDraw =
-        static_cast<int>(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(uint16_t) / 6);
-    mesh.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer.get(),
-                       flushInfo->fIndexBuffer.get(), flushInfo->fVertexOffset,
-                       kVerticesPerGlyph, kIndicesPerGlyph, flushInfo->fGlyphsToFlush,
-                       maxGlyphsPerDraw);
-    target->draw(flushInfo->fGeometryProcessor.get(), mesh);
-    flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush;
-    flushInfo->fGlyphsToFlush = 0;
-}
-
-bool GrAtlasTextBatch::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
-    GrAtlasTextBatch* that = t->cast<GrAtlasTextBatch>();
-    if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
-                                that->bounds(), caps)) {
-        return false;
-    }
-
-    if (fMaskType != that->fMaskType) {
-        return false;
-    }
-
-    if (!this->usesDistanceFields()) {
-        if (kColorBitmapMask_MaskType == fMaskType && this->color() != that->color()) {
-            return false;
-        }
-        if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
-            return false;
-        }
-    } else {
-        if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
-            return false;
-        }
-
-        if (fFilteredColor != that->fFilteredColor) {
-            return false;
-        }
-
-        if (fUseBGR != that->fUseBGR) {
-            return false;
-        }
-    }
-
-    fBatch.fNumGlyphs += that->numGlyphs();
-
-    // Reallocate space for geo data if necessary and then import that's geo data.
-    int newGeoCount = that->fGeoCount + fGeoCount;
-    // We assume (and here enforce) that the allocation size is the smallest power of two that
-    // is greater than or equal to the number of geometries (and at least
-    // kMinGeometryAllocated).
-    int newAllocSize = GrNextPow2(newGeoCount);
-    int currAllocSize = SkTMax<int>(kMinGeometryAllocated, GrNextPow2(fGeoCount));
-
-    if (newGeoCount > currAllocSize) {
-        fGeoData.realloc(newAllocSize);
-    }
-
-    memcpy(&fGeoData[fGeoCount], that->fGeoData.get(), that->fGeoCount * sizeof(Geometry));
-    // We steal the ref on the blobs from the other TextBatch and set its count to 0 so that
-    // it doesn't try to unref them.
-#ifdef SK_DEBUG
-    for (int i = 0; i < that->fGeoCount; ++i) {
-        that->fGeoData.get()[i].fBlob = (Blob*)0x1;
-    }
-#endif
-    that->fGeoCount = 0;
-    fGeoCount = newGeoCount;
-
-    this->joinBounds(*that);
-    return true;
-}
-
-// TODO just use class params
-// TODO trying to figure out why lcd is so whack
-sk_sp<GrGeometryProcessor> GrAtlasTextBatch::setupDfProcessor(const SkMatrix& viewMatrix,
-                                                              SkColor filteredColor,
-                                                              GrColor color,
-                                                              GrTexture* texture) const {
-    GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode);
-    bool isLCD = this->isLCD();
-    // set up any flags
-    uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
-    flags |= viewMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
-    flags |= fUseGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
-
-    // see if we need to create a new effect
-    if (isLCD) {
-        flags |= kUseLCD_DistanceFieldEffectFlag;
-        flags |= fUseBGR ? kBGR_DistanceFieldEffectFlag : 0;
-
-        GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
-
-        float redCorrection = fDistanceAdjustTable->getAdjustment(
-            GrColorUnpackR(colorNoPreMul) >> kDistanceAdjustLumShift,
-            fUseGammaCorrectDistanceTable);
-        float greenCorrection = fDistanceAdjustTable->getAdjustment(
-            GrColorUnpackG(colorNoPreMul) >> kDistanceAdjustLumShift,
-            fUseGammaCorrectDistanceTable);
-        float blueCorrection = fDistanceAdjustTable->getAdjustment(
-            GrColorUnpackB(colorNoPreMul) >> kDistanceAdjustLumShift,
-            fUseGammaCorrectDistanceTable);
-        GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
-            GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(redCorrection,
-                                                                greenCorrection,
-                                                                blueCorrection);
-
-        return GrDistanceFieldLCDTextGeoProc::Make(color,
-                                                   viewMatrix,
-                                                   texture,
-                                                   params,
-                                                   widthAdjust,
-                                                   flags,
-                                                   this->usesLocalCoords());
-    } else {
-#ifdef SK_GAMMA_APPLY_TO_A8
-        U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, filteredColor);
-        float correction = fDistanceAdjustTable->getAdjustment(
-            lum >> kDistanceAdjustLumShift, fUseGammaCorrectDistanceTable);
-        return GrDistanceFieldA8TextGeoProc::Make(color,
-                                                  viewMatrix,
-                                                  texture,
-                                                  params,
-                                                  correction,
-                                                  flags,
-                                                  this->usesLocalCoords());
-#else
-        return GrDistanceFieldA8TextGeoProc::Make(color,
-                                                  viewMatrix,
-                                                  texture,
-                                                  params,
-                                                  flags,
-                                                  this->usesLocalCoords());
-#endif
-    }
-
-}
-
-void GrBlobRegenHelper::flush() {
-    fBatch->flush(fTarget, fFlushInfo);
-}
diff --git a/src/gpu/batches/GrAtlasTextBatch.h b/src/gpu/batches/GrAtlasTextBatch.h
deleted file mode 100644 (file)
index 313a78e..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * 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 GrAtlasTextBatch_DEFINED
-#define GrAtlasTextBatch_DEFINED
-
-#include "batches/GrMeshDrawOp.h"
-
-#include "text/GrAtlasTextContext.h"
-#include "text/GrDistanceFieldAdjustTable.h"
-
-class GrAtlasTextBatch final : public GrMeshDrawOp {
-public:
-    DEFINE_OP_CLASS_ID
-
-    static const int kVerticesPerGlyph = GrAtlasTextBlob::kVerticesPerGlyph;
-    static const int kIndicesPerGlyph = 6;
-
-    typedef GrAtlasTextBlob Blob;
-    struct Geometry {
-        SkMatrix fViewMatrix;
-        Blob* fBlob;
-        SkScalar fX;
-        SkScalar fY;
-        int fRun;
-        int fSubRun;
-        GrColor fColor;
-    };
-
-    static GrAtlasTextBatch* CreateBitmap(GrMaskFormat maskFormat, int glyphCount,
-                                          GrBatchFontCache* fontCache) {
-        GrAtlasTextBatch* batch = new GrAtlasTextBatch;
-
-        batch->fFontCache = fontCache;
-        switch (maskFormat) {
-            case kA8_GrMaskFormat:
-                batch->fMaskType = kGrayscaleCoverageMask_MaskType;
-                break;
-            case kA565_GrMaskFormat:
-                batch->fMaskType = kLCDCoverageMask_MaskType;
-                break;
-            case kARGB_GrMaskFormat:
-                batch->fMaskType = kColorBitmapMask_MaskType;
-                break;
-        }
-        batch->fBatch.fNumGlyphs = glyphCount;
-        batch->fGeoCount = 1;
-        batch->fFilteredColor = 0;
-        batch->fFontCache = fontCache;
-        batch->fUseBGR = false;
-        return batch;
-    }
-
-    static GrAtlasTextBatch* CreateDistanceField(
-                                              int glyphCount, GrBatchFontCache* fontCache,
-                                              const GrDistanceFieldAdjustTable* distanceAdjustTable,
-                                              bool useGammaCorrectDistanceTable,
-                                              SkColor filteredColor, bool isLCD,
-                                              bool useBGR) {
-        GrAtlasTextBatch* batch = new GrAtlasTextBatch;
-
-        batch->fFontCache = fontCache;
-        batch->fMaskType = isLCD ? kLCDDistanceField_MaskType : kGrayscaleDistanceField_MaskType;
-        batch->fDistanceAdjustTable.reset(SkRef(distanceAdjustTable));
-        batch->fUseGammaCorrectDistanceTable = useGammaCorrectDistanceTable;
-        batch->fFilteredColor = filteredColor;
-        batch->fUseBGR = useBGR;
-        batch->fBatch.fNumGlyphs = glyphCount;
-        batch->fGeoCount = 1;
-        return batch;
-    }
-
-    // to avoid even the initial copy of the struct, we have a getter for the first item which
-    // is used to seed the batch with its initial geometry.  After seeding, the client should call
-    // init() so the Batch can initialize itself
-    Geometry& geometry() { return fGeoData[0]; }
-
-    void init() {
-        const Geometry& geo = fGeoData[0];
-        fBatch.fColor = geo.fColor;
-        SkRect bounds;
-        geo.fBlob->computeSubRunBounds(&bounds, geo.fRun, geo.fSubRun, geo.fViewMatrix, geo.fX,
-                                       geo.fY);
-        // We don't have tight bounds on the glyph paths in device space. For the purposes of bounds
-        // we treat this as a set of non-AA rects rendered with a texture.
-        this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
-    }
-
-    const char* name() const override { return "TextBatch"; }
-
-    SkString dumpInfo() const override;
-
-protected:
-    void computePipelineOptimizations(GrInitInvariantOutput* color,
-                                      GrInitInvariantOutput* coverage,
-                                      GrBatchToXPOverrides* overrides) const override;
-
-
-private:
-    void initBatchTracker(const GrXPOverridesForBatch& overrides) override;
-
-    struct FlushInfo {
-        sk_sp<const GrBuffer>      fVertexBuffer;
-        sk_sp<const GrBuffer>      fIndexBuffer;
-        sk_sp<GrGeometryProcessor> fGeometryProcessor;
-        int                        fGlyphsToFlush;
-        int                        fVertexOffset;
-    };
-
-    void onPrepareDraws(Target* target) const override;
-
-    GrAtlasTextBatch() : INHERITED(ClassID()) {} // initialized in factory functions.
-
-    ~GrAtlasTextBatch() {
-        for (int i = 0; i < fGeoCount; i++) {
-            fGeoData[i].fBlob->unref();
-        }
-    }
-
-    GrMaskFormat maskFormat() const {
-        switch (fMaskType) {
-            case kLCDCoverageMask_MaskType:
-                return kA565_GrMaskFormat;
-            case kColorBitmapMask_MaskType:
-                return kARGB_GrMaskFormat;
-            case kGrayscaleCoverageMask_MaskType:
-            case kGrayscaleDistanceField_MaskType:
-            case kLCDDistanceField_MaskType:
-                return kA8_GrMaskFormat;
-        }
-        return kA8_GrMaskFormat; // suppress warning
-    }
-
-    bool usesDistanceFields() const {
-        return kGrayscaleDistanceField_MaskType == fMaskType ||
-               kLCDDistanceField_MaskType == fMaskType;
-    }
-
-    bool isLCD() const {
-        return kLCDCoverageMask_MaskType == fMaskType ||
-               kLCDDistanceField_MaskType == fMaskType;
-    }
-
-    inline void flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const;
-
-    GrColor color() const { return fBatch.fColor; }
-    const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
-    bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
-    int numGlyphs() const { return fBatch.fNumGlyphs; }
-
-    bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override;
-
-    // TODO just use class params
-    // TODO trying to figure out why lcd is so whack
-    sk_sp<GrGeometryProcessor> setupDfProcessor(const SkMatrix& viewMatrix, SkColor filteredColor,
-                                                GrColor color, GrTexture* texture) const;
-
-    struct BatchTracker {
-        GrColor fColor;
-        bool fUsesLocalCoords;
-        bool fColorIgnored;
-        bool fCoverageIgnored;
-        int fNumGlyphs;
-    };
-
-    BatchTracker fBatch;
-    // The minimum number of Geometry we will try to allocate.
-    enum { kMinGeometryAllocated = 4 };
-    SkAutoSTMalloc<kMinGeometryAllocated, Geometry> fGeoData;
-    int fGeoCount;
-
-    enum MaskType {
-        kGrayscaleCoverageMask_MaskType,
-        kLCDCoverageMask_MaskType,
-        kColorBitmapMask_MaskType,
-        kGrayscaleDistanceField_MaskType,
-        kLCDDistanceField_MaskType,
-    } fMaskType;
-    bool fUseBGR; // fold this into the enum?
-
-    GrBatchFontCache* fFontCache;
-
-    // Distance field properties
-    sk_sp<const GrDistanceFieldAdjustTable> fDistanceAdjustTable;
-    SkColor fFilteredColor;
-    bool fUseGammaCorrectDistanceTable;
-
-    friend class GrBlobRegenHelper; // Needs to trigger flushes
-
-    typedef GrMeshDrawOp INHERITED;
-};
-
-/*
- * A simple helper class to abstract the interface GrAtlasTextBlob needs to regenerate itself.
- * It'd be nicer if this was nested, but we need to forward declare it in GrAtlasTextBlob.h
- */
-class GrBlobRegenHelper {
-public:
-    GrBlobRegenHelper(const GrAtlasTextBatch* batch, GrMeshDrawOp::Target* target,
-                      GrAtlasTextBatch::FlushInfo* flushInfo)
-        : fBatch(batch), fTarget(target), fFlushInfo(flushInfo) {}
-
-    void flush();
-
-    void incGlyphCount(int glyphCount = 1) {
-        fFlushInfo->fGlyphsToFlush += glyphCount;
-    }
-
-private:
-    const GrAtlasTextBatch* fBatch;
-    GrMeshDrawOp::Target* fTarget;
-    GrAtlasTextBatch::FlushInfo* fFlushInfo;
-};
-
-#endif
diff --git a/src/gpu/batches/GrAtlasTextOp.cpp b/src/gpu/batches/GrAtlasTextOp.cpp
new file mode 100644 (file)
index 0000000..0b692d1
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrAtlasTextOp.h"
+
+#include "GrOpFlushState.h"
+#include "GrResourceProvider.h"
+
+#include "SkGlyphCache.h"
+#include "SkMathPriv.h"
+
+#include "effects/GrBitmapTextGeoProc.h"
+#include "effects/GrDistanceFieldGeoProc.h"
+#include "text/GrBatchFontCache.h"
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
+    unsigned r = SkColorGetR(c);
+    unsigned g = SkColorGetG(c);
+    unsigned b = SkColorGetB(c);
+    return GrColorPackRGBA(r, g, b, 0xff);
+}
+
+static const int kDistanceAdjustLumShift = 5;
+
+SkString GrAtlasTextBatch::dumpInfo() const {
+    SkString str;
+
+    for (int i = 0; i < fGeoCount; ++i) {
+        str.appendf("%d: Color: 0x%08x Trans: %.2f,%.2f Runs: %d\n",
+                    i,
+                    fGeoData[i].fColor,
+                    fGeoData[i].fX,
+                    fGeoData[i].fY,
+                    fGeoData[i].fBlob->runCount());
+    }
+
+    str.append(DumpPipelineInfo(*this->pipeline()));
+    str.append(INHERITED::dumpInfo());
+    return str;
+}
+
+void GrAtlasTextBatch::computePipelineOptimizations(GrInitInvariantOutput* color,
+                                                    GrInitInvariantOutput* coverage,
+                                                    GrBatchToXPOverrides* overrides) const {
+    if (kColorBitmapMask_MaskType == fMaskType) {
+        color->setUnknownFourComponents();
+    } else {
+        color->setKnownFourComponents(fBatch.fColor);
+    }
+    switch (fMaskType) {
+        case kGrayscaleDistanceField_MaskType:
+        case kGrayscaleCoverageMask_MaskType:
+            coverage->setUnknownSingleComponent();
+            break;
+        case kLCDCoverageMask_MaskType:
+        case kLCDDistanceField_MaskType:
+            coverage->setUnknownOpaqueFourComponents();
+            coverage->setUsingLCDCoverage();
+            break;
+        case kColorBitmapMask_MaskType:
+            coverage->setKnownSingleComponent(0xff);
+    }
+}
+
+void GrAtlasTextBatch::initBatchTracker(const GrXPOverridesForBatch& overrides) {
+    // Handle any color overrides
+    if (!overrides.readsColor()) {
+        fGeoData[0].fColor = GrColor_ILLEGAL;
+    }
+    overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
+
+    // setup batch properties
+    fBatch.fColorIgnored = !overrides.readsColor();
+    fBatch.fColor = fGeoData[0].fColor;
+    fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
+    fBatch.fCoverageIgnored = !overrides.readsCoverage();
+}
+
+void GrAtlasTextBatch::onPrepareDraws(Target* target) const {
+    // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix.
+    // TODO actually only invert if we don't have RGBA
+    SkMatrix localMatrix;
+    if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
+        SkDebugf("Cannot invert viewmatrix\n");
+        return;
+    }
+
+    GrTexture* texture = fFontCache->getTexture(this->maskFormat());
+    if (!texture) {
+        SkDebugf("Could not allocate backing texture for atlas\n");
+        return;
+    }
+
+    GrMaskFormat maskFormat = this->maskFormat();
+
+    FlushInfo flushInfo;
+    if (this->usesDistanceFields()) {
+        flushInfo.fGeometryProcessor =
+            this->setupDfProcessor(this->viewMatrix(), fFilteredColor, this->color(), texture);
+    } else {
+        GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
+        flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(this->color(),
+                                                                 texture,
+                                                                 params,
+                                                                 maskFormat,
+                                                                 localMatrix,
+                                                                 this->usesLocalCoords());
+    }
+
+    flushInfo.fGlyphsToFlush = 0;
+    size_t vertexStride = flushInfo.fGeometryProcessor->getVertexStride();
+    SkASSERT(vertexStride == GrAtlasTextBlob::GetVertexStride(maskFormat));
+
+    int glyphCount = this->numGlyphs();
+    const GrBuffer* vertexBuffer;
+
+    void* vertices = target->makeVertexSpace(vertexStride,
+                                             glyphCount * kVerticesPerGlyph,
+                                             &vertexBuffer,
+                                             &flushInfo.fVertexOffset);
+    flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer));
+    flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer());
+    if (!vertices || !flushInfo.fVertexBuffer) {
+        SkDebugf("Could not allocate vertices\n");
+        return;
+    }
+
+    unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices);
+
+    GrBlobRegenHelper helper(this, target, &flushInfo);
+    SkAutoGlyphCache glyphCache;
+    for (int i = 0; i < fGeoCount; i++) {
+        const Geometry& args = fGeoData[i];
+        Blob* blob = args.fBlob;
+        size_t byteCount;
+        void* blobVertices;
+        int subRunGlyphCount;
+        blob->regenInBatch(target, fFontCache, &helper, args.fRun, args.fSubRun, &glyphCache,
+                           vertexStride, args.fViewMatrix, args.fX, args.fY, args.fColor,
+                           &blobVertices, &byteCount, &subRunGlyphCount);
+
+        // now copy all vertices
+        memcpy(currVertex, blobVertices, byteCount);
+
+#ifdef SK_DEBUG
+        // bounds sanity check
+        SkRect rect;
+        rect.setLargestInverted();
+        SkPoint* vertex = (SkPoint*) ((char*)blobVertices);
+        rect.growToInclude(vertex, vertexStride, kVerticesPerGlyph * subRunGlyphCount);
+
+        if (this->usesDistanceFields()) {
+            args.fViewMatrix.mapRect(&rect);
+        }
+        // Allow for small numerical error in the bounds.
+        SkRect bounds = this->bounds();
+        bounds.outset(0.001f, 0.001f);
+        SkASSERT(bounds.contains(rect));
+#endif
+
+        currVertex += byteCount;
+    }
+
+    this->flush(target, &flushInfo);
+}
+
+void GrAtlasTextBatch::flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const {
+    GrMesh mesh;
+    int maxGlyphsPerDraw =
+        static_cast<int>(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(uint16_t) / 6);
+    mesh.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer.get(),
+                       flushInfo->fIndexBuffer.get(), flushInfo->fVertexOffset,
+                       kVerticesPerGlyph, kIndicesPerGlyph, flushInfo->fGlyphsToFlush,
+                       maxGlyphsPerDraw);
+    target->draw(flushInfo->fGeometryProcessor.get(), mesh);
+    flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush;
+    flushInfo->fGlyphsToFlush = 0;
+}
+
+bool GrAtlasTextBatch::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
+    GrAtlasTextBatch* that = t->cast<GrAtlasTextBatch>();
+    if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
+                                that->bounds(), caps)) {
+        return false;
+    }
+
+    if (fMaskType != that->fMaskType) {
+        return false;
+    }
+
+    if (!this->usesDistanceFields()) {
+        if (kColorBitmapMask_MaskType == fMaskType && this->color() != that->color()) {
+            return false;
+        }
+        if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
+            return false;
+        }
+    } else {
+        if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
+            return false;
+        }
+
+        if (fFilteredColor != that->fFilteredColor) {
+            return false;
+        }
+
+        if (fUseBGR != that->fUseBGR) {
+            return false;
+        }
+    }
+
+    fBatch.fNumGlyphs += that->numGlyphs();
+
+    // Reallocate space for geo data if necessary and then import that's geo data.
+    int newGeoCount = that->fGeoCount + fGeoCount;
+    // We assume (and here enforce) that the allocation size is the smallest power of two that
+    // is greater than or equal to the number of geometries (and at least
+    // kMinGeometryAllocated).
+    int newAllocSize = GrNextPow2(newGeoCount);
+    int currAllocSize = SkTMax<int>(kMinGeometryAllocated, GrNextPow2(fGeoCount));
+
+    if (newGeoCount > currAllocSize) {
+        fGeoData.realloc(newAllocSize);
+    }
+
+    memcpy(&fGeoData[fGeoCount], that->fGeoData.get(), that->fGeoCount * sizeof(Geometry));
+    // We steal the ref on the blobs from the other TextBatch and set its count to 0 so that
+    // it doesn't try to unref them.
+#ifdef SK_DEBUG
+    for (int i = 0; i < that->fGeoCount; ++i) {
+        that->fGeoData.get()[i].fBlob = (Blob*)0x1;
+    }
+#endif
+    that->fGeoCount = 0;
+    fGeoCount = newGeoCount;
+
+    this->joinBounds(*that);
+    return true;
+}
+
+// TODO just use class params
+// TODO trying to figure out why lcd is so whack
+sk_sp<GrGeometryProcessor> GrAtlasTextBatch::setupDfProcessor(const SkMatrix& viewMatrix,
+                                                              SkColor filteredColor,
+                                                              GrColor color,
+                                                              GrTexture* texture) const {
+    GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode);
+    bool isLCD = this->isLCD();
+    // set up any flags
+    uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
+    flags |= viewMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
+    flags |= fUseGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
+
+    // see if we need to create a new effect
+    if (isLCD) {
+        flags |= kUseLCD_DistanceFieldEffectFlag;
+        flags |= fUseBGR ? kBGR_DistanceFieldEffectFlag : 0;
+
+        GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
+
+        float redCorrection = fDistanceAdjustTable->getAdjustment(
+            GrColorUnpackR(colorNoPreMul) >> kDistanceAdjustLumShift,
+            fUseGammaCorrectDistanceTable);
+        float greenCorrection = fDistanceAdjustTable->getAdjustment(
+            GrColorUnpackG(colorNoPreMul) >> kDistanceAdjustLumShift,
+            fUseGammaCorrectDistanceTable);
+        float blueCorrection = fDistanceAdjustTable->getAdjustment(
+            GrColorUnpackB(colorNoPreMul) >> kDistanceAdjustLumShift,
+            fUseGammaCorrectDistanceTable);
+        GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
+            GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(redCorrection,
+                                                                greenCorrection,
+                                                                blueCorrection);
+
+        return GrDistanceFieldLCDTextGeoProc::Make(color,
+                                                   viewMatrix,
+                                                   texture,
+                                                   params,
+                                                   widthAdjust,
+                                                   flags,
+                                                   this->usesLocalCoords());
+    } else {
+#ifdef SK_GAMMA_APPLY_TO_A8
+        U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, filteredColor);
+        float correction = fDistanceAdjustTable->getAdjustment(
+            lum >> kDistanceAdjustLumShift, fUseGammaCorrectDistanceTable);
+        return GrDistanceFieldA8TextGeoProc::Make(color,
+                                                  viewMatrix,
+                                                  texture,
+                                                  params,
+                                                  correction,
+                                                  flags,
+                                                  this->usesLocalCoords());
+#else
+        return GrDistanceFieldA8TextGeoProc::Make(color,
+                                                  viewMatrix,
+                                                  texture,
+                                                  params,
+                                                  flags,
+                                                  this->usesLocalCoords());
+#endif
+    }
+
+}
+
+void GrBlobRegenHelper::flush() {
+    fBatch->flush(fTarget, fFlushInfo);
+}
diff --git a/src/gpu/batches/GrAtlasTextOp.h b/src/gpu/batches/GrAtlasTextOp.h
new file mode 100644 (file)
index 0000000..313a78e
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * 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 GrAtlasTextBatch_DEFINED
+#define GrAtlasTextBatch_DEFINED
+
+#include "batches/GrMeshDrawOp.h"
+
+#include "text/GrAtlasTextContext.h"
+#include "text/GrDistanceFieldAdjustTable.h"
+
+class GrAtlasTextBatch final : public GrMeshDrawOp {
+public:
+    DEFINE_OP_CLASS_ID
+
+    static const int kVerticesPerGlyph = GrAtlasTextBlob::kVerticesPerGlyph;
+    static const int kIndicesPerGlyph = 6;
+
+    typedef GrAtlasTextBlob Blob;
+    struct Geometry {
+        SkMatrix fViewMatrix;
+        Blob* fBlob;
+        SkScalar fX;
+        SkScalar fY;
+        int fRun;
+        int fSubRun;
+        GrColor fColor;
+    };
+
+    static GrAtlasTextBatch* CreateBitmap(GrMaskFormat maskFormat, int glyphCount,
+                                          GrBatchFontCache* fontCache) {
+        GrAtlasTextBatch* batch = new GrAtlasTextBatch;
+
+        batch->fFontCache = fontCache;
+        switch (maskFormat) {
+            case kA8_GrMaskFormat:
+                batch->fMaskType = kGrayscaleCoverageMask_MaskType;
+                break;
+            case kA565_GrMaskFormat:
+                batch->fMaskType = kLCDCoverageMask_MaskType;
+                break;
+            case kARGB_GrMaskFormat:
+                batch->fMaskType = kColorBitmapMask_MaskType;
+                break;
+        }
+        batch->fBatch.fNumGlyphs = glyphCount;
+        batch->fGeoCount = 1;
+        batch->fFilteredColor = 0;
+        batch->fFontCache = fontCache;
+        batch->fUseBGR = false;
+        return batch;
+    }
+
+    static GrAtlasTextBatch* CreateDistanceField(
+                                              int glyphCount, GrBatchFontCache* fontCache,
+                                              const GrDistanceFieldAdjustTable* distanceAdjustTable,
+                                              bool useGammaCorrectDistanceTable,
+                                              SkColor filteredColor, bool isLCD,
+                                              bool useBGR) {
+        GrAtlasTextBatch* batch = new GrAtlasTextBatch;
+
+        batch->fFontCache = fontCache;
+        batch->fMaskType = isLCD ? kLCDDistanceField_MaskType : kGrayscaleDistanceField_MaskType;
+        batch->fDistanceAdjustTable.reset(SkRef(distanceAdjustTable));
+        batch->fUseGammaCorrectDistanceTable = useGammaCorrectDistanceTable;
+        batch->fFilteredColor = filteredColor;
+        batch->fUseBGR = useBGR;
+        batch->fBatch.fNumGlyphs = glyphCount;
+        batch->fGeoCount = 1;
+        return batch;
+    }
+
+    // to avoid even the initial copy of the struct, we have a getter for the first item which
+    // is used to seed the batch with its initial geometry.  After seeding, the client should call
+    // init() so the Batch can initialize itself
+    Geometry& geometry() { return fGeoData[0]; }
+
+    void init() {
+        const Geometry& geo = fGeoData[0];
+        fBatch.fColor = geo.fColor;
+        SkRect bounds;
+        geo.fBlob->computeSubRunBounds(&bounds, geo.fRun, geo.fSubRun, geo.fViewMatrix, geo.fX,
+                                       geo.fY);
+        // We don't have tight bounds on the glyph paths in device space. For the purposes of bounds
+        // we treat this as a set of non-AA rects rendered with a texture.
+        this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
+    }
+
+    const char* name() const override { return "TextBatch"; }
+
+    SkString dumpInfo() const override;
+
+protected:
+    void computePipelineOptimizations(GrInitInvariantOutput* color,
+                                      GrInitInvariantOutput* coverage,
+                                      GrBatchToXPOverrides* overrides) const override;
+
+
+private:
+    void initBatchTracker(const GrXPOverridesForBatch& overrides) override;
+
+    struct FlushInfo {
+        sk_sp<const GrBuffer>      fVertexBuffer;
+        sk_sp<const GrBuffer>      fIndexBuffer;
+        sk_sp<GrGeometryProcessor> fGeometryProcessor;
+        int                        fGlyphsToFlush;
+        int                        fVertexOffset;
+    };
+
+    void onPrepareDraws(Target* target) const override;
+
+    GrAtlasTextBatch() : INHERITED(ClassID()) {} // initialized in factory functions.
+
+    ~GrAtlasTextBatch() {
+        for (int i = 0; i < fGeoCount; i++) {
+            fGeoData[i].fBlob->unref();
+        }
+    }
+
+    GrMaskFormat maskFormat() const {
+        switch (fMaskType) {
+            case kLCDCoverageMask_MaskType:
+                return kA565_GrMaskFormat;
+            case kColorBitmapMask_MaskType:
+                return kARGB_GrMaskFormat;
+            case kGrayscaleCoverageMask_MaskType:
+            case kGrayscaleDistanceField_MaskType:
+            case kLCDDistanceField_MaskType:
+                return kA8_GrMaskFormat;
+        }
+        return kA8_GrMaskFormat; // suppress warning
+    }
+
+    bool usesDistanceFields() const {
+        return kGrayscaleDistanceField_MaskType == fMaskType ||
+               kLCDDistanceField_MaskType == fMaskType;
+    }
+
+    bool isLCD() const {
+        return kLCDCoverageMask_MaskType == fMaskType ||
+               kLCDDistanceField_MaskType == fMaskType;
+    }
+
+    inline void flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const;
+
+    GrColor color() const { return fBatch.fColor; }
+    const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
+    bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
+    int numGlyphs() const { return fBatch.fNumGlyphs; }
+
+    bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override;
+
+    // TODO just use class params
+    // TODO trying to figure out why lcd is so whack
+    sk_sp<GrGeometryProcessor> setupDfProcessor(const SkMatrix& viewMatrix, SkColor filteredColor,
+                                                GrColor color, GrTexture* texture) const;
+
+    struct BatchTracker {
+        GrColor fColor;
+        bool fUsesLocalCoords;
+        bool fColorIgnored;
+        bool fCoverageIgnored;
+        int fNumGlyphs;
+    };
+
+    BatchTracker fBatch;
+    // The minimum number of Geometry we will try to allocate.
+    enum { kMinGeometryAllocated = 4 };
+    SkAutoSTMalloc<kMinGeometryAllocated, Geometry> fGeoData;
+    int fGeoCount;
+
+    enum MaskType {
+        kGrayscaleCoverageMask_MaskType,
+        kLCDCoverageMask_MaskType,
+        kColorBitmapMask_MaskType,
+        kGrayscaleDistanceField_MaskType,
+        kLCDDistanceField_MaskType,
+    } fMaskType;
+    bool fUseBGR; // fold this into the enum?
+
+    GrBatchFontCache* fFontCache;
+
+    // Distance field properties
+    sk_sp<const GrDistanceFieldAdjustTable> fDistanceAdjustTable;
+    SkColor fFilteredColor;
+    bool fUseGammaCorrectDistanceTable;
+
+    friend class GrBlobRegenHelper; // Needs to trigger flushes
+
+    typedef GrMeshDrawOp INHERITED;
+};
+
+/*
+ * A simple helper class to abstract the interface GrAtlasTextBlob needs to regenerate itself.
+ * It'd be nicer if this was nested, but we need to forward declare it in GrAtlasTextBlob.h
+ */
+class GrBlobRegenHelper {
+public:
+    GrBlobRegenHelper(const GrAtlasTextBatch* batch, GrMeshDrawOp::Target* target,
+                      GrAtlasTextBatch::FlushInfo* flushInfo)
+        : fBatch(batch), fTarget(target), fFlushInfo(flushInfo) {}
+
+    void flush();
+
+    void incGlyphCount(int glyphCount = 1) {
+        fFlushInfo->fGlyphsToFlush += glyphCount;
+    }
+
+private:
+    const GrAtlasTextBatch* fBatch;
+    GrMeshDrawOp::Target* fTarget;
+    GrAtlasTextBatch::FlushInfo* fFlushInfo;
+};
+
+#endif
index c5fa86f6e83f40af6b62fa84e8055a57722c00ec..e3c23d69edb595cab630d404f344a0af70ab6739 100644 (file)
@@ -16,7 +16,7 @@
 #include "SkDrawFilter.h"
 #include "SkGlyphCache.h"
 #include "SkTextBlobRunIterator.h"
-#include "batches/GrAtlasTextBatch.h"
+#include "batches/GrAtlasTextOp.h"
 
 GrAtlasTextBlob* GrAtlasTextBlob::Create(GrMemoryPool* pool, int glyphCount, int runCount) {
     // We allocate size for the GrAtlasTextBlob itself, plus size for the vertices array,
index 68f00fc5be0d8d0a000da09ac7b6cb32a70deaf7..1b541464f0af387345ab55e35f7f72b8ee28b0eb 100644 (file)
@@ -13,7 +13,7 @@
 #include "SkDistanceFieldGen.h"
 #include "SkGlyphCache.h"
 
-#include "batches/GrAtlasTextBatch.h"
+#include "batches/GrAtlasTextOp.h"
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // A large template to handle regenerating the vertices of a textblob with as few branches as