From 43146e977ff386f7ef756ad9e74215d0a986c23b Mon Sep 17 00:00:00 2001 From: Michael Ludwig Date: Sat, 12 Feb 2022 15:02:22 -0500 Subject: [PATCH] Pass squared tolerances into GrPathUtils::generateXPoints() The GrPathUtils::quadPointCount and cubicPointCount functions take a tolerance value. The paired generateQuad/CubicPoints functions that will fill up-to the returned point count from those first questions actually takes the square of the tolerance value. This was noticed in https://fiddle.skia.org/c/7e42210ddb6675fe8729c0ba5b07daf5 as the subtle linear artifacts around the rounded corners of the stroke. GrAAConvexTessellator was not passing in the square value, so the point generation would early-out sooner than it should have in this example. Instead of using 16 vertices it used 8. Passing in the square fixes the linear artifacts when testing locally. I did an audit of other usages of these functions and SkShadowUtils also needed to be updated. As part of this, I switched the constants over to constexpr. The only other user of this function, default path renderer, did not need to be updated. Change-Id: I5e0acb8ebc8b4209f7924ca1e1674d1759da0d3e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/507926 Reviewed-by: Brian Osman Commit-Queue: Michael Ludwig Auto-Submit: Michael Ludwig --- src/gpu/geometry/GrAAConvexTessellator.cpp | 20 +++++++++++--------- src/utils/SkShadowTessellator.cpp | 12 +++++++----- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/gpu/geometry/GrAAConvexTessellator.cpp b/src/gpu/geometry/GrAAConvexTessellator.cpp index 7d89f36331..c561769c5a 100644 --- a/src/gpu/geometry/GrAAConvexTessellator.cpp +++ b/src/gpu/geometry/GrAAConvexTessellator.cpp @@ -20,19 +20,21 @@ // test more degenerate cases // The tolerance for fusing vertices and eliminating colinear lines (It is in device space). -static const SkScalar kClose = (SK_Scalar1 / 16); -static const SkScalar kCloseSqd = kClose * kClose; +static constexpr SkScalar kClose = (SK_Scalar1 / 16); +static constexpr SkScalar kCloseSqd = kClose * kClose; // tesselation tolerance values, in device space pixels -static const SkScalar kQuadTolerance = 0.2f; -static const SkScalar kCubicTolerance = 0.2f; -static const SkScalar kConicTolerance = 0.25f; +static constexpr SkScalar kQuadTolerance = 0.2f; +static constexpr SkScalar kCubicTolerance = 0.2f; +static constexpr SkScalar kQuadToleranceSqd = kQuadTolerance * kQuadTolerance; +static constexpr SkScalar kCubicToleranceSqd = kCubicTolerance * kCubicTolerance; +static constexpr SkScalar kConicTolerance = 0.25f; // dot product below which we use a round cap between curve segments -static const SkScalar kRoundCapThreshold = 0.8f; +static constexpr SkScalar kRoundCapThreshold = 0.8f; // dot product above which we consider two adjacent curves to be part of the "same" curve -static const SkScalar kCurveConnectionThreshold = 0.8f; +static constexpr SkScalar kCurveConnectionThreshold = 0.8f; static bool intersect(const SkPoint& p0, const SkPoint& n0, const SkPoint& p1, const SkPoint& n1, @@ -964,7 +966,7 @@ void GrAAConvexTessellator::quadTo(const SkPoint pts[3]) { fPointBuffer.setCount(maxCount); SkPoint* target = fPointBuffer.begin(); int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2], - kQuadTolerance, &target, maxCount); + kQuadToleranceSqd, &target, maxCount); fPointBuffer.setCount(count); for (int i = 0; i < count - 1; i++) { this->lineTo(fPointBuffer[i], kCurve_CurveState); @@ -985,7 +987,7 @@ void GrAAConvexTessellator::cubicTo(const SkMatrix& m, const SkPoint srcPts[4]) fPointBuffer.setCount(maxCount); SkPoint* target = fPointBuffer.begin(); int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3], - kCubicTolerance, &target, maxCount); + kCubicToleranceSqd, &target, maxCount); fPointBuffer.setCount(count); for (int i = 0; i < count - 1; i++) { this->lineTo(fPointBuffer[i], kCurve_CurveState); diff --git a/src/utils/SkShadowTessellator.cpp b/src/utils/SkShadowTessellator.cpp index 843712f727..e0bbc02db9 100644 --- a/src/utils/SkShadowTessellator.cpp +++ b/src/utils/SkShadowTessellator.cpp @@ -726,10 +726,12 @@ void SkBaseShadowTessellator::stitchConcaveRings(const SkTDArray& umbra // tesselation tolerance values, in device space pixels #if SK_SUPPORT_GPU -static const SkScalar kQuadTolerance = 0.2f; -static const SkScalar kCubicTolerance = 0.2f; +static constexpr SkScalar kQuadTolerance = 0.2f; +static constexpr SkScalar kCubicTolerance = 0.2f; +static constexpr SkScalar kQuadToleranceSqd = kQuadTolerance * kQuadTolerance; +static constexpr SkScalar kCubicToleranceSqd = kCubicTolerance * kCubicTolerance; #endif -static const SkScalar kConicTolerance = 0.25f; +static constexpr SkScalar kConicTolerance = 0.25f; // clamps the point to the nearest 16th of a pixel static void sanitize_point(const SkPoint& in, SkPoint* out) { @@ -783,7 +785,7 @@ void SkBaseShadowTessellator::handleQuad(const SkPoint pts[3]) { fPointBuffer.setCount(maxCount); SkPoint* target = fPointBuffer.begin(); int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2], - kQuadTolerance, &target, maxCount); + kQuadToleranceSqd, &target, maxCount); fPointBuffer.setCount(count); for (int i = 0; i < count; i++) { this->handleLine(fPointBuffer[i]); @@ -808,7 +810,7 @@ void SkBaseShadowTessellator::handleCubic(const SkMatrix& m, SkPoint pts[4]) { fPointBuffer.setCount(maxCount); SkPoint* target = fPointBuffer.begin(); int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3], - kCubicTolerance, &target, maxCount); + kCubicToleranceSqd, &target, maxCount); fPointBuffer.setCount(count); for (int i = 0; i < count; i++) { this->handleLine(fPointBuffer[i]);