aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar Brian Salomon <bsalomon@google.com>2017-11-06 16:26:02 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-11-07 01:56:36 +0000
commit18923f9a2e83675aecba7561f5095429fb467633 (patch)
treee59e9a98ee1f7422ecf641cc998a977f28151a70 /src/gpu
parent75a1377e54fb44c84a2712d9c678b1b448a9cffe (diff)
Make GrAtlasTextBlob return to caller when a flush is required during subrun tessellation.
The old code used a helper object in the tessellation code that called flush() on GrAtlasTextOp. A confusing aspect of this was that the pre-flush vertex data generated for the sub run was copied to the op's vertex buffer after flush() had already recorded the draw that read the data. The new code adds a tessellator nested helper class to GrAtlasTextBlob. The helper exits early if a flush is required, the op performs the flush, and then the helper is invoked again until tessellation is complete. This also changes the blob object to use char* instead of unsigned char* for its vertex pointers. Change-Id: I31bed251435f13b2172e6f5829ba437b882dd44d Reviewed-on: https://skia-review.googlesource.com/67856 Commit-Queue: Brian Salomon <bsalomon@google.com> Reviewed-by: Jim Van Verth <jvanverth@google.com>
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/ops/GrAtlasTextOp.cpp57
-rw-r--r--src/gpu/ops/GrAtlasTextOp.h22
-rw-r--r--src/gpu/text/GrAtlasTextBlob.cpp3
-rw-r--r--src/gpu/text/GrAtlasTextBlob.h81
-rw-r--r--src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp (renamed from src/gpu/text/GrAtlasTextBlob_regenInOp.cpp)273
5 files changed, 227 insertions, 209 deletions
diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp
index 2383510a47..9e98466d5d 100644
--- a/src/gpu/ops/GrAtlasTextOp.cpp
+++ b/src/gpu/ops/GrAtlasTextOp.cpp
@@ -76,12 +76,12 @@ GrDrawOp::RequiresDstTexture GrAtlasTextOp::finalize(const GrCaps& caps,
return analysis.requiresDstTexture() ? RequiresDstTexture::kYes : RequiresDstTexture::kNo;
}
-static void clip_quads(const SkIRect& clipRect,
- unsigned char* currVertex, unsigned char* blobVertices,
+static void clip_quads(const SkIRect& clipRect, char* currVertex, const char* blobVertices,
size_t vertexStride, int glyphCount) {
for (int i = 0; i < glyphCount; ++i) {
- SkPoint* blobPositionLT = reinterpret_cast<SkPoint*>(blobVertices);
- SkPoint* blobPositionRB = reinterpret_cast<SkPoint*>(blobVertices + 3*vertexStride);
+ const SkPoint* blobPositionLT = reinterpret_cast<const SkPoint*>(blobVertices);
+ const SkPoint* blobPositionRB =
+ reinterpret_cast<const SkPoint*>(blobVertices + 3 * vertexStride);
// positions for bitmap glyphs are pixel boundary aligned
SkIRect positionRect = SkIRect::MakeLTRB(SkScalarFloorToInt(blobPositionLT->fX),
@@ -95,11 +95,11 @@ static void clip_quads(const SkIRect& clipRect,
// Pull out some more data that we'll need.
// In the LCD case the color will be garbage, but we'll overwrite it with the texcoords
// and it avoids a lot of conditionals.
- SkColor color = *reinterpret_cast<SkColor*>(blobVertices + sizeof(SkPoint));
+ auto color = *reinterpret_cast<const SkColor*>(blobVertices + sizeof(SkPoint));
size_t coordOffset = vertexStride - 2*sizeof(uint16_t);
- uint16_t* blobCoordsLT = reinterpret_cast<uint16_t*>(blobVertices + coordOffset);
- uint16_t* blobCoordsRB = reinterpret_cast<uint16_t*>(blobVertices + 3*vertexStride +
- coordOffset);
+ auto* blobCoordsLT = reinterpret_cast<const uint16_t*>(blobVertices + coordOffset);
+ auto* blobCoordsRB = reinterpret_cast<const uint16_t*>(blobVertices + 3 * vertexStride +
+ coordOffset);
// Pull out the texel coordinates and texture index bits
uint16_t coordsRectL = blobCoordsLT[0] >> 1;
uint16_t coordsRectT = blobCoordsLT[1] >> 1;
@@ -224,32 +224,34 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) {
return;
}
- unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices);
+ char* currVertex = reinterpret_cast<char*>(vertices);
- GrBlobRegenHelper helper(this, target, &flushInfo);
SkAutoGlyphCache glyphCache;
// each of these is a SubRun
for (int i = 0; i < fGeoCount; i++) {
const Geometry& args = fGeoData[i];
Blob* blob = args.fBlob;
- size_t byteCount;
- void* blobVertices;
- int subRunGlyphCount;
- blob->regenInOp(target->deferredUploadTarget(), fFontCache, &helper, args.fRun,
- args.fSubRun, &glyphCache, vertexStride, args.fViewMatrix, args.fX, args.fY,
- args.fColor, &blobVertices, &byteCount, &subRunGlyphCount);
-
- // now copy all vertices
- if (args.fClipRect.isEmpty()) {
- memcpy(currVertex, blobVertices, byteCount);
- } else {
- clip_quads(args.fClipRect, currVertex, reinterpret_cast<unsigned char*>(blobVertices),
- vertexStride, subRunGlyphCount);
- }
-
- currVertex += byteCount;
+ GrAtlasTextBlob::VertexRegenerator regenerator(
+ blob, args.fRun, args.fSubRun, args.fViewMatrix, args.fX, args.fY, args.fColor,
+ target->deferredUploadTarget(), fFontCache, &glyphCache, vertexStride);
+ GrAtlasTextBlob::VertexRegenerator::Result result;
+ do {
+ result = regenerator.regenerate();
+ // Copy regenerated vertices from the blob to our vertex buffer.
+ size_t vertexBytes = result.fGlyphsRegenerated * kVerticesPerGlyph * vertexStride;
+ if (args.fClipRect.isEmpty()) {
+ memcpy(currVertex, result.fFirstVertex, vertexBytes);
+ } else {
+ clip_quads(args.fClipRect, currVertex, result.fFirstVertex, vertexStride,
+ result.fGlyphsRegenerated);
+ }
+ flushInfo.fGlyphsToFlush += result.fGlyphsRegenerated;
+ if (!result.fFinished) {
+ this->flush(target, &flushInfo);
+ }
+ currVertex += vertexBytes;
+ } while (!result.fFinished);
}
-
this->flush(target, &flushInfo);
}
@@ -406,4 +408,3 @@ sk_sp<GrGeometryProcessor> GrAtlasTextOp::setupDfProcessor() const {
}
}
-void GrBlobRegenHelper::flush() { fOp->flush(fTarget, fFlushInfo); }
diff --git a/src/gpu/ops/GrAtlasTextOp.h b/src/gpu/ops/GrAtlasTextOp.h
index 1814676445..240b98b6f0 100644
--- a/src/gpu/ops/GrAtlasTextOp.h
+++ b/src/gpu/ops/GrAtlasTextOp.h
@@ -206,29 +206,7 @@ private:
SkColor fLuminanceColor;
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 GrAtlasTextOp* op, GrMeshDrawOp::Target* target,
- GrAtlasTextOp::FlushInfo* flushInfo)
- : fOp(op), fTarget(target), fFlushInfo(flushInfo) {}
-
- void flush();
-
- void incGlyphCount(int glyphCount = 1) { fFlushInfo->fGlyphsToFlush += glyphCount; }
-
-private:
- const GrAtlasTextOp* fOp;
- GrMeshDrawOp::Target* fTarget;
- GrAtlasTextOp::FlushInfo* fFlushInfo;
-};
-
#endif
diff --git a/src/gpu/text/GrAtlasTextBlob.cpp b/src/gpu/text/GrAtlasTextBlob.cpp
index 17f81a2188..0b25a34ed1 100644
--- a/src/gpu/text/GrAtlasTextBlob.cpp
+++ b/src/gpu/text/GrAtlasTextBlob.cpp
@@ -34,8 +34,7 @@ sk_sp<GrAtlasTextBlob> GrAtlasTextBlob::Make(GrMemoryPool* pool, int glyphCount,
cacheBlob->fSize = size;
// setup offsets for vertices / glyphs
- cacheBlob->fVertices = sizeof(GrAtlasTextBlob) +
- reinterpret_cast<unsigned char*>(cacheBlob.get());
+ cacheBlob->fVertices = sizeof(GrAtlasTextBlob) + reinterpret_cast<char*>(cacheBlob.get());
cacheBlob->fGlyphs = reinterpret_cast<GrGlyph**>(cacheBlob->fVertices + verticesCount);
cacheBlob->fRuns = reinterpret_cast<GrAtlasTextBlob::Run*>(cacheBlob->fGlyphs + glyphCount);
diff --git a/src/gpu/text/GrAtlasTextBlob.h b/src/gpu/text/GrAtlasTextBlob.h
index 495e72aa92..403cbbfa3f 100644
--- a/src/gpu/text/GrAtlasTextBlob.h
+++ b/src/gpu/text/GrAtlasTextBlob.h
@@ -21,7 +21,6 @@
#include "SkSurfaceProps.h"
#include "SkTInternalLList.h"
-class GrBlobRegenHelper;
struct GrDistanceFieldAdjustTable;
class GrMemoryPool;
class SkDrawFilter;
@@ -50,6 +49,8 @@ class GrAtlasTextBlob : public SkNVRefCnt<GrAtlasTextBlob> {
public:
SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrAtlasTextBlob);
+ class VertexRegenerator;
+
static sk_sp<GrAtlasTextBlob> Make(GrMemoryPool* pool, int glyphCount, int runCount);
struct Key {
@@ -250,16 +251,6 @@ public:
this->setupViewMatrix(viewMatrix, x, y);
}
- /**
- * Consecutive calls to regenInOp often use the same SkGlyphCache. If the same instance of
- * SkAutoGlyphCache is passed to multiple calls of regenInOp then it can save the cost of
- * multiple detach/attach operations of SkGlyphCache.
- */
- void regenInOp(GrDeferredUploadTarget*, GrAtlasGlyphCache* fontCache, GrBlobRegenHelper* helper,
- int run, int subRun, SkAutoGlyphCache*, size_t vertexStride,
- const SkMatrix& viewMatrix, SkScalar x, SkScalar y, GrColor color,
- void** vertices, size_t* byteCount, int* glyphCount);
-
const Key& key() const { return fKey; }
~GrAtlasTextBlob() {
@@ -492,11 +483,6 @@ private:
bool fDrawAsPaths;
}; // Run
- template <bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs>
- void regenInOp(GrDeferredUploadTarget*, GrAtlasGlyphCache* fontCache, GrBlobRegenHelper* helper,
- Run* run, Run::SubRunInfo* info, SkAutoGlyphCache*, int glyphCount,
- size_t vertexStride, GrColor color, SkScalar transX, SkScalar transY) const;
-
inline std::unique_ptr<GrAtlasTextOp> makeOp(
const Run::SubRunInfo& info, int glyphCount, uint16_t run, uint16_t subRun,
const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const SkIRect& clipRect,
@@ -530,7 +516,7 @@ private:
};
// all glyph / vertex offsets are into these pools.
- unsigned char* fVertices;
+ char* fVertices;
GrGlyph** fGlyphs;
Run* fRuns;
GrMemoryPool* fPool;
@@ -554,4 +540,65 @@ private:
uint8_t fTextType;
};
+/**
+ * Used to produce vertices for a subrun of a blob. The vertices are cached in the blob itself.
+ * This is invoked each time a sub run is drawn. It regenerates the vertex data as required either
+ * because of changes to the atlas or because of different draw parameters (e.g. color change). In
+ * rare cases the draw may have to interrupted and flushed in the middle of the sub run in order to
+ * free up atlas space. Thus, this generator is stateful and should be invoked in a loop until the
+ * entire sub run has been completed.
+ */
+class GrAtlasTextBlob::VertexRegenerator {
+public:
+ /**
+ * Consecutive VertexRegenerators often use the same SkGlyphCache. If the same instance of
+ * SkAutoGlyphCache is reused then it can save the cost of multiple detach/attach operations of
+ * SkGlyphCache.
+ */
+ VertexRegenerator(GrAtlasTextBlob* blob, int runIdx, int subRunIdx, const SkMatrix& viewMatrix,
+ SkScalar x, SkScalar y, GrColor color, GrDeferredUploadTarget*,
+ GrAtlasGlyphCache*, SkAutoGlyphCache*, size_t vertexStride);
+
+ struct Result {
+ /**
+ * Was regenerate() able to draw all the glyphs from the sub run? If not flush all glyph
+ * draws and call regenerate() again.
+ */
+ bool fFinished = true;
+
+ /**
+ * How many glyphs were regenerated. Will be equal to the sub run's glyph count if
+ * fType is kFinished.
+ */
+ int fGlyphsRegenerated = 0;
+
+ /**
+ * Pointer where the caller finds the first regenerated vertex.
+ */
+ const char* fFirstVertex;
+ };
+
+ Result regenerate();
+
+private:
+ template <bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs>
+ Result doRegen();
+
+ const SkMatrix& fViewMatrix;
+ GrAtlasTextBlob* fBlob;
+ GrDeferredUploadTarget* fUploadTarget;
+ GrAtlasGlyphCache* fGlyphCache;
+ SkAutoGlyphCache* fLazyCache;
+ Run* fRun;
+ Run::SubRunInfo* fSubRun;
+ size_t fVertexStride;
+ GrColor fColor;
+ SkScalar fTransX;
+ SkScalar fTransY;
+
+ uint32_t fRegenFlags = 0;
+ int fCurrGlyph = 0;
+ bool fBrokenRun = false;
+};
+
#endif
diff --git a/src/gpu/text/GrAtlasTextBlob_regenInOp.cpp b/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp
index e0811587e4..6b242adcde 100644
--- a/src/gpu/text/GrAtlasTextBlob_regenInOp.cpp
+++ b/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp
@@ -6,20 +6,35 @@
*/
#include "GrAtlasTextBlob.h"
-
-#include "GrOpFlushState.h"
#include "GrTextUtils.h"
-
#include "SkDistanceFieldGen.h"
#include "SkGlyphCache.h"
-
#include "ops/GrAtlasTextOp.h"
+using Regenerator = GrAtlasTextBlob::VertexRegenerator;
+
+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,
+};
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// 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,
+inline void regen_vertices(char* vertex, const GrGlyph* glyph, size_t vertexStride,
bool useDistanceFields, SkScalar transX, SkScalar transY,
GrColor color) {
uint16_t u0, v0, u1, v1;
@@ -135,190 +150,168 @@ inline void regen_vertices(intptr_t vertex, const GrGlyph* glyph, size_t vertexS
}
}
+Regenerator::VertexRegenerator(GrAtlasTextBlob* blob, int runIdx, int subRunIdx,
+ const SkMatrix& viewMatrix, SkScalar x, SkScalar y, GrColor color,
+ GrDeferredUploadTarget* uploadTarget, GrAtlasGlyphCache* glyphCache,
+ SkAutoGlyphCache* lazyCache, size_t vertexStride)
+ : fViewMatrix(viewMatrix)
+ , fBlob(blob)
+ , fUploadTarget(uploadTarget)
+ , fGlyphCache(glyphCache)
+ , fLazyCache(lazyCache)
+ , fRun(&blob->fRuns[runIdx])
+ , fSubRun(&blob->fRuns[runIdx].fSubRunInfo[subRunIdx])
+ , fVertexStride(vertexStride)
+ , fColor(color) {
+ // Compute translation if any
+ fSubRun->computeTranslation(fViewMatrix, x, y, &fTransX, &fTransY);
+
+ // Because the GrAtlasGlyphCache 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
+ if (fSubRun->strike()->isAbandoned()) {
+ fRegenFlags |= kRegenGlyph;
+ fRegenFlags |= kRegenTex;
+ }
+ if (kARGB_GrMaskFormat != fSubRun->maskFormat() && fSubRun->color() != color) {
+ fRegenFlags |= kRegenCol;
+ }
+ if (0.f != fTransX || 0.f != fTransY) {
+ fRegenFlags |= kRegenPos;
+ }
+}
+
template <bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs>
-void GrAtlasTextBlob::regenInOp(GrDeferredUploadTarget* target, GrAtlasGlyphCache* fontCache,
- GrBlobRegenHelper* helper, Run* run, Run::SubRunInfo* info,
- SkAutoGlyphCache* lazyCache, int glyphCount, size_t vertexStride,
- GrColor color, SkScalar transX, SkScalar transY) const {
- SkASSERT(lazyCache);
+Regenerator::Result Regenerator::doRegen() {
static_assert(!regenGlyphs || regenTexCoords, "must regenTexCoords along regenGlyphs");
GrAtlasTextStrike* strike = nullptr;
if (regenTexCoords) {
- info->resetBulkUseToken();
+ fSubRun->resetBulkUseToken();
- const SkDescriptor* desc = (run->fOverrideDescriptor && !info->drawAsDistanceFields())
- ? run->fOverrideDescriptor->getDesc()
- : run->fDescriptor.getDesc();
+ const SkDescriptor* desc = (fRun->fOverrideDescriptor && !fSubRun->drawAsDistanceFields())
+ ? fRun->fOverrideDescriptor->getDesc()
+ : fRun->fDescriptor.getDesc();
- if (!*lazyCache || (*lazyCache)->getDescriptor() != *desc) {
+ if (!*fLazyCache || (*fLazyCache)->getDescriptor() != *desc) {
SkScalerContextEffects effects;
- effects.fPathEffect = run->fPathEffect.get();
- effects.fRasterizer = run->fRasterizer.get();
- effects.fMaskFilter = run->fMaskFilter.get();
- lazyCache->reset(SkGlyphCache::DetachCache(run->fTypeface.get(), effects, desc));
+ effects.fPathEffect = fRun->fPathEffect.get();
+ effects.fRasterizer = fRun->fRasterizer.get();
+ effects.fMaskFilter = fRun->fMaskFilter.get();
+ fLazyCache->reset(SkGlyphCache::DetachCache(fRun->fTypeface.get(), effects, desc));
}
if (regenGlyphs) {
- strike = fontCache->getStrike(lazyCache->get());
+ strike = fGlyphCache->getStrike(fLazyCache->get());
} else {
- strike = info->strike();
+ strike = fSubRun->strike();
}
}
- bool brokenRun = false;
- intptr_t vertex = reinterpret_cast<intptr_t>(fVertices);
- vertex += info->vertexStartIndex();
- for (int glyphIdx = 0; glyphIdx < glyphCount; glyphIdx++) {
+ Result result;
+ char* currVertex = fBlob->fVertices + fSubRun->vertexStartIndex() +
+ fCurrGlyph * kVerticesPerGlyph * fVertexStride;
+ result.fFirstVertex = currVertex;
+
+ for (int glyphIdx = fCurrGlyph; glyphIdx < (int)fSubRun->glyphCount(); glyphIdx++) {
GrGlyph* glyph = nullptr;
if (regenTexCoords) {
- size_t glyphOffset = glyphIdx + info->glyphStartIndex();
+ size_t glyphOffset = glyphIdx + fSubRun->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(), lazyCache->get());
- SkASSERT(id == fGlyphs[glyphOffset]->fPackedID);
+ GrGlyph::PackedID id = fBlob->fGlyphs[glyphOffset]->fPackedID;
+ fBlob->fGlyphs[glyphOffset] =
+ strike->getGlyph(id, fSubRun->maskFormat(), fLazyCache->get());
+ SkASSERT(id == fBlob->fGlyphs[glyphOffset]->fPackedID);
}
- glyph = fGlyphs[glyphOffset];
- SkASSERT(glyph && glyph->fMaskFormat == info->maskFormat());
-
- if (!fontCache->hasGlyph(glyph) &&
- !strike->addGlyphToAtlas(target, glyph, lazyCache->get(), info->maskFormat())) {
- helper->flush();
- brokenRun = glyphIdx > 0;
-
- SkDEBUGCODE(bool success =) strike->addGlyphToAtlas(target,
- glyph,
- lazyCache->get(),
- info->maskFormat());
- SkASSERT(success);
+ glyph = fBlob->fGlyphs[glyphOffset];
+ SkASSERT(glyph && glyph->fMaskFormat == fSubRun->maskFormat());
+
+ if (!fGlyphCache->hasGlyph(glyph) &&
+ !strike->addGlyphToAtlas(fUploadTarget, glyph, fLazyCache->get(),
+ fSubRun->maskFormat())) {
+ fBrokenRun = glyphIdx > 0;
+ result.fFinished = false;
+ return result;
}
- fontCache->addGlyphToBulkAndSetUseToken(info->bulkUseToken(), glyph,
- target->nextDrawToken());
+ fGlyphCache->addGlyphToBulkAndSetUseToken(fSubRun->bulkUseToken(), glyph,
+ fUploadTarget->nextDrawToken());
}
- regen_vertices<regenPos, regenCol, regenTexCoords>(vertex, glyph, vertexStride,
- info->drawAsDistanceFields(),
- transX, transY, color);
- vertex += vertexStride * GrAtlasTextOp::kVerticesPerGlyph;
- helper->incGlyphCount();
+ regen_vertices<regenPos, regenCol, regenTexCoords>(currVertex, glyph, fVertexStride,
+ fSubRun->drawAsDistanceFields(), fTransX,
+ fTransY, fColor);
+ currVertex += fVertexStride * GrAtlasTextOp::kVerticesPerGlyph;
+ ++result.fGlyphsRegenerated;
+ ++fCurrGlyph;
}
// We may have changed the color so update it here
- info->setColor(color);
+ fSubRun->setColor(fColor);
if (regenTexCoords) {
if (regenGlyphs) {
- info->setStrike(strike);
+ fSubRun->setStrike(strike);
}
- info->setAtlasGeneration(brokenRun ? GrDrawOpAtlas::kInvalidAtlasGeneration
- : fontCache->atlasGeneration(info->maskFormat()));
+ fSubRun->setAtlasGeneration(fBrokenRun
+ ? GrDrawOpAtlas::kInvalidAtlasGeneration
+ : fGlyphCache->atlasGeneration(fSubRun->maskFormat()));
}
+ return result;
}
-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, lazyCache, \
- *glyphCount, vertexStride, color, transX, transY
-
-void GrAtlasTextBlob::regenInOp(GrDeferredUploadTarget* target, GrAtlasGlyphCache* fontCache,
- GrBlobRegenHelper* helper, int runIndex, int subRunIndex,
- SkAutoGlyphCache* lazyCache, size_t vertexStride,
- const SkMatrix& viewMatrix, SkScalar x, SkScalar y, GrColor color,
- void** vertices, size_t* byteCount, int* glyphCount) {
- Run& run = fRuns[runIndex];
- Run::SubRunInfo& info = run.fSubRunInfo[subRunIndex];
-
- uint64_t currentAtlasGen = fontCache->atlasGeneration(info.maskFormat());
-
- // Compute translation if any
- SkScalar transX, transY;
- info.computeTranslation(viewMatrix, x, y, &transX, &transY);
+Regenerator::Result Regenerator::regenerate() {
+ uint64_t currentAtlasGen = fGlyphCache->atlasGeneration(fSubRun->maskFormat());
+ // If regenerate() is called multiple times then the atlas gen may have changed. So we check
+ // this each time.
+ if (fSubRun->atlasGeneration() != currentAtlasGen) {
+ fRegenFlags |= kRegenTex;
+ }
- // Because the GrAtlasGlyphCache 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) {
+ switch (static_cast<RegenMask>(fRegenFlags)) {
case kRegenPos:
- this->regenInOp<true, false, false, false>(REGEN_ARGS);
- break;
+ return this->doRegen<true, false, false, false>();
case kRegenCol:
- this->regenInOp<false, true, false, false>(REGEN_ARGS);
- break;
+ return this->doRegen<false, true, false, false>();
case kRegenTex:
- this->regenInOp<false, false, true, false>(REGEN_ARGS);
- break;
+ return this->doRegen<false, false, true, false>();
case kRegenGlyph:
- this->regenInOp<false, false, true, true>(REGEN_ARGS);
- break;
+ return this->doRegen<false, false, true, true>();
// combinations
case kRegenPosCol:
- this->regenInOp<true, true, false, false>(REGEN_ARGS);
- break;
+ return this->doRegen<true, true, false, false>();
case kRegenPosTex:
- this->regenInOp<true, false, true, false>(REGEN_ARGS);
- break;
+ return this->doRegen<true, false, true, false>();
case kRegenPosTexGlyph:
- this->regenInOp<true, false, true, true>(REGEN_ARGS);
- break;
+ return this->doRegen<true, false, true, true>();
case kRegenPosColTex:
- this->regenInOp<true, true, true, false>(REGEN_ARGS);
- break;
+ return this->doRegen<true, true, true, false>();
case kRegenPosColTexGlyph:
- this->regenInOp<true, true, true, true>(REGEN_ARGS);
- break;
+ return this->doRegen<true, true, true, true>();
case kRegenColTex:
- this->regenInOp<false, true, true, false>(REGEN_ARGS);
- break;
+ return this->doRegen<false, true, true, false>();
case kRegenColTexGlyph:
- this->regenInOp<false, true, true, true>(REGEN_ARGS);
- break;
- case kNoRegen:
- helper->incGlyphCount(*glyphCount);
+ return this->doRegen<false, true, true, true>();
+ case kNoRegen: {
+ Result result;
+ result.fGlyphsRegenerated = fSubRun->glyphCount() - fCurrGlyph;
+ result.fFirstVertex = fBlob->fVertices + fSubRun->vertexStartIndex() +
+ fCurrGlyph * kVerticesPerGlyph * fVertexStride;
+ fCurrGlyph = fSubRun->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->nextDrawToken(),
- info.maskFormat());
- break;
+ fGlyphCache->setUseTokenBulk(*fSubRun->bulkUseToken(), fUploadTarget->nextDrawToken(),
+ fSubRun->maskFormat());
+ return result;
+ }
}
-
- *byteCount = info.byteCount();
- *vertices = fVertices + info.vertexStartIndex();
+ SK_ABORT("Should not get here");
+ return Result();
}