diff options
author | Chris Dalton <csmartdalton@google.com> | 2017-09-07 10:36:51 -0600 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-09-08 19:29:58 +0000 |
commit | 900cd05037739eac6fd7bb8611ac489bb5ad305e (patch) | |
tree | 97cb20fc9595abbabf028bf38d06f17f5da7faa8 /src/gpu/ccpr | |
parent | 6c251d24cf90a5c4c091bb7b7373e72705f716d2 (diff) |
CCPR: Check for flat lines before crunching on curves
Bug: skia:
Change-Id: Ib99f3f83aee4c261ef1cfc4e1045b2be3113e1ae
Reviewed-on: https://skia-review.googlesource.com/43100
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Diffstat (limited to 'src/gpu/ccpr')
-rw-r--r-- | src/gpu/ccpr/GrCCPRGeometry.cpp | 39 |
1 files changed, 37 insertions, 2 deletions
diff --git a/src/gpu/ccpr/GrCCPRGeometry.cpp b/src/gpu/ccpr/GrCCPRGeometry.cpp index 4ba4f54c63..54464080ad 100644 --- a/src/gpu/ccpr/GrCCPRGeometry.cpp +++ b/src/gpu/ccpr/GrCCPRGeometry.cpp @@ -40,6 +40,7 @@ void GrCCPRGeometry::beginContour(const SkPoint& devPt) { void GrCCPRGeometry::lineTo(const SkPoint& devPt) { SkASSERT(fBuildingContour); + SkASSERT(fCurrFanPoint == fPoints.back()); fCurrFanPoint = devPt; fPoints.push_back(devPt); fVerbs.push_back(Verb::kLineTo); @@ -56,6 +57,22 @@ static inline float dot(const Sk2f& a, const Sk2f& b) { return product[0] + product[1]; } +static inline bool are_collinear(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2) { + static constexpr float kFlatnessTolerance = 16; // 1/16 of a pixel. + + // Area (times 2) of the triangle. + Sk2f a = (p0 - p1) * SkNx_shuffle<1,0>(p1 - p2); + a = (a - SkNx_shuffle<1,0>(a)).abs(); + + // Bounding box of the triangle. + Sk2f bbox0 = Sk2f::Min(Sk2f::Min(p0, p1), p2); + Sk2f bbox1 = Sk2f::Max(Sk2f::Max(p0, p1), p2); + + // The triangle is linear if its area is within a fraction of the largest bounding box + // dimension, or else if its area is within a fraction of a pixel. + return (a * (kFlatnessTolerance/2) < Sk2f::Max(bbox1 - bbox0, 1)).anyTrue(); +} + // Returns whether the (convex) curve segment is monotonic with respect to [endPt - startPt]. static inline bool is_convex_curve_monotonic(const Sk2f& startPt, const Sk2f& startTan, const Sk2f& endPt, const Sk2f& endTan) { @@ -75,12 +92,20 @@ static inline Sk2f lerp(const Sk2f& a, const Sk2f& b, const Sk2f& t) { void GrCCPRGeometry::quadraticTo(const SkPoint& devP0, const SkPoint& devP1) { SkASSERT(fBuildingContour); + SkASSERT(fCurrFanPoint == fPoints.back()); Sk2f p0 = Sk2f::Load(&fCurrFanPoint); Sk2f p1 = Sk2f::Load(&devP0); Sk2f p2 = Sk2f::Load(&devP1); fCurrFanPoint = devP1; + // Don't send curves to the GPU if we know they are flat (or just very small). + if (are_collinear(p0, p1, p2)) { + p2.store(&fPoints.push_back()); + fVerbs.push_back(Verb::kLineTo); + return; + } + Sk2f tan0 = p1 - p0; Sk2f tan1 = p2 - p1; // This should almost always be this case for well-behaved curves in the real world. @@ -230,6 +255,7 @@ static inline void calc_loop_intersect_padding_pts(float padRadius, const Sk2f& void GrCCPRGeometry::cubicTo(const SkPoint& devP1, const SkPoint& devP2, const SkPoint& devP3, float inflectPad, float loopIntersectPad) { SkASSERT(fBuildingContour); + SkASSERT(fCurrFanPoint == fPoints.back()); SkPoint devPts[4] = {fCurrFanPoint, devP1, devP2, devP3}; Sk2f p0 = Sk2f::Load(&fCurrFanPoint); @@ -238,6 +264,15 @@ void GrCCPRGeometry::cubicTo(const SkPoint& devP1, const SkPoint& devP2, const S Sk2f p3 = Sk2f::Load(&devP3); fCurrFanPoint = devP3; + // Don't crunch on the curve and inflate geometry if it is already flat (or just very small). + if (are_collinear(p0, p1, p2) && + are_collinear(p1, p2, p3) && + are_collinear(p0, (p1 + p2) * .5f, p3)) { + p3.store(&fPoints.push_back()); + fVerbs.push_back(Verb::kLineTo); + return; + } + double tt[2], ss[2]; fCurrCubicType = SkClassifyCubic(devPts, tt, ss); if (SkCubicIsDegenerate(fCurrCubicType)) { @@ -251,8 +286,8 @@ void GrCCPRGeometry::cubicTo(const SkPoint& devP1, const SkPoint& devP2, const S if (ExcludedTerm::kNonInvertible == skipTerm) { // This could technically also happen if the curve were a quadratic, but SkClassifyCubic // should have detected that case already with tolerance. - fCurrCubicType = SkCubicType::kLineOrPoint; - this->appendCubicApproximation(p0, p1, p2, p3, /*maxSubdivisions=*/0); + p3.store(&fPoints.push_back()); + fVerbs.push_back(Verb::kLineTo); return; } SkASSERT(0 == CIT[6]); |