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()); |
+} |