Have Renderer use combined path code - v2
Currently, the GPU code uses the unified code path in painter to draw. Have the remote glyph cache use it too. Moved a function out of the GPU flag. Change-Id: I1d0bfc7edff0fd8731ea6cbf0b5b05aad537c3c6 Reviewed-on: https://skia-review.googlesource.com/157760 Reviewed-by: Mike Klein <mtklein@google.com> Commit-Queue: Herb Derby <herb@google.com>
This commit is contained in:
parent
41576877bd
commit
d9e732185e
@ -248,6 +248,91 @@ void SkGlyphRunListPainter::drawUsingMasks(
|
||||
}
|
||||
}
|
||||
|
||||
// Getting glyphs to the screen in a fallback situation can be complex. Here is the set of
|
||||
// transformations that have to happen. Normally, they would all be accommodated by the font
|
||||
// scaler, but the atlas has an upper limit to the glyphs it can handle. So the GPU is used to
|
||||
// make up the difference from the smaller atlas size to the larger size needed by the final
|
||||
// transform. Here are the transformations that are applied.
|
||||
//
|
||||
// final transform = [view matrix] * [text scale] * [text size]
|
||||
//
|
||||
// There are three cases:
|
||||
// * Go Fast - view matrix is scale and translate, and all the glyphs are small enough
|
||||
// Just scale the positions, and have the glyph cache handle the view matrix transformation.
|
||||
// The text scale is 1.
|
||||
// * It's complicated - view matrix is not scale and translate, and the glyphs are small enough
|
||||
// The glyph cache does not handle the view matrix, but stores the glyphs at the text size
|
||||
// specified by the run paint. The GPU handles the rotation, etc. specified by the view matrix.
|
||||
// The text scale is 1.
|
||||
// * Too big - The glyphs are too big to fit in the atlas
|
||||
// Reduce the text size so the glyphs will fit in the atlas, but don't apply any
|
||||
// transformations from the view matrix. Calculate a text scale based on that reduction. This
|
||||
// scale factor is used to increase the size of the destination rectangles. The destination
|
||||
// rectangles are then scaled, rotated, etc. by the GPU using the view matrix.
|
||||
void SkGlyphRunListPainter::processARGBFallback(
|
||||
SkScalar maxGlyphDimension, const SkPaint& runPaint, SkPoint origin,
|
||||
const SkMatrix& viewMatrix, SkScalar textScale, ARGBFallback argbFallback) {
|
||||
SkASSERT(!fARGBGlyphsIDs.empty());
|
||||
|
||||
SkScalar maxScale = viewMatrix.getMaxScale();
|
||||
|
||||
// This is a conservative estimate of the longest dimension among all the glyph widths and
|
||||
// heights.
|
||||
SkScalar conservativeMaxGlyphDimension = maxGlyphDimension * textScale * maxScale;
|
||||
|
||||
// If the situation that the matrix is simple, and all the glyphs are small enough. Go fast!
|
||||
bool useFastPath =
|
||||
viewMatrix.isScaleTranslate() && conservativeMaxGlyphDimension <= maxGlyphDimension;
|
||||
|
||||
auto glyphIDs = SkSpan<const SkGlyphID>{fARGBGlyphsIDs};
|
||||
|
||||
// A scaled and translated transform is the common case, and is handled directly in fallback.
|
||||
// Even if the transform is scale and translate, fallback must be careful to use glyphs that
|
||||
// fit in the atlas. If a glyph will not fit in the atlas, then the general transform case is
|
||||
// used to render the glyphs.
|
||||
if (useFastPath) {
|
||||
// Translate the positions to device space.
|
||||
viewMatrix.mapPoints(fARGBPositions.data(), fARGBPositions.size());
|
||||
for (SkPoint& point : fARGBPositions) {
|
||||
point.fX = SkScalarFloorToScalar(point.fX);
|
||||
point.fY = SkScalarFloorToScalar(point.fY);
|
||||
}
|
||||
|
||||
auto positions = SkSpan<const SkPoint>{fARGBPositions};
|
||||
argbFallback(runPaint, glyphIDs, positions, SK_Scalar1, viewMatrix, kTransformDone);
|
||||
|
||||
} else {
|
||||
// If the matrix is complicated or if scaling is used to fit the glyphs in the cache,
|
||||
// then this case is used.
|
||||
|
||||
// Subtract 2 to account for the bilerp pad around the glyph
|
||||
SkScalar maxAtlasDimension = SkGlyphCacheCommon::kSkSideTooBigForAtlas - 2;
|
||||
|
||||
SkScalar runPaintTextSize = runPaint.getTextSize();
|
||||
|
||||
// Scale the text size down so the long side of all the glyphs will fit in the atlas.
|
||||
SkScalar reducedTextSize =
|
||||
(maxAtlasDimension / conservativeMaxGlyphDimension) * runPaintTextSize;
|
||||
|
||||
// If there's a glyph in the font that's particularly large, it's possible
|
||||
// that fScaledFallbackTextSize may end up minimizing too much. We'd rather skip
|
||||
// that glyph than make the others blurry, so we set a minimum size of half the
|
||||
// maximum text size to avoid this case.
|
||||
SkScalar fallbackTextSize =
|
||||
SkScalarFloorToScalar(std::max(reducedTextSize, 0.5f * runPaintTextSize));
|
||||
|
||||
// Don't allow the text size to get too big. This will also improve glyph cache hit rate
|
||||
// for larger text sizes.
|
||||
fallbackTextSize = std::min(fallbackTextSize, 256.0f);
|
||||
|
||||
SkPaint fallbackPaint{runPaint};
|
||||
fallbackPaint.setTextSize(fallbackTextSize);
|
||||
SkScalar fallbackTextScale = runPaintTextSize / fallbackTextSize;
|
||||
auto positions = SkSpan<const SkPoint>{fARGBPositions};
|
||||
argbFallback(
|
||||
fallbackPaint, glyphIDs, positions, fallbackTextScale, SkMatrix::I(), kDoTransform);
|
||||
}
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
@ -413,92 +498,6 @@ void GrTextContext::AppendGlyph(GrTextBlob* blob, int runIndex,
|
||||
}
|
||||
}
|
||||
|
||||
// Getting glyphs to the screen in a fallback situation can be complex. Here is the set of
|
||||
// transformations that have to happen. Normally, they would all be accommodated by the font
|
||||
// scaler, but the atlas has an upper limit to the glyphs it can handle. So the GPU is used to
|
||||
// make up the difference from the smaller atlas size to the larger size needed by the final
|
||||
// transform. Here are the transformations that are applied.
|
||||
//
|
||||
// final transform = [view matrix] * [text scale] * [text size]
|
||||
//
|
||||
// There are three cases:
|
||||
// * Go Fast - view matrix is scale and translate, and all the glyphs are small enough
|
||||
// Just scale the positions, and have the glyph cache handle the view matrix transformation.
|
||||
// The text scale is 1.
|
||||
// * It's complicated - view matrix is not scale and translate, and the glyphs are small enough
|
||||
// The glyph cache does not handle the view matrix, but stores the glyphs at the text size
|
||||
// specified by the run paint. The GPU handles the rotation, etc. specified by the view matrix.
|
||||
// The text scale is 1.
|
||||
// * Too big - The glyphs are too big to fit in the atlas
|
||||
// Reduce the text size so the glyphs will fit in the atlas, but don't apply any
|
||||
// transformations from the view matrix. Calculate a text scale based on that reduction. This
|
||||
// scale factor is used to increase the size of the destination rectangles. The destination
|
||||
// rectangles are then scaled, rotated, etc. by the GPU using the view matrix.
|
||||
|
||||
void SkGlyphRunListPainter::processARGBFallback(
|
||||
SkScalar maxGlyphDimension, const SkPaint& runPaint, SkPoint origin,
|
||||
const SkMatrix& viewMatrix, SkScalar textScale, ARGBFallback argbFallback) {
|
||||
SkASSERT(!fARGBGlyphsIDs.empty());
|
||||
|
||||
SkScalar maxScale = viewMatrix.getMaxScale();
|
||||
|
||||
// This is a conservative estimate of the longest dimension among all the glyph widths and
|
||||
// heights.
|
||||
SkScalar conservativeMaxGlyphDimension = maxGlyphDimension * textScale * maxScale;
|
||||
|
||||
// If the situation that the matrix is simple, and all the glyphs are small enough. Go fast!
|
||||
bool useFastPath =
|
||||
viewMatrix.isScaleTranslate() && conservativeMaxGlyphDimension <= maxGlyphDimension;
|
||||
|
||||
auto glyphIDs = SkSpan<const SkGlyphID>{fARGBGlyphsIDs};
|
||||
|
||||
// A scaled and translated transform is the common case, and is handled directly in fallback.
|
||||
// Even if the transform is scale and translate, fallback must be careful to use glyphs that
|
||||
// fit in the atlas. If a glyph will not fit in the atlas, then the general transform case is
|
||||
// used to render the glyphs.
|
||||
if (useFastPath) {
|
||||
// Translate the positions to device space.
|
||||
viewMatrix.mapPoints(fARGBPositions.data(), fARGBPositions.size());
|
||||
for (SkPoint& point : fARGBPositions) {
|
||||
point.fX = SkScalarFloorToScalar(point.fX);
|
||||
point.fY = SkScalarFloorToScalar(point.fY);
|
||||
}
|
||||
|
||||
auto positions = SkSpan<const SkPoint>{fARGBPositions};
|
||||
argbFallback(runPaint, glyphIDs, positions, SK_Scalar1, viewMatrix, kTransformDone);
|
||||
|
||||
} else {
|
||||
// If the matrix is complicated or if scaling is used to fit the glyphs in the cache,
|
||||
// then this case is used.
|
||||
|
||||
// Subtract 2 to account for the bilerp pad around the glyph
|
||||
SkScalar maxAtlasDimension = SkGlyphCacheCommon::kSkSideTooBigForAtlas - 2;
|
||||
|
||||
SkScalar runPaintTextSize = runPaint.getTextSize();
|
||||
|
||||
// Scale the text size down so the long side of all the glyphs will fit in the atlas.
|
||||
SkScalar reducedTextSize =
|
||||
(maxAtlasDimension / conservativeMaxGlyphDimension) * runPaintTextSize;
|
||||
|
||||
// If there's a glyph in the font that's particularly large, it's possible
|
||||
// that fScaledFallbackTextSize may end up minimizing too much. We'd rather skip
|
||||
// that glyph than make the others blurry, so we set a minimum size of half the
|
||||
// maximum text size to avoid this case.
|
||||
SkScalar fallbackTextSize =
|
||||
SkScalarFloorToScalar(std::max(reducedTextSize, 0.5f * runPaintTextSize));
|
||||
|
||||
// Don't allow the text size to get too big. This will also improve glyph cache hit rate
|
||||
// for larger text sizes.
|
||||
fallbackTextSize = std::min(fallbackTextSize, 256.0f);
|
||||
|
||||
SkPaint fallbackPaint{runPaint};
|
||||
fallbackPaint.setTextSize(fallbackTextSize);
|
||||
SkScalar fallbackTextScale = runPaintTextSize / fallbackTextSize;
|
||||
auto positions = SkSpan<const SkPoint>{fARGBPositions};
|
||||
argbFallback(
|
||||
fallbackPaint, glyphIDs, positions, fallbackTextScale, SkMatrix::I(), kDoTransform);
|
||||
}
|
||||
}
|
||||
|
||||
void GrTextContext::regenerateGlyphRunList(GrTextBlob* cacheBlob,
|
||||
GrGlyphCache* glyphCache,
|
||||
@ -595,10 +594,12 @@ void GrTextContext::regenerateGlyphRunList(GrTextBlob* cacheBlob,
|
||||
// Given a glyph that is not ARGB, draw it.
|
||||
auto perPath = [textScale, runIndex, cacheBlob, &pathCache]
|
||||
(const SkGlyph& glyph, SkPoint position) {
|
||||
const SkPath* path = pathCache->findPath(glyph);
|
||||
if (path != nullptr) {
|
||||
cacheBlob->appendPathGlyph(
|
||||
runIndex, *path, position.fX, position.fY, textScale, false);
|
||||
if (!glyph.isEmpty()) {
|
||||
const SkPath* path = pathCache->findPath(glyph);
|
||||
if (path != nullptr) {
|
||||
cacheBlob->appendPathGlyph(
|
||||
runIndex, *path, position.fX, position.fY, textScale, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -175,15 +175,13 @@ void SkGlyphRunListPainter::drawGlyphRunAsPathWithARGBFallback(
|
||||
(SkGlyphID glyphID, SkPoint position) {
|
||||
if (SkScalarsAreFinite(position.x(), position.y())) {
|
||||
const SkGlyph& glyph = pathCache->getGlyphMetrics(glyphID, {0, 0});
|
||||
if (!glyph.isEmpty()) {
|
||||
if (glyph.fMaskFormat != SkMask::kARGB32_Format) {
|
||||
perPath(glyph, origin + position);
|
||||
} else {
|
||||
SkScalar largestDimension = std::max(glyph.fWidth, glyph.fHeight);
|
||||
maxFallbackDimension = std::max(maxFallbackDimension, largestDimension);
|
||||
fARGBGlyphsIDs.push_back(glyphID);
|
||||
fARGBPositions.push_back(position);
|
||||
}
|
||||
if (glyph.fMaskFormat != SkMask::kARGB32_Format) {
|
||||
perPath(glyph, origin + position);
|
||||
} else {
|
||||
SkScalar largestDimension = std::max(glyph.fWidth, glyph.fHeight);
|
||||
maxFallbackDimension = std::max(maxFallbackDimension, largestDimension);
|
||||
fARGBGlyphsIDs.push_back(glyphID);
|
||||
fARGBPositions.push_back(position);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -182,7 +182,6 @@ bool read_path(Deserializer* deserializer, SkGlyph* glyph, SkGlyphCache* cache)
|
||||
return cache->initializePath(glyph, path, pathSize);
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
void add_glyph_to_cache(SkStrikeServer::SkGlyphCacheState* cache, SkTypeface* tf,
|
||||
const SkScalerContextEffects& effects, SkGlyphID glyphID) {
|
||||
SkASSERT(cache != nullptr);
|
||||
@ -190,6 +189,7 @@ void add_glyph_to_cache(SkStrikeServer::SkGlyphCacheState* cache, SkTypeface* tf
|
||||
cache->addGlyph(SkPackedGlyphID(glyphID, 0, 0), false);
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
void add_fallback_text_to_cache(const GrTextContext::FallbackGlyphRunHelper& helper,
|
||||
const SkSurfaceProps& props,
|
||||
const SkMatrix& matrix,
|
||||
@ -272,7 +272,7 @@ void SkTextBlobCacheDiffCanvas::TrackLayerDevice::processGlyphRun(
|
||||
} else
|
||||
#endif
|
||||
if (SkDraw::ShouldDrawTextAsPaths(runPaint, runMatrix)) {
|
||||
this->processGlyphRunForPaths(glyphRun, runMatrix);
|
||||
this->processGlyphRunForPaths(glyphRun, runMatrix, origin);
|
||||
} else {
|
||||
this->processGlyphRunForMask(glyphRun, runMatrix, origin);
|
||||
}
|
||||
@ -306,43 +306,44 @@ void SkTextBlobCacheDiffCanvas::TrackLayerDevice::processGlyphRunForMask(
|
||||
}
|
||||
|
||||
void SkTextBlobCacheDiffCanvas::TrackLayerDevice::processGlyphRunForPaths(
|
||||
const SkGlyphRun& glyphRun, const SkMatrix& runMatrix) {
|
||||
const SkGlyphRun& glyphRun, const SkMatrix& runMatrix, SkPoint origin) {
|
||||
TRACE_EVENT0("skia", "SkTextBlobCacheDiffCanvas::processGlyphRunForPaths");
|
||||
const SkPaint& runPaint = glyphRun.paint();
|
||||
SkPaint pathPaint{runPaint};
|
||||
|
||||
// The code below borrowed from GrTextContext::DrawBmpPosTextAsPaths.
|
||||
SkPaint pathPaint(runPaint);
|
||||
#if SK_SUPPORT_GPU
|
||||
SkScalar matrixScale = pathPaint.setupForAsPaths();
|
||||
GrTextContext::FallbackGlyphRunHelper fallbackTextHelper(runMatrix, runPaint, matrixScale);
|
||||
#else
|
||||
pathPaint.setupForAsPaths();
|
||||
#endif
|
||||
SkScalar textScale = pathPaint.setupForAsPaths();
|
||||
|
||||
SkScalerContextEffects effects;
|
||||
auto* glyphCacheState = fStrikeServer->getOrCreateCache(
|
||||
pathPaint, this->surfaceProps(), SkMatrix::I(),
|
||||
SkScalerContextFlags::kFakeGammaAndBoostContrast, &effects);
|
||||
|
||||
const bool asPath = true;
|
||||
auto glyphs = glyphRun.shuntGlyphsIDs();
|
||||
for (uint32_t index = 0; index < glyphRun.runSize(); index++) {
|
||||
auto glyphID = glyphs[index];
|
||||
#if SK_SUPPORT_GPU
|
||||
const auto& glyph = glyphCacheState->findGlyph(glyphID);
|
||||
if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
|
||||
// Note that we send data for the original glyph even in the case of fallback
|
||||
// since its glyph metrics will still be used on the client.
|
||||
fallbackTextHelper.appendGlyph(glyph, glyphID, {0, 0});
|
||||
}
|
||||
#endif
|
||||
glyphCacheState->addGlyph(glyphID, asPath);
|
||||
}
|
||||
auto perPath = [glyphCacheState](const SkGlyph& glyph, SkPoint position) {
|
||||
const bool asPath = true;
|
||||
glyphCacheState->addGlyph(glyph.getGlyphID(), asPath);
|
||||
};
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
add_fallback_text_to_cache(fallbackTextHelper, this->surfaceProps(), runMatrix, runPaint,
|
||||
fStrikeServer);
|
||||
#endif
|
||||
auto argbFallback = [this, &runMatrix]
|
||||
(const SkPaint& fallbackPaint, SkSpan<const SkGlyphID> glyphIDs,
|
||||
SkSpan<const SkPoint> positions, SkScalar textScale,
|
||||
const SkMatrix& glyphCacheMatrix,
|
||||
SkGlyphRunListPainter::NeedsTransform needsTransform) {
|
||||
TRACE_EVENT0("skia", "argbFallback_path");
|
||||
SkMatrix fallbackMatrix = runMatrix;
|
||||
|
||||
SkScalerContextEffects effects;
|
||||
auto* glyphCacheState =
|
||||
fStrikeServer->getOrCreateCache(
|
||||
fallbackPaint, surfaceProps(), fallbackMatrix,
|
||||
SkScalerContextFlags::kFakeGammaAndBoostContrast, &effects);
|
||||
|
||||
for (auto glyphID : glyphIDs) {
|
||||
add_glyph_to_cache(glyphCacheState, fallbackPaint.getTypeface(), effects, glyphID);
|
||||
}
|
||||
};
|
||||
|
||||
fPainter.drawGlyphRunAsPathWithARGBFallback(
|
||||
glyphCacheState, glyphRun, origin, runMatrix, textScale, perPath, argbFallback);
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
@ -100,7 +100,8 @@ private:
|
||||
void processGlyphRunForMask(
|
||||
const SkGlyphRun& glyphRun, const SkMatrix& runMatrix, SkPoint origin);
|
||||
|
||||
void processGlyphRunForPaths(const SkGlyphRun& glyphRun, const SkMatrix& runMatrix);
|
||||
void processGlyphRunForPaths(
|
||||
const SkGlyphRun& glyphRun, const SkMatrix& runMatrix, SkPoint origin);
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
bool maybeProcessGlyphRunForDFT(const SkGlyphRun& glyphRun, const SkMatrix& runMatrix);
|
||||
|
Loading…
Reference in New Issue
Block a user