aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar joshualitt <joshualitt@chromium.org>2016-02-16 06:47:52 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-02-16 06:47:52 -0800
commitddd22d86455d95941ea21253b210819c1d4a3863 (patch)
treed371c8482601378fbbf902528a42babcb237ddd2 /src
parent6f65957335e9a1fa3eb0fdf8dee0a66d35fc27f6 (diff)
Remove last bit of privacy violation for GrAtlasTextBlob
Diffstat (limited to 'src')
-rw-r--r--src/gpu/GrBatchAtlas.h3
-rw-r--r--src/gpu/batches/GrAtlasTextBatch.cpp285
-rw-r--r--src/gpu/batches/GrAtlasTextBatch.h39
-rw-r--r--src/gpu/text/GrAtlasTextBlob.h23
-rw-r--r--src/gpu/text/GrAtlasTextBlob_regenInBatch.cpp294
5 files changed, 364 insertions, 280 deletions
diff --git a/src/gpu/GrBatchAtlas.h b/src/gpu/GrBatchAtlas.h
index bd6504030b..61fc7e1093 100644
--- a/src/gpu/GrBatchAtlas.h
+++ b/src/gpu/GrBatchAtlas.h
@@ -9,11 +9,12 @@
#define GrBatchAtlas_DEFINED
#include "GrTexture.h"
-#include "batches/GrDrawBatch.h"
#include "SkPoint.h"
#include "SkTDArray.h"
#include "SkTInternalLList.h"
+#include "batches/GrDrawBatch.h"
+
class GrRectanizer;
struct GrBatchAtlasConfig {
diff --git a/src/gpu/batches/GrAtlasTextBatch.cpp b/src/gpu/batches/GrAtlasTextBatch.cpp
index 6a172df5a6..6fea132969 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());
+}
diff --git a/src/gpu/batches/GrAtlasTextBatch.h b/src/gpu/batches/GrAtlasTextBatch.h
index 05d6afdb51..d90aa194c3 100644
--- a/src/gpu/batches/GrAtlasTextBatch.h
+++ b/src/gpu/batches/GrAtlasTextBatch.h
@@ -21,8 +21,6 @@ public:
static const int kIndicesPerGlyph = 6;
typedef GrAtlasTextBlob Blob;
- typedef Blob::Run Run;
- typedef Run::SubRunInfo TextInfo;
struct Geometry {
Blob* fBlob;
int fRun;
@@ -140,13 +138,6 @@ private:
kLCDDistanceField_MaskType == fMaskType;
}
- template <bool regenTexCoords, bool regenPos, bool regenCol, bool regenGlyphs>
- inline void 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;
-
inline void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const;
GrColor color() const { return fBatch.fColor; }
@@ -191,7 +182,37 @@ private:
SkAutoTUnref<const GrDistanceFieldAdjustTable> fDistanceAdjustTable;
SkColor fFilteredColor;
+ friend class GrBlobRegenHelper; // Needs to trigger flushes
+
typedef GrVertexBatch 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,
+ GrVertexBatch::Target* target,
+ GrAtlasTextBatch::FlushInfo* flushInfo,
+ const GrGeometryProcessor* gp)
+ : fBatch(batch)
+ , fTarget(target)
+ , fFlushInfo(flushInfo)
+ , fGP(gp) {}
+
+ void flush();
+
+ void incGlyphCount(int glyphCount = 1) {
+ fFlushInfo->fGlyphsToFlush += glyphCount;
+ }
+
+private:
+ const GrAtlasTextBatch* fBatch;
+ GrVertexBatch::Target* fTarget;
+ GrAtlasTextBatch::FlushInfo* fFlushInfo;
+ const GrGeometryProcessor* fGP;
+};
+
#endif
diff --git a/src/gpu/text/GrAtlasTextBlob.h b/src/gpu/text/GrAtlasTextBlob.h
index b4168e921e..63eb56b6f8 100644
--- a/src/gpu/text/GrAtlasTextBlob.h
+++ b/src/gpu/text/GrAtlasTextBlob.h
@@ -17,6 +17,7 @@
#include "SkSurfaceProps.h"
#include "SkTInternalLList.h"
+class GrBlobRegenHelper;
struct GrDistanceFieldAdjustTable;
class GrMemoryPool;
class GrTextContext;
@@ -108,6 +109,8 @@ public:
void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; }
void setHasBitmap() { fTextType |= kHasBitmap_TextType; }
+ int runCount() const { return fRunCount; }
+
void push_back_run(int currRun) {
SkASSERT(currRun < fRunCount);
if (currRun > 0) {
@@ -255,6 +258,13 @@ public:
this->setupViewMatrix(viewMatrix, x, y);
}
+ void regenInBatch(GrDrawBatch::Target* target, GrBatchFontCache* fontCache,
+ GrBlobRegenHelper *helper, int run, int subRun, SkGlyphCache** cache,
+ SkTypeface** typeface, GrFontScaler** scaler,
+ const SkDescriptor** desc, size_t vertexStride,
+ GrColor color, SkScalar transX, SkScalar transY,
+ void** vertices, size_t* byteCount, int* glyphCount);
+
const Key& key() const { return fKey; }
~GrAtlasTextBlob() {
@@ -453,6 +463,17 @@ private:
bool fDrawAsPaths;
};
+ template <bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs>
+ void regenInBatch(GrDrawBatch::Target* target,
+ GrBatchFontCache* fontCache,
+ GrBlobRegenHelper* helper,
+ Run* run, Run::SubRunInfo* info, SkGlyphCache** cache,
+ SkTypeface** typeface, GrFontScaler** scaler,
+ const SkDescriptor** desc,
+ int glyphCount, size_t vertexStride,
+ GrColor color, SkScalar transX,
+ SkScalar transY) const;
+
inline GrDrawBatch* createBatch(const Run::SubRunInfo& info,
int glyphCount, int run, int subRun,
GrColor color, SkScalar transX, SkScalar transY,
@@ -510,8 +531,6 @@ private:
SkScalar fMinMaxScale;
int fRunCount;
uint8_t fTextType;
-
- friend class GrAtlasTextBatch; // We might be able to get rid of this friending
};
#endif
diff --git a/src/gpu/text/GrAtlasTextBlob_regenInBatch.cpp b/src/gpu/text/GrAtlasTextBlob_regenInBatch.cpp
new file mode 100644
index 0000000000..6443d41ac5
--- /dev/null
+++ b/src/gpu/text/GrAtlasTextBlob_regenInBatch.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrAtlasTextBlob.h"
+
+#include "GrBatchFlushState.h"
+
+#include "SkDistanceFieldGen.h"
+#include "SkGlyphCache.h"
+
+#include "batches/GrAtlasTextBatch.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>
+void GrAtlasTextBlob::regenInBatch(GrDrawBatch::Target* target,
+ GrBatchFontCache* fontCache,
+ GrBlobRegenHelper *helper,
+ Run* run,
+ Run::SubRunInfo* info, SkGlyphCache** cache,
+ SkTypeface** typeface, GrFontScaler** scaler,
+ const SkDescriptor** desc,
+ 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 && !info->drawAsDistanceFields()) ?
+ 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 = fontCache->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 = fGlyphs[glyphOffset]->fPackedID;
+ fGlyphs[glyphOffset] = strike->getGlyph(id, info->maskFormat(), *scaler);
+ SkASSERT(id == fGlyphs[glyphOffset]->fPackedID);
+ }
+ glyph = fGlyphs[glyphOffset];
+ SkASSERT(glyph && glyph->fMaskFormat == info->maskFormat());
+
+ if (!fontCache->hasGlyph(glyph) &&
+ !strike->addGlyphToAtlas(target, glyph, *scaler, info->maskFormat())) {
+ helper->flush();
+ brokenRun = glyphIdx > 0;
+
+ SkDEBUGCODE(bool success =) strike->addGlyphToAtlas(target,
+ glyph,
+ *scaler,
+ info->maskFormat());
+ SkASSERT(success);
+ }
+ fontCache->addGlyphToBulkAndSetUseToken(info->bulkUseToken(), glyph,
+ target->currentToken());
+ }
+
+ intptr_t vertex = reinterpret_cast<intptr_t>(fVertices);
+ vertex += info->vertexStartIndex();
+ vertex += vertexStride * glyphIdx * GrAtlasTextBatch::kVerticesPerGlyph;
+ regen_vertices<regenPos, regenCol, regenTexCoords>(vertex, glyph, vertexStride,
+ info->drawAsDistanceFields(), transX,
+ transY, color);
+ helper->incGlyphCount();
+ }
+
+ // 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 :
+ fontCache->atlasGeneration(info->maskFormat()));
+ }
+}
+
+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, fontCache, helper, &run, &info, cache, typeface, scaler, desc, \
+ *glyphCount, vertexStride, color, transX, transY
+
+void GrAtlasTextBlob::regenInBatch(GrDrawBatch::Target* target,
+ GrBatchFontCache* fontCache,
+ GrBlobRegenHelper *helper,
+ int runIndex, int subRunIndex, SkGlyphCache** cache,
+ SkTypeface** typeface, GrFontScaler** scaler,
+ const SkDescriptor** desc, size_t vertexStride,
+ GrColor color, SkScalar transX,
+ SkScalar transY,
+ void** vertices, size_t* byteCount, int* glyphCount) {
+ Run& run = fRuns[runIndex];
+ Run::SubRunInfo& info = run.fSubRunInfo[subRunIndex];
+
+ uint64_t currentAtlasGen = fontCache->atlasGeneration(info.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 != info.maskFormat() &&
+ info.color() != color;
+ bool regeneratePositions = transX != 0.f || transY != 0.f;
+ *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->regenInBatch<true, false, false, false>(REGEN_ARGS); break;
+ case kRegenCol: this->regenInBatch<false, true, false, false>(REGEN_ARGS); break;
+ case kRegenTex: this->regenInBatch<false, false, true, false>(REGEN_ARGS); break;
+ case kRegenGlyph: this->regenInBatch<false, false, true, true>(REGEN_ARGS); break;
+
+ // combinations
+ case kRegenPosCol: this->regenInBatch<true, true, false, false>(REGEN_ARGS); break;
+ case kRegenPosTex: this->regenInBatch<true, false, true, false>(REGEN_ARGS); break;
+ case kRegenPosTexGlyph: this->regenInBatch<true, false, true, true>(REGEN_ARGS); break;
+ case kRegenPosColTex: this->regenInBatch<true, true, true, false>(REGEN_ARGS); break;
+ case kRegenPosColTexGlyph: this->regenInBatch<true, true, true, true>(REGEN_ARGS); break;
+ case kRegenColTex: this->regenInBatch<false, true, true, false>(REGEN_ARGS); break;
+ case kRegenColTexGlyph: this->regenInBatch<false, true, true, true>(REGEN_ARGS); break;
+ case kNoRegen:
+ helper->incGlyphCount(*glyphCount);
+
+ // set use tokens for all of the glyphs in our subrun. This is only valid if we
+ // have a valid atlas generation
+ fontCache->setUseTokenBulk(*info.bulkUseToken(), target->currentToken(),
+ info.maskFormat());
+ break;
+ }
+
+ *byteCount = info.byteCount();
+ *vertices = fVertices + info.vertexStartIndex();
+}