split transformed mask from SDFT

* transformed masks -> GrTransformedMaskSubRun
* GrMaskSubRun is SDFT -> GrSDFTSubRun

There is much duplicate code, which will be cleaned up shortly.

Change-Id: If54e388e89f7db15ddfd4b4354f0a1b4d6f5e36b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/305686
Reviewed-by: Herb Derby <herb@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Herb Derby <herb@google.com>
This commit is contained in:
Herb Derby 2020-07-24 15:03:54 -04:00 committed by Skia Commit-Bot
parent 392da6ba30
commit 53453f76b5
3 changed files with 419 additions and 280 deletions

View File

@ -510,7 +510,7 @@ private:
SkScalar setupForAsPaths(SkPaint*);
bool hasSomeAntiAliasing() const;
friend class GrMaskSubRun;
friend class GrSDFTSubRun;
friend class GrTextBlob;
friend class SkFontPriv;
friend class SkGlyphRunListPainter;

View File

@ -212,6 +212,17 @@ std::tuple<bool, int> GrGlyphVector::regenerateAtlas(int begin, int end,
}
}
// -- GrAtlasSubRun --------------------------------------------------------------------------------
static GrAtlasTextOp::MaskType op_mask_type(GrMaskFormat grMaskFormat) {
switch (grMaskFormat) {
case kA8_GrMaskFormat: return GrAtlasTextOp::kGrayscaleCoverageMask_MaskType;
case kA565_GrMaskFormat: return GrAtlasTextOp::kLCDCoverageMask_MaskType;
case kARGB_GrMaskFormat: return GrAtlasTextOp::kColorBitmapMask_MaskType;
// Needed to placate some compilers.
default: return GrAtlasTextOp::kGrayscaleCoverageMask_MaskType;
}
}
// -- GrDirectMaskSubRun ---------------------------------------------------------------------------
GrDirectMaskSubRun::GrDirectMaskSubRun(GrMaskFormat format,
GrTextBlob* blob,
@ -275,16 +286,6 @@ int GrDirectMaskSubRun::glyphCount() const {
return fGlyphs.glyphs().count();
}
static GrAtlasTextOp::MaskType op_mask_type(GrMaskFormat grMaskFormat) {
switch (grMaskFormat) {
case kA8_GrMaskFormat: return GrAtlasTextOp::kGrayscaleCoverageMask_MaskType;
case kA565_GrMaskFormat: return GrAtlasTextOp::kLCDCoverageMask_MaskType;
case kARGB_GrMaskFormat: return GrAtlasTextOp::kColorBitmapMask_MaskType;
// Needed to placate some compilers.
default: return GrAtlasTextOp::kGrayscaleCoverageMask_MaskType;
}
}
static SkPMColor4f calculate_colors(GrRenderTargetContext* rtc,
const SkPaint& paint,
const SkMatrixProvider& matrix,
@ -484,32 +485,70 @@ SkRect GrDirectMaskSubRun::deviceRect(const SkMatrix& drawMatrix, SkPoint drawOr
return outBounds;
}
// -- GrMaskSubRun ---------------------------------------------------------------------------------
GrMaskSubRun::GrMaskSubRun(SubRunType type,
GrTextBlob* textBlob,
GrMaskFormat format,
SkRect vertexBounds,
GrGlyphVector glyphs,
const SkSpan<VertexData>& vertexData)
: fBlob{textBlob}
, fType{type}
, fMaskFormat{format}
, fGlyphs{glyphs}
, fVertexBounds{vertexBounds}
, fVertexData{vertexData} { }
// -- GrTransformedMaskSubRun ----------------------------------------------------------------------
GrTransformedMaskSubRun::GrTransformedMaskSubRun(GrMaskFormat format,
GrTextBlob* blob,
const SkRect& bounds,
SkSpan<const VertexData> vertexData,
GrGlyphVector glyphs)
: fMaskFormat{format}
, fBlob{blob}
, fVertexBounds{bounds}
, fVertexData{vertexData}
, fGlyphs{glyphs} { }
std::tuple<const GrClip*, std::unique_ptr<GrDrawOp> >
GrMaskSubRun::makeAtlasTextOp(const GrClip* clip,
const SkMatrixProvider& viewMatrix,
const SkGlyphRunList& glyphRunList,
GrRenderTargetContext* rtc) const {
GrSubRun* GrTransformedMaskSubRun::Make(const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkStrikeSpec& strikeSpec,
GrMaskFormat format,
GrTextBlob* blob,
SkArenaAlloc* alloc) {
size_t vertexCount = drawables.size();
SkRect bounds = SkRectPriv::MakeLargestInverted();
auto initializer = [&, strikeToSource=strikeSpec.strikeToSourceRatio()](size_t i) {
auto [variant, pos] = drawables[i];
SkGlyph* skGlyph = variant;
int16_t l = skGlyph->left();
int16_t t = skGlyph->top();
int16_t r = l + skGlyph->width();
int16_t b = t + skGlyph->height();
SkPoint lt = SkPoint::Make(l, t) * strikeToSource + pos,
rb = SkPoint::Make(r, b) * strikeToSource + pos;
bounds.joinPossiblyEmptyRect(SkRect::MakeLTRB(lt.x(), lt.y(), rb.x(), rb.y()));
return VertexData{pos, {l, t, r, b}};
};
SkSpan<VertexData> vertexData{
alloc->makeInitializedArray<VertexData>(vertexCount, initializer), vertexCount};
GrAtlasSubRun* subRun = alloc->make<GrTransformedMaskSubRun>(
format, blob, bounds, vertexData,
GrGlyphVector::Make(strikeSpec, drawables.get<0>(), alloc));
return subRun;
}
void GrTransformedMaskSubRun::draw(const GrClip* clip,
const SkMatrixProvider& viewMatrix,
const SkGlyphRunList& glyphRunList,
GrRenderTargetContext* rtc) const {
auto[drawingClip, op] = this->makeAtlasTextOp(clip, viewMatrix, glyphRunList, rtc);
if (op != nullptr) {
rtc->priv().addDrawOp(drawingClip, std::move(op));
}
}
std::tuple<const GrClip*, std::unique_ptr<GrDrawOp>>
GrTransformedMaskSubRun::makeAtlasTextOp(const GrClip* clip,
const SkMatrixProvider& viewMatrix,
const SkGlyphRunList& glyphRunList,
GrRenderTargetContext* rtc) const {
SkASSERT(this->glyphCount() != 0);
SkPoint drawOrigin = glyphRunList.origin();
const SkPaint& drawPaint = glyphRunList.paint();
const SkMatrix& drawMatrix = viewMatrix.localToDevice();
GrRecordingContext* rContext = rtc->priv().recordingContext();
GrOpMemoryPool* pool = rContext->priv().opMemoryPool();
GrOpMemoryPool* pool = rtc->priv().recordingContext()->priv().opMemoryPool();
GrPaint grPaint;
SkPMColor4f drawingColor = calculate_colors(rtc, drawPaint, viewMatrix, fMaskFormat, &grPaint);
@ -524,76 +563,108 @@ GrMaskSubRun::makeAtlasTextOp(const GrClip* clip,
SkRef(fBlob),
drawingColor
};
std::unique_ptr<GrDrawOp> op;
if (!this->drawAsDistanceFields()) {
GrAtlasTextOp::MaskType maskType = op_mask_type(fMaskFormat);
op = pool->allocate<GrAtlasTextOp>(maskType,
true,
this->glyphCount(),
this->deviceRect(drawMatrix, drawOrigin),
geometry,
std::move(grPaint));
} else {
const GrColorInfo& colorInfo = rtc->colorInfo();
const SkSurfaceProps& props = rtc->surfaceProps();
bool isBGR = SkPixelGeometryIsBGR(props.pixelGeometry());
bool isLCD = this->hasUseLCDText() && SkPixelGeometryIsH(props.pixelGeometry());
using MT = GrAtlasTextOp::MaskType;
MT maskType = !this->isAntiAliased() ? MT::kAliasedDistanceField_MaskType
: isLCD ? (isBGR ? MT::kLCDBGRDistanceField_MaskType
: MT::kLCDDistanceField_MaskType)
: MT::kGrayscaleDistanceField_MaskType;
bool useGammaCorrectDistanceTable = colorInfo.isLinearlyBlended();
uint32_t DFGPFlags = drawMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
DFGPFlags |= drawMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
DFGPFlags |= drawMatrix.hasPerspective() ? kPerspective_DistanceFieldEffectFlag : 0;
DFGPFlags |= useGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
DFGPFlags |= MT::kAliasedDistanceField_MaskType == maskType ?
kAliased_DistanceFieldEffectFlag : 0;
if (isLCD) {
DFGPFlags |= kUseLCD_DistanceFieldEffectFlag;
DFGPFlags |= MT::kLCDBGRDistanceField_MaskType == maskType ?
kBGR_DistanceFieldEffectFlag : 0;
}
op = pool->allocate<GrAtlasTextOp>(maskType,
true,
this->glyphCount(),
this->deviceRect(drawMatrix, drawOrigin),
SkPaintPriv::ComputeLuminanceColor(drawPaint),
useGammaCorrectDistanceTable,
DFGPFlags,
geometry,
std::move(grPaint));
}
std::unique_ptr<GrDrawOp> op = pool->allocate<GrAtlasTextOp>(
op_mask_type(fMaskFormat),
true,
this->glyphCount(),
this->deviceRect(drawMatrix, drawOrigin),
geometry,
std::move(grPaint));
return {clip, std::move(op)};
}
void GrMaskSubRun::draw(const GrClip* clip,
const SkMatrixProvider& viewMatrix,
const SkGlyphRunList& glyphRunList,
GrRenderTargetContext* rtc) const {
auto[drawingClip, op] = this->makeAtlasTextOp(clip, viewMatrix, glyphRunList, rtc);
if (op != nullptr) {
rtc->priv().addDrawOp(drawingClip, std::move(op));
std::tuple<bool, int> GrTransformedMaskSubRun::regenerateAtlas(int begin, int end,
GrMeshDrawOp::Target* target) const {
return fGlyphs.regenerateAtlas(begin, end, fMaskFormat, 1, target);
}
void GrTransformedMaskSubRun::fillVertexData(void* vertexDst,
int offset, int count,
GrColor color,
const SkMatrix& drawMatrix, SkPoint drawOrigin,
SkIRect clip) const {
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 = fGlyphs.strikeToSourceRatio();
SkPoint inset = {dstPadding, dstPadding};
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;
SkPoint lt = matrix.mapXY(sLT.x(), sLT.y()),
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->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
quad[3] = {rb, color, {ar, ab}}; // R,B
}
};
auto transformed3D = [&](auto dst, SkScalar dstPadding, SkScalar srcPadding) {
SkScalar strikeToSource = fGlyphs.strikeToSourceRatio();
SkPoint inset = {dstPadding, dstPadding};
auto mapXYZ = [&](SkScalar x, SkScalar y) {
SkPoint pt{x, y};
SkPoint3 result;
matrix.mapHomogeneousPoints(&result, &pt, 1);
return result;
};
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;
SkPoint3 lt = mapXYZ(sLT.x(), sLT.y()),
lb = mapXYZ(sLT.x(), sRB.y()),
rt = mapXYZ(sRB.x(), sLT.y()),
rb = mapXYZ(sRB.x(), sRB.y());
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
quad[3] = {rb, color, {ar, ab}}; // R,B
}
};
if (!this->hasW()) {
if (fMaskFormat == GrMaskFormat::kARGB_GrMaskFormat) {
using Quad = ARGB2DVertex[4];
SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
transformed2D((Quad*) vertexDst, 0, 1);
} else {
using Quad = Mask2DVertex[4];
SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
transformed2D((Quad*) vertexDst, 0, 1);
}
} else {
if (fMaskFormat == GrMaskFormat::kARGB_GrMaskFormat) {
using Quad = ARGB3DVertex[4];
SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
transformed3D((Quad*) vertexDst, 0, 1);
} else {
using Quad = Mask3DVertex[4];
SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
transformed3D((Quad*) vertexDst, 0, 1);
}
}
}
std::tuple<bool, int> GrMaskSubRun::regenerateAtlas(
int begin, int end, GrMeshDrawOp::Target *target) const {
return fGlyphs.regenerateAtlas(begin, end, this->maskFormat(), this->atlasPadding(), target);
}
GrMaskFormat GrMaskSubRun::maskFormat() const { return fMaskFormat; }
size_t GrMaskSubRun::vertexStride() const {
switch (this->maskFormat()) {
size_t GrTransformedMaskSubRun::vertexStride() const {
switch (fMaskFormat) {
case kA8_GrMaskFormat:
return this->hasW() ? sizeof(Mask3DVertex) : sizeof(Mask2DVertex);
case kARGB_GrMaskFormat:
@ -605,7 +676,155 @@ size_t GrMaskSubRun::vertexStride() const {
SkUNREACHABLE;
}
void GrMaskSubRun::fillVertexData(
int GrTransformedMaskSubRun::glyphCount() const {
return fVertexData.count();
}
bool GrTransformedMaskSubRun::hasW() const {
return fBlob->hasPerspective();
}
SkRect GrTransformedMaskSubRun::deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const {
SkRect outBounds = fVertexBounds;
outBounds.offset(drawOrigin);
return drawMatrix.mapRect(outBounds);
}
// -- GrSDFTSubRun ---------------------------------------------------------------------------------
GrSDFTSubRun::GrSDFTSubRun(GrMaskFormat format,
GrTextBlob* textBlob,
SkRect vertexBounds,
SkSpan<const VertexData> vertexData,
GrGlyphVector glyphs,
bool useLCDText,
bool antiAliased)
: fMaskFormat{format}
, fBlob{textBlob}
, fVertexBounds{vertexBounds}
, fVertexData{vertexData}
, fGlyphs{glyphs}
, fUseLCDText{useLCDText}
, fAntiAliased{antiAliased} { }
GrSubRun* GrSDFTSubRun::Make(
const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkFont& runFont,
const SkStrikeSpec& strikeSpec,
GrTextBlob* blob,
SkArenaAlloc* alloc) {
size_t vertexCount = drawables.size();
SkRect bounds = SkRectPriv::MakeLargestInverted();
auto initializer = [&, strikeToSource=strikeSpec.strikeToSourceRatio()](size_t i) {
auto [variant, pos] = drawables[i];
SkGlyph* skGlyph = variant;
int16_t l = skGlyph->left();
int16_t t = skGlyph->top();
int16_t r = l + skGlyph->width();
int16_t b = t + skGlyph->height();
SkPoint lt = SkPoint::Make(l, t) * strikeToSource + pos,
rb = SkPoint::Make(r, b) * strikeToSource + pos;
bounds.joinPossiblyEmptyRect(SkRect::MakeLTRB(lt.x(), lt.y(), rb.x(), rb.y()));
return VertexData{pos, {l, t, r, b}};
};
SkSpan<VertexData> vertexData{
alloc->makeInitializedArray<VertexData>(vertexCount, initializer), vertexCount};
return alloc->make<GrSDFTSubRun>(
kA8_GrMaskFormat,
blob,
bounds,
vertexData,
GrGlyphVector::Make(strikeSpec, drawables.get<0>(), alloc),
runFont.getEdging() == SkFont::Edging::kSubpixelAntiAlias,
runFont.hasSomeAntiAliasing());
}
std::tuple<const GrClip*, std::unique_ptr<GrDrawOp> >
GrSDFTSubRun::makeAtlasTextOp(const GrClip* clip,
const SkMatrixProvider& viewMatrix,
const SkGlyphRunList& glyphRunList,
GrRenderTargetContext* rtc) const {
SkASSERT(this->glyphCount() != 0);
SkPoint drawOrigin = glyphRunList.origin();
const SkPaint& drawPaint = glyphRunList.paint();
const SkMatrix& drawMatrix = viewMatrix.localToDevice();
GrOpMemoryPool* pool = rtc->priv().recordingContext()->priv().opMemoryPool();
GrPaint grPaint;
SkPMColor4f drawingColor = calculate_colors(rtc, drawPaint, viewMatrix, fMaskFormat, &grPaint);
const GrColorInfo& colorInfo = rtc->colorInfo();
const SkSurfaceProps& props = rtc->surfaceProps();
bool isBGR = SkPixelGeometryIsBGR(props.pixelGeometry());
bool isLCD = fUseLCDText && SkPixelGeometryIsH(props.pixelGeometry());
using MT = GrAtlasTextOp::MaskType;
MT maskType = !fAntiAliased ? MT::kAliasedDistanceField_MaskType
: isLCD ? (isBGR ? MT::kLCDBGRDistanceField_MaskType
: MT::kLCDDistanceField_MaskType)
: MT::kGrayscaleDistanceField_MaskType;
bool useGammaCorrectDistanceTable = colorInfo.isLinearlyBlended();
uint32_t DFGPFlags = drawMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
DFGPFlags |= drawMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
DFGPFlags |= drawMatrix.hasPerspective() ? kPerspective_DistanceFieldEffectFlag : 0;
DFGPFlags |= useGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
DFGPFlags |= MT::kAliasedDistanceField_MaskType == maskType ?
kAliased_DistanceFieldEffectFlag : 0;
if (isLCD) {
DFGPFlags |= kUseLCD_DistanceFieldEffectFlag;
DFGPFlags |= MT::kLCDBGRDistanceField_MaskType == maskType ?
kBGR_DistanceFieldEffectFlag : 0;
}
GrAtlasTextOp::Geometry geometry = {
*this,
drawMatrix,
drawOrigin,
SkIRect::MakeEmpty(),
SkRef(fBlob),
drawingColor
};
std::unique_ptr<GrDrawOp> op = pool->allocate<GrAtlasTextOp>(
maskType,
true,
this->glyphCount(),
this->deviceRect(drawMatrix, drawOrigin),
SkPaintPriv::ComputeLuminanceColor(drawPaint),
useGammaCorrectDistanceTable,
DFGPFlags,
geometry,
std::move(grPaint));
return {clip, std::move(op)};
}
void GrSDFTSubRun::draw(const GrClip* clip,
const SkMatrixProvider& viewMatrix,
const SkGlyphRunList& glyphRunList,
GrRenderTargetContext* rtc) const {
auto[drawingClip, op] = this->makeAtlasTextOp(clip, viewMatrix, glyphRunList, rtc);
if (op != nullptr) {
rtc->priv().addDrawOp(drawingClip, std::move(op));
}
}
std::tuple<bool, int> GrSDFTSubRun::regenerateAtlas(
int begin, int end, GrMeshDrawOp::Target *target) const {
return fGlyphs.regenerateAtlas(begin, end, fMaskFormat, 0, target);
}
size_t GrSDFTSubRun::vertexStride() const {
return this->hasW() ? sizeof(Mask3DVertex) : sizeof(Mask2DVertex);
}
void GrSDFTSubRun::fillVertexData(
void *vertexDst, int offset, int count,
GrColor color, const SkMatrix& drawMatrix, SkPoint drawOrigin, SkIRect clip) const {
@ -664,141 +883,31 @@ void GrMaskSubRun::fillVertexData(
}
};
switch (fType) {
case kTransformedMask: {
if (!this->hasW()) {
if (this->maskFormat() == GrMaskFormat::kARGB_GrMaskFormat) {
using Quad = ARGB2DVertex[4];
SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
transformed2D((Quad*) vertexDst, 0, 1);
} else {
using Quad = Mask2DVertex[4];
SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
transformed2D((Quad*) vertexDst, 0, 1);
}
} else {
if (this->maskFormat() == GrMaskFormat::kARGB_GrMaskFormat) {
using Quad = ARGB3DVertex[4];
SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
transformed3D((Quad*) vertexDst, 0, 1);
} else {
using Quad = Mask3DVertex[4];
SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
transformed3D((Quad*) vertexDst, 0, 1);
}
}
break;
}
case kTransformedSDFT: {
if (!this->hasW()) {
using Quad = Mask2DVertex[4];
SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
transformed2D((Quad*) vertexDst, SK_DistanceFieldInset, SK_DistanceFieldInset);
} else {
using Quad = Mask3DVertex[4];
SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
transformed3D((Quad*) vertexDst, SK_DistanceFieldInset, SK_DistanceFieldInset);
}
break;
}
if (!this->hasW()) {
using Quad = Mask2DVertex[4];
SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
transformed2D((Quad*) vertexDst, SK_DistanceFieldInset, SK_DistanceFieldInset);
} else {
using Quad = Mask3DVertex[4];
SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
transformed3D((Quad*) vertexDst, SK_DistanceFieldInset, SK_DistanceFieldInset);
}
}
int GrMaskSubRun::glyphCount() const {
int GrSDFTSubRun::glyphCount() const {
return fVertexData.count();
}
bool GrMaskSubRun::drawAsDistanceFields() const { return fType == kTransformedSDFT; }
bool GrMaskSubRun::needsPadding() const {
return fType == kTransformedMask;
}
int GrMaskSubRun::atlasPadding() const {
return SkTo<int>(this->needsPadding());
}
auto GrMaskSubRun::vertexData() const -> SkSpan<const VertexData> {
return fVertexData;
}
bool GrMaskSubRun::hasW() const {
if (fType == kTransformedSDFT || fType == kTransformedMask) {
bool GrSDFTSubRun::hasW() const {
return fBlob->hasPerspective();
}
// The viewMatrix is implicitly SkMatrix::I when drawing kDirectMask, because it is not
// used.
return false;
}
SkRect GrMaskSubRun::deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const {
SkRect GrSDFTSubRun::deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const {
SkRect outBounds = fVertexBounds;
outBounds.offset(drawOrigin);
return drawMatrix.mapRect(outBounds);
}
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; }
auto GrMaskSubRun::MakeSDFT(
const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkFont& runFont,
const SkStrikeSpec& strikeSpec,
GrTextBlob* blob,
SkArenaAlloc* alloc) -> GrSubRun* {
GrMaskSubRun* subRun = GrMaskSubRun::InitForAtlas(
kTransformedSDFT, drawables, strikeSpec, kA8_GrMaskFormat, blob, alloc);
subRun->setUseLCDText(runFont.getEdging() == SkFont::Edging::kSubpixelAntiAlias);
subRun->setAntiAliased(runFont.hasSomeAntiAliasing());
return subRun;
}
auto GrMaskSubRun::MakeTransformedMask(
const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkStrikeSpec& strikeSpec,
GrMaskFormat format,
GrTextBlob* blob,
SkArenaAlloc* alloc) -> GrSubRun* {
return GrMaskSubRun::InitForAtlas(
kTransformedMask, drawables, strikeSpec, format, blob, alloc);
}
auto GrMaskSubRun::InitForAtlas(SubRunType type,
const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkStrikeSpec& strikeSpec,
GrMaskFormat format,
GrTextBlob* blob,
SkArenaAlloc* alloc) -> GrMaskSubRun* {
size_t vertexCount = drawables.size();
SkRect bounds = SkRectPriv::MakeLargestInverted();
auto initializer = [&, strikeToSource=strikeSpec.strikeToSourceRatio()](size_t i) {
auto [variant, pos] = drawables[i];
SkGlyph* skGlyph = variant;
int16_t l = skGlyph->left();
int16_t t = skGlyph->top();
int16_t r = l + skGlyph->width();
int16_t b = t + skGlyph->height();
SkPoint lt = SkPoint::Make(l, t) * strikeToSource + pos,
rb = SkPoint::Make(r, b) * strikeToSource + pos;
bounds.joinPossiblyEmptyRect(SkRect::MakeLTRB(lt.x(), lt.y(), rb.x(), rb.y()));
return VertexData{pos, {l, t, r, b}};
};
SkSpan<VertexData> vertexData{
alloc->makeInitializedArray<VertexData>(vertexCount, initializer), vertexCount};
GrMaskSubRun* subRun = alloc->make<GrMaskSubRun>(
type, blob, format, bounds,
GrGlyphVector::Make(strikeSpec, drawables.get<0>(), alloc), vertexData);
return subRun;
}
// -- GrTextBlob -----------------------------------------------------------------------------------
void GrTextBlob::operator delete(void* p) { ::operator delete(p); }
void* GrTextBlob::operator new(size_t) { SK_ABORT("All blobs are created by placement new."); }
@ -808,12 +917,12 @@ GrTextBlob::~GrTextBlob() = default;
sk_sp<GrTextBlob> GrTextBlob::Make(const SkGlyphRunList& glyphRunList, const SkMatrix& drawMatrix) {
// The difference in alignment from the storage of VertexData to SubRun;
using AllSubRuns = std::aligned_union_t<1, GrMaskSubRun, GrDirectMaskSubRun, GrPathSubRun>;
constexpr size_t alignDiff = alignof(AllSubRuns) - alignof(GrMaskSubRun::VertexData);
using AllSubRuns = std::aligned_union_t<1, GrSDFTSubRun, GrDirectMaskSubRun, GrPathSubRun>;
constexpr size_t alignDiff = alignof(AllSubRuns) - alignof(GrSDFTSubRun::VertexData);
constexpr size_t vertexDataToSubRunPadding = alignDiff > 0 ? alignDiff : 0;
size_t totalGlyphCount = glyphRunList.totalGlyphCount();
size_t arenaSize =
totalGlyphCount * sizeof(GrMaskSubRun::VertexData)
totalGlyphCount * sizeof(GrSDFTSubRun::VertexData)
+ GrGlyphVector::GlyphVectorSize(totalGlyphCount)
+ glyphRunList.runCount() * (sizeof(AllSubRuns) + vertexDataToSubRunPadding)
+ 32; // Misc arena overhead.
@ -1020,11 +1129,11 @@ void GrTextBlob::processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawabl
SkScalar maxScale) {
this->setHasDistanceField();
this->setMinAndMaxScale(minScale, maxScale);
GrSubRun* subRun = GrMaskSubRun::MakeSDFT(drawables, runFont, strikeSpec, this, &fAlloc);
GrSubRun* subRun = GrSDFTSubRun::Make(drawables, runFont, strikeSpec, this, &fAlloc);
this->insertSubRun(subRun);
}
void GrTextBlob::processSourceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkStrikeSpec& strikeSpec) {
this->addMultiMaskFormat(GrMaskSubRun::MakeTransformedMask, drawables, strikeSpec);
this->addMultiMaskFormat(GrTransformedMaskSubRun::Make, drawables, strikeSpec);
}

View File

@ -318,7 +318,7 @@ public:
GrDirectMaskSubRun(GrMaskFormat format,
GrTextBlob* blob,
const SkRect& bounds,
SkSpan<const VertexData> fVertexData,
SkSpan<const VertexData> vertexData,
GrGlyphVector glyphs);
static GrSubRun* Make(const SkZip<SkGlyphVariant, SkPoint>& drawables,
@ -363,15 +363,8 @@ private:
mutable GrGlyphVector fGlyphs;
};
// -- GrMaskSubRun ---------------------------------------------------------------------------------
// Hold data to draw the different types of sub run. SubRuns are produced knowing all the
// glyphs that are included in them.
class GrMaskSubRun : public GrAtlasSubRun {
enum SubRunType {
kTransformedMask,
kTransformedSDFT
};
// -- GrTransformedMaskSubRun ----------------------------------------------------------------------
class GrTransformedMaskSubRun : public GrAtlasSubRun {
public:
struct VertexData {
const SkPoint pos;
@ -381,12 +374,22 @@ public:
};
// SubRun for masks
GrMaskSubRun(SubRunType type,
GrTextBlob* textBlob,
GrMaskFormat format,
SkRect vertexBounds,
GrGlyphVector glyphs,
const SkSpan<VertexData>& vertexData);
GrTransformedMaskSubRun(GrMaskFormat format,
GrTextBlob* blob,
const SkRect& bounds,
SkSpan<const VertexData> vertexData,
GrGlyphVector glyphs);
static GrSubRun* Make(const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkStrikeSpec& strikeSpec,
GrMaskFormat format,
GrTextBlob* blob,
SkArenaAlloc* alloc);
void draw(const GrClip* clip,
const SkMatrixProvider& viewMatrix,
const SkGlyphRunList& glyphRunList,
GrRenderTargetContext* rtc) const override;
std::tuple<const GrClip*, std::unique_ptr<GrDrawOp>>
makeAtlasTextOp(const GrClip* clip,
@ -394,72 +397,99 @@ public:
const SkGlyphRunList& glyphRunList,
GrRenderTargetContext* rtc) const override;
void draw(const GrClip* clip,
const SkMatrixProvider& viewMatrix,
const SkGlyphRunList& glyphRunList,
GrRenderTargetContext* rtc) const override;
std::tuple<bool, int> regenerateAtlas(
int begin, int end, GrMeshDrawOp::Target* target) const override;
size_t vertexStride() const override;
void fillVertexData(
void* vertexDst, int offset, int count,
GrColor color, const SkMatrix& drawMatrix, SkPoint drawOrigin,
SkIRect clip) const override;
size_t vertexStride() const override;
int glyphCount() const override;
static GrSubRun* MakeSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkFont& runFont,
const SkStrikeSpec& strikeSpec,
GrTextBlob* blob,
SkArenaAlloc* alloc);
private:
bool hasW() const;
// The rectangle that surrounds all the glyph bounding boxes in device space.
SkRect deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const;
static GrSubRun* MakeTransformedMask(const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkStrikeSpec& strikeSpec,
GrMaskFormat format,
GrTextBlob* blob,
SkArenaAlloc* alloc);
const GrMaskFormat fMaskFormat;
GrTextBlob* fBlob;
// The bounds in source space. The bounds are the joined rectangles of all the glyphs.
const SkRect fVertexBounds;
const SkSpan<const VertexData> fVertexData;
// The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
// be single threaded.
mutable GrGlyphVector fGlyphs;
};
// -- GrSDFTSubRun ---------------------------------------------------------------------------------
// Hold data to draw Scaled Distance Field Text sub runs.
class GrSDFTSubRun : public GrAtlasSubRun {
public:
struct VertexData {
const SkPoint pos;
// The rectangle of the glyphs in strike space.
GrIRect16 rect;
};
GrSDFTSubRun(GrMaskFormat format,
GrTextBlob* blob,
SkRect vertexBounds,
SkSpan<const VertexData> vertexData,
GrGlyphVector glyphs,
bool useLCDText,
bool antiAliased);
static GrSubRun* Make(const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkFont& runFont,
const SkStrikeSpec& strikeSpec,
GrTextBlob* blob,
SkArenaAlloc* alloc);
void draw(const GrClip* clip,
const SkMatrixProvider& viewMatrix,
const SkGlyphRunList& glyphRunList,
GrRenderTargetContext* rtc) const override;
std::tuple<const GrClip*, std::unique_ptr<GrDrawOp>>
makeAtlasTextOp(const GrClip* clip,
const SkMatrixProvider& viewMatrix,
const SkGlyphRunList& glyphRunList,
GrRenderTargetContext* rtc) const override;
std::tuple<bool, int> regenerateAtlas(
int begin, int end, GrMeshDrawOp::Target* target) const override;
void fillVertexData(
void* vertexDst, int offset, int count,
GrColor color, const SkMatrix& drawMatrix, SkPoint drawOrigin,
SkIRect clip) const override;
size_t vertexStride() const override;
int glyphCount() const override;
private:
static GrMaskSubRun* InitForAtlas(SubRunType type,
const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkStrikeSpec& strikeSpec,
GrMaskFormat format,
GrTextBlob* blob,
SkArenaAlloc* alloc);
bool hasW() const;
void setUseLCDText(bool useLCDText);
void setAntiAliased(bool antiAliased);
// df properties
bool hasUseLCDText() const;
bool isAntiAliased() const;
GrMaskFormat maskFormat() const;
// The rectangle that surrounds all the glyph bounding boxes in device space.
SkRect deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const;
bool drawAsDistanceFields() const;
bool needsPadding() const;
int atlasPadding() const;
SkSpan<const VertexData> vertexData() const;
GrTextBlob* fBlob;
const SubRunType fType;
const GrMaskFormat fMaskFormat;
bool fUseLCDText{false};
bool fAntiAliased{false};
GrTextBlob* fBlob;
// The bounds in source space. The bounds are the joined rectangles of all the glyphs.
const SkRect fVertexBounds;
const SkSpan<const VertexData> fVertexData;
// The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
// be single threaded.
mutable GrGlyphVector fGlyphs;
// The bounds in source space. The bounds are the joined rectangles of all the glyphs.
const SkRect fVertexBounds;
const SkSpan<VertexData> fVertexData;
}; // SubRun
const bool fUseLCDText;
const bool fAntiAliased;
};
#endif // GrTextBlob_DEFINED