encapsulate GrSDFTOptions better

The logic for picking what type of sub run to create is spread
over several locations. Gather that altogether in drawingType().

Have GrSDFT close over all the data needed to calculate the
drawing type. This reduces plumbing to the processGlyphRun
routine.

The next CL should rename GrSDFTOptions to GrSDFTControl.

Change-Id: I99e74c11af6d3b3d9919e54fe1e7286fcfbf1bfb
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/378036
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Herb Derby <herb@google.com>
This commit is contained in:
Herb Derby 2021-03-01 14:19:36 -05:00 committed by Skia Commit-Bot
parent 158cab563f
commit 9ad09829f5
13 changed files with 80 additions and 78 deletions

View File

@ -49,15 +49,14 @@ class DirectMaskGlyphVertexFillBenchmark : public Benchmark {
SkGlyphRunListPainter painter{props, kUnknown_SkColorType,
colorSpace.get(), SkStrikeCache::GlobalStrikeCache()};
GrSDFTOptions options{256, 256};
GrSDFTOptions options{false, props.isUseDeviceIndependentFonts(), 256, 256};
const SkPoint drawOrigin = glyphRunList.origin();
const SkPaint& drawPaint = glyphRunList.paint();
SkMatrix drawMatrix = view;
drawMatrix.preTranslate(drawOrigin.x(), drawOrigin.y());
for (auto& glyphRun : glyphRunList) {
painter.processGlyphRun(
glyphRun, drawMatrix, drawPaint, props, false, options, fBlob.get());
painter.processGlyphRun(glyphRun, drawMatrix, drawPaint, options, fBlob.get());
}
SkASSERT(!fBlob->subRunList().isEmpty());

View File

@ -140,21 +140,15 @@ void SkGlyphRunListPainter::drawForBitmapDevice(
void SkGlyphRunListPainter::processGlyphRun(const SkGlyphRun& glyphRun,
const SkMatrix& drawMatrix,
const SkPaint& runPaint,
const SkSurfaceProps& props,
bool contextSupportsDistanceFieldText,
const GrSDFTOptions& options,
SkGlyphRunPainterInterface* process) {
ScopedBuffers _ = this->ensureBuffers(glyphRun);
fRejects.setSource(glyphRun.source());
const SkFont& runFont = glyphRun.font();
bool useSDFT = options.canDrawAsDistanceFields(
runPaint, runFont, drawMatrix, props, contextSupportsDistanceFieldText);
GrSDFTOptions::DrawingType drawingType = options.drawingType(runFont, runPaint, drawMatrix);
bool usePaths =
useSDFT ? false : SkStrikeSpec::ShouldDrawAsPath(runPaint, runFont, drawMatrix);
if (useSDFT) {
if (drawingType == GrSDFTOptions::kSDFT) {
// Process SDFT - This should be the .009% case.
const auto& [strikeSpec, minScale, maxScale] =
SkStrikeSpec::MakeSDFT(runFont, runPaint, fDeviceProps, drawMatrix, options);
@ -175,7 +169,7 @@ void SkGlyphRunListPainter::processGlyphRun(const SkGlyphRun& glyphRun,
}
}
if (!usePaths && !fRejects.source().empty()) {
if (drawingType != GrSDFTOptions::kPath && !fRejects.source().empty()) {
// Process masks including ARGB - this should be the 99.99% case.
SkStrikeSpec strikeSpec = SkStrikeSpec::MakeMask(

View File

@ -86,8 +86,6 @@ public:
void processGlyphRun(const SkGlyphRun& glyphRun,
const SkMatrix& drawMatrix,
const SkPaint& drawPaint,
const SkSurfaceProps& props,
bool contextSupportsDistanceFieldText,
const GrSDFTOptions& options,
SkGlyphRunPainterInterface* process);
#endif // SK_SUPPORT_GPU

View File

@ -819,7 +819,10 @@ protected:
#if SK_SUPPORT_GPU
GrContextOptions ctxOptions;
GrSDFTOptions options =
{ctxOptions.fMinDistanceFieldFontSize, ctxOptions.fGlyphsAsPathsFontSize};
GrSDFTOptions{fDFTSupport,
this->surfaceProps().isUseDeviceIndependentFonts(),
ctxOptions.fMinDistanceFieldFontSize,
ctxOptions.fGlyphsAsPathsFontSize};
SkMatrix drawMatrix = this->localToDevice();
drawMatrix.preTranslate(glyphRunList.origin().x(), glyphRunList.origin().y());
@ -827,8 +830,6 @@ protected:
fPainter.processGlyphRun(glyphRun,
drawMatrix,
glyphRunList.paint(),
this->surfaceProps(),
fDFTSupport,
options,
nullptr);
}

View File

@ -7,8 +7,17 @@
#include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/GrCaps.h"
#include "src/gpu/GrDrawingManager.h"
void GrRecordingContextPriv::moveRenderTasksToDDL(SkDeferredDisplayList* ddl) {
fContext->drawingManager()->moveRenderTasksToDDL(ddl);
}
GrSDFTOptions GrRecordingContextPriv::getSDFTOptions(bool useSDFTForSmallText) const {
return GrSDFTOptions{
this->caps()->shaderCaps()->supportsDistanceFieldText(),
useSDFTForSmallText,
this->options().fMinDistanceFieldFontSize,
this->options().fGlyphsAsPathsFontSize};
}

View File

@ -102,9 +102,7 @@ public:
return &fContext->fStats;
}
GrSDFTOptions SDFTOptions() const {
return {this->options().fMinDistanceFieldFontSize, this->options().fGlyphsAsPathsFontSize};
}
GrSDFTOptions getSDFTOptions(bool useSDFTForSmallText) const;
/**
* Create a GrRecordingContext without a resource cache

View File

@ -364,7 +364,10 @@ void GrSurfaceDrawContext::drawGlyphRunList(const GrClip* clip,
return;
}
GrSDFTOptions options = fContext->priv().SDFTOptions();
GrSDFTOptions options =
this->recordingContext()->priv().getSDFTOptions(
this->surfaceProps().isUseDeviceIndependentFonts());
GrTextBlobCache* textBlobCache = fContext->priv().getTextBlobCache();
// Get the first paint to use as the key paint.
@ -424,13 +427,10 @@ void GrSurfaceDrawContext::drawGlyphRunList(const GrClip* clip,
}
blob = GrTextBlob::Make(glyphRunList, drawMatrix);
bool supportsSDFT = fContext->priv().caps()->shaderCaps()->supportsDistanceFieldText();
blob->makeSubRuns(&fGlyphPainter,
glyphRunList,
drawMatrix,
drawPaint,
fSurfaceProps,
supportsSDFT,
options);
if (canCache) {

View File

@ -483,7 +483,8 @@ GrOp::Owner GrAtlasTextOp::CreateOpTestingOnly(GrSurfaceDrawContext* rtc,
}
auto rContext = rtc->recordingContext();
GrSDFTOptions SDFOptions = rContext->priv().SDFTOptions();
GrSDFTOptions SDFOptions =
rContext->priv().getSDFTOptions(rtc->surfaceProps().isUseDeviceIndependentFonts());
sk_sp<GrTextBlob> blob = GrTextBlob::Make(glyphRunList, drawMatrix);
SkGlyphRunListPainter* painter = rtc->glyphRunPainter();
@ -491,9 +492,8 @@ GrOp::Owner GrAtlasTextOp::CreateOpTestingOnly(GrSurfaceDrawContext* rtc,
*glyphRunList.begin(),
drawMatrix,
glyphRunList.paint(),
rtc->surfaceProps(),
rContext->priv().caps()->shaderCaps()->supportsDistanceFieldText(),
SDFOptions, blob.get());
SDFOptions,
blob.get());
if (blob->subRunList().isEmpty()) {
return nullptr;
}

View File

@ -8,10 +8,12 @@
#include "src/gpu/text/GrSDFTOptions.h"
#include "include/core/SkFont.h"
#include "include/core/SkGraphics.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSurfaceProps.h"
#include "src/core/SkGlyphRunPainter.h"
#include <tuple>
@ -28,50 +30,49 @@ static const int kLargeDFFontLimit = 162;
static const int kExtraLargeDFFontSize = 256;
#endif
GrSDFTOptions::GrSDFTOptions(SkScalar min, SkScalar max)
: fMinDistanceFieldFontSize{min}
, fMaxDistanceFieldFontSize{max} {
SkASSERT_RELEASE(min > 0 && max >= min);
SkScalar GrSDFTOptions::MinSDFTRange(bool useSDFTForSmallText, SkScalar min) {
if (!useSDFTForSmallText) {
return kLargeDFFontSize;
}
return min;
}
bool GrSDFTOptions::canDrawAsDistanceFields(const SkPaint& paint, const SkFont& font,
const SkMatrix& viewMatrix,
const SkSurfaceProps& props,
bool contextSupportsDistanceFieldText) const {
// mask filters modify alpha, which doesn't translate well to distance
if (paint.getMaskFilter() || !contextSupportsDistanceFieldText) {
return false;
GrSDFTOptions::GrSDFTOptions(
bool ableToUseSDFT, bool useSDFTForSmallText, SkScalar min, SkScalar max)
: fMinDistanceFieldFontSize{MinSDFTRange(useSDFTForSmallText, min)}
, fMaxDistanceFieldFontSize{max}
, fAbleToUseSDFT{ableToUseSDFT} {
SkASSERT_RELEASE(0 < min && min <= max);
}
auto GrSDFTOptions::drawingType(
const SkFont& font, const SkPaint& paint, const SkMatrix& viewMatrix) const -> DrawingType {
// Use paths as the first choice for hairlines and perspective.
if ((paint.getStyle() == SkPaint::kStroke_Style && paint.getStrokeWidth() == 0)
|| viewMatrix.hasPerspective()) {
return kPath;
}
// TODO: add some stroking support
if (paint.getStyle() != SkPaint::kFill_Style) {
return false;
SkScalar maxScale = viewMatrix.getMaxScale();
SkScalar scaledTextSize = maxScale * font.getSize();
// If we can't use SDFT, then make a simple choice between direct or path.
if (!fAbleToUseSDFT || paint.getMaskFilter() || paint.getStyle() != SkPaint::kFill_Style) {
const int kAboveIsPath = std::min(SkGraphics::GetFontCachePointSizeLimit(),
(int)SkStrikeCommon::kSkSideTooBigForAtlas);
return scaledTextSize < kAboveIsPath ? kDirect : kPath;
}
if (viewMatrix.hasPerspective()) {
// Don't use SDF for perspective. Paths look better.
return false;
} else {
SkScalar maxScale = viewMatrix.getMaxScale();
SkScalar scaledTextSize = maxScale * font.getSize();
// Hinted text looks far better at small resolutions
// Scaling up beyond 2x yields undesirable artifacts
if (scaledTextSize < fMinDistanceFieldFontSize ||
scaledTextSize > fMaxDistanceFieldFontSize) {
return false;
}
bool useDFT = props.isUseDeviceIndependentFonts();
#if SK_FORCE_DISTANCE_FIELD_TEXT
useDFT = true;
#endif
if (!useDFT && scaledTextSize < kLargeDFFontSize) {
return false;
}
// Hinted text looks far better at small resolutions
// Scaling up beyond 2x yields undesirable artifacts
if (scaledTextSize < fMinDistanceFieldFontSize) {
return kDirect;
} else if (fMaxDistanceFieldFontSize < scaledTextSize) {
return kPath;
}
return true;
return kSDFT;
}
SkScalar scaled_text_size(const SkScalar textSize, const SkMatrix& viewMatrix) {

View File

@ -16,23 +16,33 @@ class SkSurfaceProps;
class GrSDFTOptions {
public:
GrSDFTOptions(SkScalar min, SkScalar max);
GrSDFTOptions(bool ableToUseSDFT, bool useSDFTForSmallText, SkScalar min, SkScalar max);
enum DrawingType {
kDirect,
kSDFT,
kPath
};
DrawingType drawingType(
const SkFont& font, const SkPaint& paint, const SkMatrix& viewMatrix) const;
bool canDrawAsDistanceFields(const SkPaint&, const SkFont&, const SkMatrix& viewMatrix,
const SkSurfaceProps& props,
bool contextSupportsDistanceFieldText) const;
SkFont getSDFFont(const SkFont& font,
const SkMatrix& viewMatrix,
SkScalar* textRatio) const;
std::pair<SkScalar, SkScalar> computeSDFMinMaxScale(
SkScalar textSize, const SkMatrix& viewMatrix) const;
private:
static SkScalar MinSDFTRange(bool useSDFTForSmallText, SkScalar min);
// Below this size (in device space) distance field text will not be used.
const SkScalar fMinDistanceFieldFontSize;
// Above this size (in device space) distance field text will not be used and glyphs will
// be rendered from outline as individual paths.
const SkScalar fMaxDistanceFieldFontSize;
const bool fAbleToUseSDFT;
};
#endif // GrSDFTOptions_DEFINED

View File

@ -1492,15 +1492,11 @@ void GrTextBlob::makeSubRuns(SkGlyphRunListPainter* painter,
const SkGlyphRunList& glyphRunList,
const SkMatrix& drawMatrix,
const SkPaint& runPaint,
const SkSurfaceProps& props,
bool contextSupportsDistanceFieldText,
const GrSDFTOptions& options) {
for (auto& glyphRun : glyphRunList) {
painter->processGlyphRun(glyphRun,
drawMatrix,
runPaint,
props,
contextSupportsDistanceFieldText,
options,
this);
}

View File

@ -404,8 +404,6 @@ public:
const SkGlyphRunList& glyphRunList,
const SkMatrix& drawMatrix,
const SkPaint& runPaint,
const SkSurfaceProps& props,
bool contextSupportsDistanceFieldText,
const GrSDFTOptions& options);
static const Key& GetKey(const GrTextBlob& blob);

View File

@ -683,10 +683,8 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, c
// A scale transform forces fallback to dft.
SkMatrix matrix = SkMatrix::Scale(16, 16);
SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
GrSDFTOptions options = direct->priv().asRecordingContext()->priv().SDFTOptions();
REPORTER_ASSERT(reporter,
options.canDrawAsDistanceFields(paint, font, matrix, surfaceProps, true));
GrSDFTOptions options = direct->priv().asRecordingContext()->priv().getSDFTOptions(true);
REPORTER_ASSERT(reporter, options.drawingType(font, paint, matrix) == GrSDFTOptions::kSDFT);
// Server.
auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());