diff options
author | 2017-11-06 16:26:02 -0500 | |
---|---|---|
committer | 2017-11-07 01:56:36 +0000 | |
commit | 18923f9a2e83675aecba7561f5095429fb467633 (patch) | |
tree | e59e9a98ee1f7422ecf641cc998a977f28151a70 /src/gpu | |
parent | 75a1377e54fb44c84a2712d9c678b1b448a9cffe (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.cpp | 57 | ||||
-rw-r--r-- | src/gpu/ops/GrAtlasTextOp.h | 22 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasTextBlob.cpp | 3 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasTextBlob.h | 81 | ||||
-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(); } |