| Index: src/gpu/batches/GrAtlasTextBatch.cpp
|
| diff --git a/src/gpu/batches/GrAtlasTextBatch.cpp b/src/gpu/batches/GrAtlasTextBatch.cpp
|
| index 6a172df5a6c856b707c43bdc5acd80d02e770b78..6fea13296931850e8b078de984c2ef6626f30f2f 100644
|
| --- a/src/gpu/batches/GrAtlasTextBatch.cpp
|
| +++ b/src/gpu/batches/GrAtlasTextBatch.cpp
|
| @@ -8,206 +8,14 @@
|
| #include "GrAtlasTextBatch.h"
|
|
|
| #include "GrBatchFlushState.h"
|
| -#include "GrBatchTest.h"
|
| #include "GrResourceProvider.h"
|
|
|
| -#include "SkDistanceFieldGen.h"
|
| #include "SkGlyphCache.h"
|
|
|
| #include "effects/GrBitmapTextGeoProc.h"
|
| #include "effects/GrDistanceFieldGeoProc.h"
|
| #include "text/GrBatchFontCache.h"
|
|
|
| -////////////////////////////////////////////////////////////////////////////////////////////////////
|
| -// A large template to handle regenerating the vertices of a textblob with as few branches as
|
| -// possible
|
| -template <bool regenPos, bool regenCol, bool regenTexCoords>
|
| -inline void regen_vertices(intptr_t vertex, const GrGlyph* glyph, size_t vertexStride,
|
| - bool useDistanceFields, SkScalar transX, SkScalar transY,
|
| - GrColor color) {
|
| - int u0, v0, u1, v1;
|
| - if (regenTexCoords) {
|
| - SkASSERT(glyph);
|
| - int width = glyph->fBounds.width();
|
| - int height = glyph->fBounds.height();
|
| -
|
| - if (useDistanceFields) {
|
| - u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset;
|
| - v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset;
|
| - u1 = u0 + width - 2 * SK_DistanceFieldInset;
|
| - v1 = v0 + height - 2 * SK_DistanceFieldInset;
|
| - } else {
|
| - u0 = glyph->fAtlasLocation.fX;
|
| - v0 = glyph->fAtlasLocation.fY;
|
| - u1 = u0 + width;
|
| - v1 = v0 + height;
|
| - }
|
| - }
|
| -
|
| - // This is a bit wonky, but sometimes we have LCD text, in which case we won't have color
|
| - // vertices, hence vertexStride - sizeof(SkIPoint16)
|
| - intptr_t colorOffset = sizeof(SkPoint);
|
| - intptr_t texCoordOffset = vertexStride - sizeof(SkIPoint16);
|
| -
|
| - // V0
|
| - if (regenPos) {
|
| - SkPoint* point = reinterpret_cast<SkPoint*>(vertex);
|
| - point->fX += transX;
|
| - point->fY += transY;
|
| - }
|
| -
|
| - if (regenCol) {
|
| - SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
|
| - *vcolor = color;
|
| - }
|
| -
|
| - if (regenTexCoords) {
|
| - SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + texCoordOffset);
|
| - textureCoords->set(u0, v0);
|
| - }
|
| - vertex += vertexStride;
|
| -
|
| - // V1
|
| - if (regenPos) {
|
| - SkPoint* point = reinterpret_cast<SkPoint*>(vertex);
|
| - point->fX += transX;
|
| - point->fY += transY;
|
| - }
|
| -
|
| - if (regenCol) {
|
| - SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
|
| - *vcolor = color;
|
| - }
|
| -
|
| - if (regenTexCoords) {
|
| - SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + texCoordOffset);
|
| - textureCoords->set(u0, v1);
|
| - }
|
| - vertex += vertexStride;
|
| -
|
| - // V2
|
| - if (regenPos) {
|
| - SkPoint* point = reinterpret_cast<SkPoint*>(vertex);
|
| - point->fX += transX;
|
| - point->fY += transY;
|
| - }
|
| -
|
| - if (regenCol) {
|
| - SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
|
| - *vcolor = color;
|
| - }
|
| -
|
| - if (regenTexCoords) {
|
| - SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + texCoordOffset);
|
| - textureCoords->set(u1, v1);
|
| - }
|
| - vertex += vertexStride;
|
| -
|
| - // V3
|
| - if (regenPos) {
|
| - SkPoint* point = reinterpret_cast<SkPoint*>(vertex);
|
| - point->fX += transX;
|
| - point->fY += transY;
|
| - }
|
| -
|
| - if (regenCol) {
|
| - SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
|
| - *vcolor = color;
|
| - }
|
| -
|
| - if (regenTexCoords) {
|
| - SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + texCoordOffset);
|
| - textureCoords->set(u1, v0);
|
| - }
|
| -}
|
| -
|
| -template <bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs>
|
| -inline void GrAtlasTextBatch::regenBlob(Target* target, FlushInfo* flushInfo, Blob* blob, Run* run,
|
| - TextInfo* info, SkGlyphCache** cache,
|
| - SkTypeface** typeface, GrFontScaler** scaler,
|
| - const SkDescriptor** desc, const GrGeometryProcessor* gp,
|
| - int glyphCount, size_t vertexStride,
|
| - GrColor color, SkScalar transX, SkScalar transY) const {
|
| - static_assert(!regenGlyphs || regenTexCoords, "must regenTexCoords along regenGlyphs");
|
| - GrBatchTextStrike* strike = nullptr;
|
| - if (regenTexCoords) {
|
| - info->resetBulkUseToken();
|
| -
|
| - // We can reuse if we have a valid strike and our descriptors / typeface are the
|
| - // same. The override descriptor is only for the non distance field text within
|
| - // a run
|
| - const SkDescriptor* newDesc = (run->fOverrideDescriptor && !this->usesDistanceFields()) ?
|
| - run->fOverrideDescriptor->getDesc() :
|
| - run->fDescriptor.getDesc();
|
| - if (!*cache || !SkTypeface::Equal(*typeface, run->fTypeface) ||
|
| - !((*desc)->equals(*newDesc))) {
|
| - if (*cache) {
|
| - SkGlyphCache::AttachCache(*cache);
|
| - }
|
| - *desc = newDesc;
|
| - *cache = SkGlyphCache::DetachCache(run->fTypeface, *desc);
|
| - *scaler = GrTextContext::GetGrFontScaler(*cache);
|
| - *typeface = run->fTypeface;
|
| - }
|
| -
|
| - if (regenGlyphs) {
|
| - strike = fFontCache->getStrike(*scaler);
|
| - } else {
|
| - strike = info->strike();
|
| - }
|
| - }
|
| -
|
| - bool brokenRun = false;
|
| - for (int glyphIdx = 0; glyphIdx < glyphCount; glyphIdx++) {
|
| - GrGlyph* glyph = nullptr;
|
| - if (regenTexCoords) {
|
| - size_t glyphOffset = glyphIdx + info->glyphStartIndex();
|
| -
|
| - if (regenGlyphs) {
|
| - // Get the id from the old glyph, and use the new strike to lookup
|
| - // the glyph.
|
| - GrGlyph::PackedID id = blob->fGlyphs[glyphOffset]->fPackedID;
|
| - blob->fGlyphs[glyphOffset] = strike->getGlyph(id, this->maskFormat(), *scaler);
|
| - SkASSERT(id == blob->fGlyphs[glyphOffset]->fPackedID);
|
| - }
|
| - glyph = blob->fGlyphs[glyphOffset];
|
| - SkASSERT(glyph && glyph->fMaskFormat == this->maskFormat());
|
| -
|
| - if (!fFontCache->hasGlyph(glyph) &&
|
| - !strike->addGlyphToAtlas(target, glyph, *scaler, this->maskFormat())) {
|
| - this->flush(target, flushInfo);
|
| - target->initDraw(gp, this->pipeline());
|
| - brokenRun = glyphIdx > 0;
|
| -
|
| - SkDEBUGCODE(bool success =) strike->addGlyphToAtlas(target,
|
| - glyph,
|
| - *scaler,
|
| - this->maskFormat());
|
| - SkASSERT(success);
|
| - }
|
| - fFontCache->addGlyphToBulkAndSetUseToken(info->bulkUseToken(), glyph,
|
| - target->currentToken());
|
| - }
|
| -
|
| - intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices);
|
| - vertex += info->vertexStartIndex();
|
| - vertex += vertexStride * glyphIdx * GrAtlasTextBatch::kVerticesPerGlyph;
|
| - regen_vertices<regenPos, regenCol, regenTexCoords>(vertex, glyph, vertexStride,
|
| - this->usesDistanceFields(), transX,
|
| - transY, color);
|
| - flushInfo->fGlyphsToFlush++;
|
| - }
|
| -
|
| - // We may have changed the color so update it here
|
| - info->setColor(color);
|
| - if (regenTexCoords) {
|
| - if (regenGlyphs) {
|
| - info->setStrike(strike);
|
| - }
|
| - info->setAtlasGeneration(brokenRun ? GrBatchAtlas::kInvalidAtlasGeneration :
|
| - fFontCache->atlasGeneration(this->maskFormat()));
|
| - }
|
| -}
|
| ///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
| static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
|
| @@ -228,7 +36,7 @@ SkString GrAtlasTextBatch::dumpInfo() const {
|
| fGeoData[i].fColor,
|
| fGeoData[i].fTransX,
|
| fGeoData[i].fTransY,
|
| - fGeoData[i].fBlob->fRunCount);
|
| + fGeoData[i].fBlob->runCount());
|
| }
|
|
|
| str.append(INHERITED::dumpInfo());
|
| @@ -272,26 +80,6 @@ void GrAtlasTextBatch::initBatchTracker(const GrXPOverridesForBatch& overrides)
|
| fBatch.fCoverageIgnored = !overrides.readsCoverage();
|
| }
|
|
|
| -enum RegenMask {
|
| - kNoRegen = 0x0,
|
| - kRegenPos = 0x1,
|
| - kRegenCol = 0x2,
|
| - kRegenTex = 0x4,
|
| - kRegenGlyph = 0x8 | kRegenTex, // we have to regenerate the texture coords when we regen glyphs
|
| -
|
| - // combinations
|
| - kRegenPosCol = kRegenPos | kRegenCol,
|
| - kRegenPosTex = kRegenPos | kRegenTex,
|
| - kRegenPosTexGlyph = kRegenPos | kRegenGlyph,
|
| - kRegenPosColTex = kRegenPos | kRegenCol | kRegenTex,
|
| - kRegenPosColTexGlyph = kRegenPos | kRegenCol | kRegenGlyph,
|
| - kRegenColTex = kRegenCol | kRegenTex,
|
| - kRegenColTexGlyph = kRegenCol | kRegenGlyph,
|
| -};
|
| -
|
| -#define REGEN_ARGS target, &flushInfo, blob, &run, &info, &cache, &typeface, &scaler, &desc, gp, \
|
| - glyphCount, vertexStride, args.fColor, args.fTransX, args.fTransY
|
| -
|
| 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
|
| @@ -353,71 +141,27 @@ void GrAtlasTextBatch::onPrepareDraws(Target* target) const {
|
| GrFontScaler* scaler = nullptr;
|
| SkTypeface* typeface = nullptr;
|
|
|
| + GrBlobRegenHelper helper(this, target, &flushInfo, gp);
|
| +
|
| for (int i = 0; i < fGeoCount; i++) {
|
| const Geometry& args = fGeoData[i];
|
| Blob* blob = args.fBlob;
|
| - Run& run = blob->fRuns[args.fRun];
|
| - TextInfo& info = run.fSubRunInfo[args.fSubRun];
|
| -
|
| - uint64_t currentAtlasGen = fFontCache->atlasGeneration(maskFormat);
|
| -
|
| - // Because the GrBatchFontCache may evict the strike a blob depends on using for
|
| - // generating its texture coords, we have to track whether or not the strike has
|
| - // been abandoned. If it hasn't been abandoned, then we can use the GrGlyph*s as is
|
| - // otherwise we have to get the new strike, and use that to get the correct glyphs.
|
| - // Because we do not have the packed ids, and thus can't look up our glyphs in the
|
| - // new strike, we instead keep our ref to the old strike and use the packed ids from
|
| - // it. These ids will still be valid as long as we hold the ref. When we are done
|
| - // updating our cache of the GrGlyph*s, we drop our ref on the old strike
|
| - bool regenerateGlyphs = info.strike()->isAbandoned();
|
| - bool regenerateTextureCoords = info.atlasGeneration() != currentAtlasGen ||
|
| - regenerateGlyphs;
|
| - bool regenerateColors = kARGB_GrMaskFormat != maskFormat &&
|
| - info.color() != args.fColor;
|
| - bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0.f;
|
| - int glyphCount = info.glyphCount();
|
| -
|
| - uint32_t regenMaskBits = kNoRegen;
|
| - regenMaskBits |= regeneratePositions ? kRegenPos : 0;
|
| - regenMaskBits |= regenerateColors ? kRegenCol : 0;
|
| - regenMaskBits |= regenerateTextureCoords ? kRegenTex : 0;
|
| - regenMaskBits |= regenerateGlyphs ? kRegenGlyph : 0;
|
| - RegenMask regenMask = (RegenMask)regenMaskBits;
|
| -
|
| - switch (regenMask) {
|
| - case kRegenPos: this->regenBlob<true, false, false, false>(REGEN_ARGS); break;
|
| - case kRegenCol: this->regenBlob<false, true, false, false>(REGEN_ARGS); break;
|
| - case kRegenTex: this->regenBlob<false, false, true, false>(REGEN_ARGS); break;
|
| - case kRegenGlyph: this->regenBlob<false, false, true, true>(REGEN_ARGS); break;
|
| -
|
| - // combinations
|
| - case kRegenPosCol: this->regenBlob<true, true, false, false>(REGEN_ARGS); break;
|
| - case kRegenPosTex: this->regenBlob<true, false, true, false>(REGEN_ARGS); break;
|
| - case kRegenPosTexGlyph: this->regenBlob<true, false, true, true>(REGEN_ARGS); break;
|
| - case kRegenPosColTex: this->regenBlob<true, true, true, false>(REGEN_ARGS); break;
|
| - case kRegenPosColTexGlyph: this->regenBlob<true, true, true, true>(REGEN_ARGS); break;
|
| - case kRegenColTex: this->regenBlob<false, true, true, false>(REGEN_ARGS); break;
|
| - case kRegenColTexGlyph: this->regenBlob<false, true, true, true>(REGEN_ARGS); break;
|
| - case kNoRegen:
|
| - flushInfo.fGlyphsToFlush += glyphCount;
|
| -
|
| - // set use tokens for all of the glyphs in our subrun. This is only valid if we
|
| - // have a valid atlas generation
|
| - fFontCache->setUseTokenBulk(*info.bulkUseToken(), target->currentToken(),
|
| - maskFormat);
|
| - break;
|
| - }
|
| + size_t byteCount;
|
| + void* blobVertices;
|
| + int glyphCount;
|
| + blob->regenInBatch(target, fFontCache, &helper, args.fRun, args.fSubRun, &cache,
|
| + &typeface, &scaler, &desc, vertexStride, args.fColor, args.fTransX,
|
| + args.fTransY, &blobVertices, &byteCount, &glyphCount);
|
|
|
| // now copy all vertices
|
| - size_t byteCount = info.byteCount();
|
| - memcpy(currVertex, blob->fVertices + info.vertexStartIndex(), byteCount);
|
| + memcpy(currVertex, blobVertices, byteCount);
|
|
|
| #ifdef SK_DEBUG
|
| // bounds sanity check
|
| SkRect rect;
|
| rect.setLargestInverted();
|
| - SkPoint* vertex = (SkPoint*) ((char*)blob->fVertices + info.vertexStartIndex());
|
| - rect.growToInclude(vertex, vertexStride, kVerticesPerGlyph * info.glyphCount());
|
| + SkPoint* vertex = (SkPoint*) ((char*)blobVertices);
|
| + rect.growToInclude(vertex, vertexStride, kVerticesPerGlyph * glyphCount);
|
|
|
| if (this->usesDistanceFields()) {
|
| fBatch.fViewMatrix.mapRect(&rect);
|
| @@ -566,3 +310,8 @@ GrGeometryProcessor* GrAtlasTextBatch::setupDfProcessor(const SkMatrix& viewMatr
|
| }
|
|
|
| }
|
| +
|
| +void GrBlobRegenHelper::flush() {
|
| + fBatch->flush(fTarget, fFlushInfo);
|
| + fTarget->initDraw(fGP, fBatch->pipeline());
|
| +}
|
|
|