split glyph and geometry data apart

The next subclass I make will have a different description of the
glyphs position and bounds. Split the glyph info from the VertexData
and put it into its own class called GrGlyphVector.

Change-Id: Idaf9e914700832baf14bdb3bd1d8e8aeb8c63243
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/303589
Commit-Queue: Herb Derby <herb@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Herb Derby 2020-07-17 14:07:00 -04:00 committed by Skia Commit-Bot
parent c57327d2ed
commit c1cde36a9b
2 changed files with 153 additions and 113 deletions

View File

@ -122,17 +122,113 @@ auto GrPathSubRun::Make(
isAntiAliased, strikeSpec, SkMakeSpan(pathData, drawables.size()));
};
// -- GrGlyphVector --------------------------------------------------------------------------------
GrGlyphVector::GrGlyphVector(const SkStrikeSpec& spec, SkSpan<Variant> glyphs)
: fStrikeSpec{spec}
, fGlyphs{glyphs} { }
GrGlyphVector GrGlyphVector::Make(
const SkStrikeSpec &spec, SkSpan<SkGlyphVariant> glyphs, SkArenaAlloc *alloc) {
Variant* variants = alloc->makeInitializedArray<Variant>(glyphs.size(),
[&](int i) {
return Variant{glyphs[i].glyph()->getPackedID()};
});
return GrGlyphVector{spec, SkMakeSpan(variants, glyphs.size())};
}
void GrGlyphVector::prepareGrGlyphs(GrStrikeCache* strikeCache) {
if (fStrike) {
return;
}
fStrike = fStrikeSpec.findOrCreateGrStrike(strikeCache);
for (auto& variant : fGlyphs) {
variant.grGlyph = fStrike->getGlyph(variant.packedGlyphID);
}
}
SkSpan<const GrGlyph*> GrGlyphVector::glyphs() const {
return SkMakeSpan(reinterpret_cast<const GrGlyph**>(fGlyphs.data()), fGlyphs.size());
}
std::tuple<bool, int> GrGlyphVector::regenerateAtlas(
int begin, int end, GrMaskFormat maskFormat, int padding, GrMeshDrawOp::Target *target) {
GrAtlasManager* atlasManager = target->atlasManager();
GrDeferredUploadTarget* uploadTarget = target->deferredUploadTarget();
uint64_t currentAtlasGen = atlasManager->atlasGeneration(maskFormat);
this->prepareGrGlyphs(target->strikeCache());
if (fAtlasGeneration != currentAtlasGen) {
// Calculate the texture coordinates for the vertexes during first use (fAtlasGeneration
// is set to kInvalidAtlasGeneration) or the atlas has changed in subsequent calls..
fBulkUseToken.reset();
SkBulkGlyphMetricsAndImages metricsAndImages{fStrikeSpec};
// Update the atlas information in the GrStrike.
auto tokenTracker = uploadTarget->tokenTracker();
auto glyphs = fGlyphs.subspan(begin, end - begin);
int glyphsPlacedInAtlas = 0;
bool success = true;
for (const Variant& variant : glyphs) {
GrGlyph* grGlyph = variant.grGlyph;
SkASSERT(grGlyph != nullptr);
if (!atlasManager->hasGlyph(maskFormat, grGlyph)) {
const SkGlyph& skGlyph = *metricsAndImages.glyph(grGlyph->fPackedID);
auto code = atlasManager->addGlyphToAtlas(
skGlyph, padding, grGlyph,
target->resourceProvider(), uploadTarget);
if (code != GrDrawOpAtlas::ErrorCode::kSucceeded) {
success = code != GrDrawOpAtlas::ErrorCode::kError;
break;
}
}
atlasManager->addGlyphToBulkAndSetUseToken(
&fBulkUseToken, maskFormat, grGlyph,
tokenTracker->nextDrawToken());
glyphsPlacedInAtlas++;
}
// Update atlas generation if there are no more glyphs to put in the atlas.
if (success && begin + glyphsPlacedInAtlas == fGlyphs.count()) {
// Need to get the freshest value of the atlas' generation because
// updateTextureCoordinates may have changed it.
fAtlasGeneration = atlasManager->atlasGeneration(maskFormat);
}
return {success, glyphsPlacedInAtlas};
} else {
// The atlas hasn't changed, so our texture coordinates are still valid.
if (end == fGlyphs.count()) {
// The atlas hasn't changed and the texture coordinates are all still valid. Update
// all the plots used to the new use token.
atlasManager->setUseTokenBulk(fBulkUseToken,
uploadTarget->tokenTracker()->nextDrawToken(),
maskFormat);
}
return {true, end - begin};
}
}
// -- GrMaskSubRun ---------------------------------------------------------------------------------
GrMaskSubRun::GrMaskSubRun(SubRunType type, GrTextBlob* textBlob, const SkStrikeSpec& strikeSpec,
GrMaskFormat format, SkRect vertexBounds,
GrMaskSubRun::GrMaskSubRun(SubRunType type,
GrTextBlob* textBlob,
GrMaskFormat format,
SkRect vertexBounds,
GrGlyphVector glyphs,
const SkSpan<VertexData>& vertexData)
: fBlob{textBlob}
, fType{type}
, fMaskFormat{format}
, fStrikeSpec{strikeSpec}
, fGlyphs{glyphs}
, fVertexBounds{vertexBounds}
, fVertexData{vertexData} {
}
, fVertexData{vertexData} { }
static SkPMColor4f generate_filtered_color(const SkPaint& paint, const GrColorInfo& colorInfo) {
SkColor4f c = paint.getColor4f();
@ -284,69 +380,10 @@ void GrMaskSubRun::draw(const GrClip* clip,
std::tuple<bool, int> GrMaskSubRun::regenerateAtlas(
int begin, int end, GrMeshDrawOp::Target *target) {
GrAtlasManager* atlasManager = target->atlasManager();
GrDeferredUploadTarget* uploadTarget = target->deferredUploadTarget();
uint64_t currentAtlasGen = atlasManager->atlasGeneration(this->maskFormat());
this->prepareGrGlyphs(target->strikeCache());
if (fAtlasGeneration != currentAtlasGen) {
// Calculate the texture coordinates for the vertexes during first use (fAtlasGeneration
// is set to kInvalidAtlasGeneration) or the atlas has changed in subsequent calls..
this->resetBulkUseToken();
SkBulkGlyphMetricsAndImages metricsAndImages{this->strikeSpec()};
// Update the atlas information in the GrStrike.
auto tokenTracker = uploadTarget->tokenTracker();
auto vertexData = this->vertexData().subspan(begin, end - begin);
int glyphsPlacedInAtlas = 0;
bool success = true;
for (auto [glyph, pos, rect] : vertexData) {
GrGlyph* grGlyph = glyph.grGlyph;
SkASSERT(grGlyph != nullptr);
if (!atlasManager->hasGlyph(this->maskFormat(), grGlyph)) {
const SkGlyph& skGlyph = *metricsAndImages.glyph(grGlyph->fPackedID);
auto code = atlasManager->addGlyphToAtlas(
skGlyph, this->atlasPadding(), grGlyph,
target->resourceProvider(), uploadTarget);
if (code != GrDrawOpAtlas::ErrorCode::kSucceeded) {
success = code != GrDrawOpAtlas::ErrorCode::kError;
break;
}
}
atlasManager->addGlyphToBulkAndSetUseToken(
this->bulkUseToken(), this->maskFormat(), grGlyph,
tokenTracker->nextDrawToken());
glyphsPlacedInAtlas++;
}
// Update atlas generation if there are no more glyphs to put in the atlas.
if (success && begin + glyphsPlacedInAtlas == this->glyphCount()) {
// Need to get the freshest value of the atlas' generation because
// updateTextureCoordinates may have changed it.
fAtlasGeneration = atlasManager->atlasGeneration(this->maskFormat());
}
return {success, glyphsPlacedInAtlas};
} else {
// The atlas hasn't changed, so our texture coordinates are still valid.
if (end == this->glyphCount()) {
// The atlas hasn't changed and the texture coordinates are all still valid. Update
// all the plots used to the new use token.
atlasManager->setUseTokenBulk(*this->bulkUseToken(),
uploadTarget->tokenTracker()->nextDrawToken(),
this->maskFormat());
}
return {true, end - begin};
}
return fGlyphs.regenerateAtlas(begin, end, this->maskFormat(), this->atlasPadding(), target);
}
void GrMaskSubRun::resetBulkUseToken() { fBulkUseToken.reset(); }
GrDrawOpAtlas::BulkUseTokenUpdater* GrMaskSubRun::bulkUseToken() { return &fBulkUseToken; }
GrMaskFormat GrMaskSubRun::maskFormat() const { return fMaskFormat; }
size_t GrMaskSubRun::vertexStride() const {
@ -374,11 +411,17 @@ void GrMaskSubRun::fillVertexData(
SkMatrix matrix = drawMatrix;
matrix.preTranslate(drawOrigin.x(), drawOrigin.y());
auto vertices = [&](auto dst) {
return SkMakeZip(dst,
fGlyphs.glyphs().subspan(offset, count),
fVertexData.subspan(offset, count));
};
auto transformed2D = [&](auto dst, SkScalar dstPadding, SkScalar srcPadding) {
SkScalar strikeToSource = fStrikeSpec.strikeToSourceRatio();
SkScalar strikeToSource = fGlyphs.strikeToSourceRatio();
SkPoint inset = {dstPadding, dstPadding};
for (auto[quad, vertexData] : SkMakeZip(dst, fVertexData.subspan(offset, count))) {
auto[glyph, pos, rect] = vertexData;
for (auto[quad, glyph, vertexData] : vertices(dst)) {
auto[pos, rect] = vertexData;
auto [l, t, r, b] = rect;
SkPoint sLT = (SkPoint::Make(l, t) + inset) * strikeToSource + pos,
sRB = (SkPoint::Make(r, b) - inset) * strikeToSource + pos;
@ -386,7 +429,7 @@ void GrMaskSubRun::fillVertexData(
lb = matrix.mapXY(sLT.x(), sRB.y()),
rt = matrix.mapXY(sRB.x(), sLT.y()),
rb = matrix.mapXY(sRB.x(), sRB.y());
auto[al, at, ar, ab] = glyph.grGlyph->fAtlasLocator.getUVs(srcPadding);
auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs(srcPadding);
quad[0] = {lt, color, {al, at}}; // L,T
quad[1] = {lb, color, {al, ab}}; // L,B
quad[2] = {rt, color, {ar, at}}; // R,T
@ -395,7 +438,7 @@ void GrMaskSubRun::fillVertexData(
};
auto transformed3D = [&](auto dst, SkScalar dstPadding, SkScalar srcPadding) {
SkScalar strikeToSource = fStrikeSpec.strikeToSourceRatio();
SkScalar strikeToSource = fGlyphs.strikeToSourceRatio();
SkPoint inset = {dstPadding, dstPadding};
auto mapXYZ = [&](SkScalar x, SkScalar y) {
SkPoint pt{x, y};
@ -403,8 +446,8 @@ void GrMaskSubRun::fillVertexData(
matrix.mapHomogeneousPoints(&result, &pt, 1);
return result;
};
for (auto[quad, vertexData] : SkMakeZip(dst, fVertexData.subspan(offset, count))) {
auto[glyph, pos, rect] = vertexData;
for (auto[quad, glyph, vertexData] : vertices(dst)) {
auto[pos, rect] = vertexData;
auto [l, t, r, b] = rect;
SkPoint sLT = (SkPoint::Make(l, t) + inset) * strikeToSource + pos,
sRB = (SkPoint::Make(r, b) - inset) * strikeToSource + pos;
@ -412,7 +455,7 @@ void GrMaskSubRun::fillVertexData(
lb = mapXYZ(sLT.x(), sRB.y()),
rt = mapXYZ(sRB.x(), sLT.y()),
rb = mapXYZ(sRB.x(), sRB.y());
auto[al, at, ar, ab] = glyph.grGlyph->fAtlasLocator.getUVs(srcPadding);
auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs(srcPadding);
quad[0] = {lt, color, {al, at}}; // L,T
quad[1] = {lb, color, {al, ab}}; // L,B
quad[2] = {rt, color, {ar, at}}; // R,T
@ -423,11 +466,11 @@ void GrMaskSubRun::fillVertexData(
auto direct2D = [&](auto dst, SkIRect* clip) {
// Rectangles in device space
SkPoint originInDeviceSpace = matrix.mapXY(0, 0);
for (auto[quad, vertexData] : SkMakeZip(dst, fVertexData.subspan(offset, count))) {
auto[glyph, pos, rect] = vertexData;
for (auto[quad, glyph, vertexData] : vertices(dst)) {
auto[pos, rect] = vertexData;
auto[l, t, r, b] = rect;
auto[fx, fy] = pos + originInDeviceSpace;
auto[al, at, ar, ab] = glyph.grGlyph->fAtlasLocator.getUVs(0);
auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs(0);
if (clip == nullptr) {
SkScalar dx = SkScalarRoundToScalar(fx),
dy = SkScalarRoundToScalar(fy);
@ -540,7 +583,6 @@ void GrMaskSubRun::fillVertexData(
}
}
int GrMaskSubRun::glyphCount() const {
return fVertexData.count();
}
@ -574,18 +616,6 @@ bool GrMaskSubRun::hasW() const {
return false;
}
void GrMaskSubRun::prepareGrGlyphs(GrStrikeCache* strikeCache) {
if (fStrike) {
return;
}
fStrike = fStrikeSpec.findOrCreateGrStrike(strikeCache);
for (auto& tmp : fVertexData) {
tmp.glyph.grGlyph = fStrike->getGlyph(tmp.glyph.packedGlyphID);
}
}
SkRect GrMaskSubRun::deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const {
SkRect outBounds = fVertexBounds;
if (this->needsTransform()) {
@ -607,7 +637,6 @@ void GrMaskSubRun::setUseLCDText(bool useLCDText) { fUseLCDText = useLCDText; }
bool GrMaskSubRun::hasUseLCDText() const { return fUseLCDText; }
void GrMaskSubRun::setAntiAliased(bool antiAliased) { fAntiAliased = antiAliased; }
bool GrMaskSubRun::isAntiAliased() const { return fAntiAliased; }
const SkStrikeSpec& GrMaskSubRun::strikeSpec() const { return fStrikeSpec; }
auto GrMaskSubRun::MakeSDFT(
const SkZip<SkGlyphVariant, SkPoint>& drawables,
@ -648,7 +677,6 @@ auto GrMaskSubRun::InitForAtlas(SubRunType type,
GrTextBlob* blob,
SkArenaAlloc* alloc) -> GrMaskSubRun* {
size_t vertexCount = drawables.size();
using Data = VertexData;
SkRect bounds = SkRectPriv::MakeLargestInverted();
auto initializer = [&, strikeToSource=strikeSpec.strikeToSourceRatio()](size_t i) {
auto [variant, pos] = drawables[i];
@ -661,14 +689,15 @@ auto GrMaskSubRun::InitForAtlas(SubRunType type,
rb = SkPoint::Make(r, b) * strikeToSource + pos;
bounds.joinPossiblyEmptyRect(SkRect::MakeLTRB(lt.x(), lt.y(), rb.x(), rb.y()));
return Data{{skGlyph->getPackedID()}, pos, {l, t, r, b}};
return VertexData{pos, {l, t, r, b}};
};
SkSpan<Data> vertexData{
alloc->makeInitializedArray<Data>(vertexCount, initializer), vertexCount};
SkSpan<VertexData> vertexData{
alloc->makeInitializedArray<VertexData>(vertexCount, initializer), vertexCount};
GrMaskSubRun* subRun = alloc->make<GrMaskSubRun>(
type, blob, strikeSpec, format, bounds, vertexData);
type, blob, format, bounds,
GrGlyphVector::Make(strikeSpec, drawables.get<0>(), alloc), vertexData);
return subRun;
}

View File

@ -22,6 +22,7 @@
#include "src/gpu/GrColor.h"
#include "src/gpu/GrDrawOpAtlas.h"
#include "src/gpu/ops/GrMeshDrawOp.h"
#include "src/gpu/text/GrStrikeCache.h"
class GrAtlasManager;
class GrAtlasTextOp;
@ -240,6 +241,32 @@ public:
SkIRect clip) const = 0;
};
// -- GrGlyphVector --------------------------------------------------------------------------------
class GrGlyphVector {
union Variant {
// Initially, filled with packed id, but changed to GrGlyph* in the onPrepare stage.
SkPackedGlyphID packedGlyphID;
GrGlyph* grGlyph;
};
public:
static GrGlyphVector Make(
const SkStrikeSpec& spec, SkSpan<SkGlyphVariant> glyphs, SkArenaAlloc* alloc);
void prepareGrGlyphs(GrStrikeCache* strikeCache);
std::tuple<bool, int> regenerateAtlas(
int begin, int end, GrMaskFormat maskFormat, int padding, GrMeshDrawOp::Target *target);
SkSpan<const GrGlyph*> glyphs() const;
SkScalar strikeToSourceRatio() const { return fStrikeSpec.strikeToSourceRatio(); }
private:
GrGlyphVector(const SkStrikeSpec& spec, SkSpan<Variant> glyphs);
const SkStrikeSpec fStrikeSpec;
SkSpan<Variant> fGlyphs;
sk_sp<GrTextStrike> fStrike{nullptr};
uint64_t fAtlasGeneration{GrDrawOpAtlas::kInvalidAtlasGeneration};
GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken;
};
// -- GrMaskSubRun ---------------------------------------------------------------------------------
// Hold data to draw the different types of sub run. SubRuns are produced knowing all the
// glyphs that are included in them.
@ -252,11 +279,6 @@ class GrMaskSubRun : public GrAtlasSubRun {
public:
struct VertexData {
union {
// Initially, filled with packed id, but changed to GrGlyph* in the onPrepare stage.
SkPackedGlyphID packedGlyphID;
GrGlyph* grGlyph;
} glyph;
const SkPoint pos;
// The rectangle of the glyphs in strike space. But, for kDirectMask this also implies a
// device space rect.
@ -266,9 +288,9 @@ public:
// SubRun for masks
GrMaskSubRun(SubRunType type,
GrTextBlob* textBlob,
const SkStrikeSpec& strikeSpec,
GrMaskFormat format,
SkRect vertexBounds,
GrGlyphVector glyphs,
const SkSpan<VertexData>& vertexData);
std::tuple<const GrClip*, std::unique_ptr<GrDrawOp>>
@ -293,8 +315,6 @@ public:
int glyphCount() const override;
const SkStrikeSpec& strikeSpec() const;
static GrSubRun* MakeSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkFont& runFont,
const SkStrikeSpec& strikeSpec,
@ -368,27 +388,18 @@ private:
int atlasPadding() const;
SkSpan<const VertexData> vertexData() const;
// Acquire a GrTextStrike and convert the SkPackedGlyphIDs to GrGlyphs for this run
void prepareGrGlyphs(GrStrikeCache*);
void resetBulkUseToken();
GrDrawOpAtlas::BulkUseTokenUpdater* bulkUseToken();
GrTextBlob* fBlob;
const SubRunType fType;
const GrMaskFormat fMaskFormat;
bool fUseLCDText{false};
bool fAntiAliased{false};
const SkStrikeSpec fStrikeSpec;
sk_sp<GrTextStrike> fStrike;
GrGlyphVector fGlyphs;
GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken;
// The vertex bounds in device space if needsTransform() is false, otherwise the bounds in
// source space. The bounds are the joined rectangles of all the glyphs.
const SkRect fVertexBounds;
const SkSpan<VertexData> fVertexData;
uint64_t fAtlasGeneration{GrDrawOpAtlas::kInvalidAtlasGeneration};
}; // SubRun
#endif // GrTextBlob_DEFINED