aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--samplecode/SampleCCPRGeometry.cpp7
-rw-r--r--src/gpu/ccpr/GrCCGeometry.cpp115
-rw-r--r--src/gpu/ccpr/GrCCGeometry.h12
-rw-r--r--src/gpu/ccpr/GrCCPathParser.cpp5
4 files changed, 69 insertions, 70 deletions
diff --git a/samplecode/SampleCCPRGeometry.cpp b/samplecode/SampleCCPRGeometry.cpp
index 7ddf91f0ae..a6e408749a 100644
--- a/samplecode/SampleCCPRGeometry.cpp
+++ b/samplecode/SampleCCPRGeometry.cpp
@@ -245,7 +245,7 @@ void CCPRGeometryView::updateGpuData() {
fCubicType = GrPathUtils::getCubicKLM(fPoints, &fCubicKLM, t, s);
GrCCGeometry geometry;
geometry.beginContour(fPoints[0]);
- geometry.cubicTo(fPoints[1], fPoints[2], fPoints[3], kDebugBloat / 2, kDebugBloat / 2);
+ geometry.cubicTo(fPoints, kDebugBloat / 2, kDebugBloat / 2);
geometry.endContour();
int ptsIdx = 0;
for (GrCCGeometry::Verb verb : geometry.verbs()) {
@@ -265,9 +265,10 @@ void CCPRGeometryView::updateGpuData() {
}
}
} else if (PrimitiveType::kQuadratics == fPrimitiveType) {
+ SkPoint P3[3] = {fPoints[0], fPoints[1], fPoints[3]};
GrCCGeometry geometry;
- geometry.beginContour(fPoints[0]);
- geometry.quadraticTo(fPoints[1], fPoints[3]);
+ geometry.beginContour(P3[0]);
+ geometry.quadraticTo(P3);
geometry.endContour();
int ptsIdx = 0;
for (GrCCGeometry::Verb verb : geometry.verbs()) {
diff --git a/src/gpu/ccpr/GrCCGeometry.cpp b/src/gpu/ccpr/GrCCGeometry.cpp
index 481f4e4725..c289c40453 100644
--- a/src/gpu/ccpr/GrCCGeometry.cpp
+++ b/src/gpu/ccpr/GrCCGeometry.cpp
@@ -23,26 +23,27 @@ void GrCCGeometry::beginPath() {
fVerbs.push_back(Verb::kBeginPath);
}
-void GrCCGeometry::beginContour(const SkPoint& devPt) {
+void GrCCGeometry::beginContour(const SkPoint& pt) {
SkASSERT(!fBuildingContour);
-
- fCurrFanPoint = fCurrAnchorPoint = devPt;
-
// Store the current verb count in the fTriangles field for now. When we close the contour we
// will use this value to calculate the actual number of triangles in its fan.
fCurrContourTallies = {fVerbs.count(), 0, 0, 0};
- fPoints.push_back(devPt);
+ fPoints.push_back(pt);
fVerbs.push_back(Verb::kBeginContour);
+ fCurrAnchorPoint = pt;
SkDEBUGCODE(fBuildingContour = true);
}
-void GrCCGeometry::lineTo(const SkPoint& devPt) {
+void GrCCGeometry::lineTo(const SkPoint& pt) {
SkASSERT(fBuildingContour);
- SkASSERT(fCurrFanPoint == fPoints.back());
- fCurrFanPoint = devPt;
- fPoints.push_back(devPt);
+ fPoints.push_back(pt);
+ fVerbs.push_back(Verb::kLineTo);
+}
+
+void GrCCGeometry::appendLine(const Sk2f& endpt) {
+ endpt.store(&fPoints.push_back());
fVerbs.push_back(Verb::kLineTo);
}
@@ -74,11 +75,11 @@ static inline bool are_collinear(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2)
}
// 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) {
+static inline bool is_convex_curve_monotonic(const Sk2f& startPt, const Sk2f& tan0,
+ const Sk2f& endPt, const Sk2f& tan1) {
Sk2f v = endPt - startPt;
- float dot0 = dot(startTan, v);
- float dot1 = dot(endTan, v);
+ float dot0 = dot(tan0, v);
+ float dot1 = dot(tan1, v);
// A small, negative tolerance handles floating-point error in the case when one tangent
// approaches 0 length, meaning the (convex) curve segment is effectively a flat line.
@@ -90,14 +91,19 @@ static inline Sk2f lerp(const Sk2f& a, const Sk2f& b, const Sk2f& t) {
return SkNx_fma(t, b - a, a);
}
-void GrCCGeometry::quadraticTo(const SkPoint& devP0, const SkPoint& devP1) {
+void GrCCGeometry::quadraticTo(const SkPoint P[3]) {
SkASSERT(fBuildingContour);
- SkASSERT(fCurrFanPoint == fPoints.back());
+ SkASSERT(P[0] == fPoints.back());
+ Sk2f p0 = Sk2f::Load(P);
+ Sk2f p1 = Sk2f::Load(P+1);
+ Sk2f p2 = Sk2f::Load(P+2);
- Sk2f p0 = Sk2f::Load(&fCurrFanPoint);
- Sk2f p1 = Sk2f::Load(&devP0);
- Sk2f p2 = Sk2f::Load(&devP1);
- fCurrFanPoint = devP1;
+ // Don't crunch on the curve if it is nearly flat (or just very small). Flat curves can break
+ // The monotonic chopping math.
+ if (are_collinear(p0, p1, p2)) {
+ this->appendLine(p2);
+ return;
+ }
this->appendMonotonicQuadratics(p0, p1, p2);
}
@@ -114,10 +120,10 @@ inline void GrCCGeometry::appendMonotonicQuadratics(const Sk2f& p0, const Sk2f&
}
// Chop the curve into two segments with equal curvature. To do this we find the T value whose
- // tangent is perpendicular to the vector that bisects tan0 and -tan1.
+ // tangent angle is halfway between tan0 and tan1.
Sk2f n = normalize(tan0) - normalize(tan1);
- // This tangent can be found where (dQ(t) dot n) = 0:
+ // The midtangent can be found where (dQ(t) dot n) = 0:
//
// 0 = (dQ(t) dot n) = | 2*t 1 | * | p0 - 2*p1 + p2 | * | n |
// | -2*p0 + 2*p1 | | . |
@@ -147,8 +153,7 @@ inline void GrCCGeometry::appendSingleMonotonicQuadratic(const Sk2f& p0, const S
// Don't send curves to the GPU if we know they are nearly flat (or just very small).
if (are_collinear(p0, p1, p2)) {
- p2.store(&fPoints.push_back());
- fVerbs.push_back(Verb::kLineTo);
+ this->appendLine(p2);
return;
}
@@ -274,51 +279,47 @@ static inline Sk2f first_unless_nearly_zero(const Sk2f& a, const Sk2f& b) {
}
static inline bool is_cubic_nearly_quadratic(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2,
- const Sk2f& p3, Sk2f& tan0, Sk2f& tan3, Sk2f& c) {
+ const Sk2f& p3, Sk2f& tan0, Sk2f& tan1, Sk2f& c) {
tan0 = first_unless_nearly_zero(p1 - p0, p2 - p0);
- tan3 = first_unless_nearly_zero(p3 - p2, p3 - p1);
+ tan1 = first_unless_nearly_zero(p3 - p2, p3 - p1);
Sk2f c1 = SkNx_fma(Sk2f(1.5f), tan0, p0);
- Sk2f c2 = SkNx_fma(Sk2f(-1.5f), tan3, p3);
+ Sk2f c2 = SkNx_fma(Sk2f(-1.5f), tan1, p3);
c = (c1 + c2) * .5f; // Hopefully optimized out if not used?
return ((c1 - c2).abs() <= 1).allTrue();
}
-void GrCCGeometry::cubicTo(const SkPoint& devP1, const SkPoint& devP2, const SkPoint& devP3,
- float inflectPad, float loopIntersectPad) {
+void GrCCGeometry::cubicTo(const SkPoint P[4], float inflectPad, float loopIntersectPad) {
SkASSERT(fBuildingContour);
- SkASSERT(fCurrFanPoint == fPoints.back());
-
- SkPoint devPts[4] = {fCurrFanPoint, devP1, devP2, devP3};
- Sk2f p0 = Sk2f::Load(&fCurrFanPoint);
- Sk2f p1 = Sk2f::Load(&devP1);
- Sk2f p2 = Sk2f::Load(&devP2);
- Sk2f p3 = Sk2f::Load(&devP3);
- fCurrFanPoint = devP3;
-
- // Don't crunch on the curve and inflate geometry if it is nearly flat (or just very small).
+ SkASSERT(P[0] == fPoints.back());
+ Sk2f p0 = Sk2f::Load(P);
+ Sk2f p1 = Sk2f::Load(P+1);
+ Sk2f p2 = Sk2f::Load(P+2);
+ Sk2f p3 = Sk2f::Load(P+3);
+
+ // Don't crunch on the curve or inflate geometry if it is nearly flat (or just very small).
+ // Flat curves can break the math below.
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);
+ this->appendLine(p3);
return;
}
// Also detect near-quadratics ahead of time.
- Sk2f tan0, tan3, c;
- if (is_cubic_nearly_quadratic(p0, p1, p2, p3, tan0, tan3, c)) {
+ Sk2f tan0, tan1, c;
+ if (is_cubic_nearly_quadratic(p0, p1, p2, p3, tan0, tan1, c)) {
this->appendMonotonicQuadratics(p0, c, p3);
return;
}
double tt[2], ss[2];
- fCurrCubicType = SkClassifyCubic(devPts, tt, ss);
+ fCurrCubicType = SkClassifyCubic(P, tt, ss);
SkASSERT(!SkCubicIsDegenerate(fCurrCubicType)); // Should have been caught above.
SkMatrix CIT;
- ExcludedTerm skipTerm = GrPathUtils::calcCubicInverseTransposePowerBasisMatrix(devPts, &CIT);
+ ExcludedTerm skipTerm = GrPathUtils::calcCubicInverseTransposePowerBasisMatrix(P, &CIT);
SkASSERT(ExcludedTerm::kNonInvertible != skipTerm); // Should have been caught above.
SkASSERT(0 == CIT[6]);
SkASSERT(0 == CIT[7]);
@@ -460,9 +461,9 @@ void GrCCGeometry::cubicTo(const SkPoint& devP1, const SkPoint& devP2, const SkP
template<GrCCGeometry::AppendCubicFn AppendLeftRight>
inline void GrCCGeometry::chopCubicAtMidTangent(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2,
const Sk2f& p3, const Sk2f& tan0,
- const Sk2f& tan3, int maxFutureSubdivisions) {
- // Find the T value whose tangent is perpendicular to the vector that bisects tan0 and -tan3.
- Sk2f n = normalize(tan0) - normalize(tan3);
+ const Sk2f& tan1, int maxFutureSubdivisions) {
+ // Find the T value whose tangent is perpendicular to the vector that bisects tan0 and -tan1.
+ Sk2f n = normalize(tan0) - normalize(tan1);
float a = 3 * dot(p3 + (p1 - p2)*3 - p0, n);
float b = 6 * dot(p0 - p1*2 + p2, n);
@@ -515,11 +516,11 @@ void GrCCGeometry::appendMonotonicCubics(const Sk2f& p0, const Sk2f& p1, const S
if (maxSubdivisions) {
Sk2f tan0 = first_unless_nearly_zero(p1 - p0, p2 - p0);
- Sk2f tan3 = first_unless_nearly_zero(p3 - p2, p3 - p1);
+ Sk2f tan1 = first_unless_nearly_zero(p3 - p2, p3 - p1);
- if (!is_convex_curve_monotonic(p0, tan0, p3, tan3)) {
+ if (!is_convex_curve_monotonic(p0, tan0, p3, tan1)) {
this->chopCubicAtMidTangent<&GrCCGeometry::appendMonotonicCubics>(p0, p1, p2, p3,
- tan0, tan3,
+ tan0, tan1,
maxSubdivisions - 1);
return;
}
@@ -530,8 +531,7 @@ void GrCCGeometry::appendMonotonicCubics(const Sk2f& p0, const Sk2f& p1, const S
// Don't send curves to the GPU if we know they are nearly flat (or just very small).
// Since the cubic segment is known to be convex at this point, our flatness check is simple.
if (are_collinear(p0, (p1 + p2) * .5f, p3)) {
- p3.store(&fPoints.push_back());
- fVerbs.push_back(Verb::kLineTo);
+ this->appendLine(p3);
return;
}
@@ -554,15 +554,14 @@ void GrCCGeometry::appendCubicApproximation(const Sk2f& p0, const Sk2f& p1, cons
// This can cause some curves to feel slightly more flat when inspected rigorously back and
// forth against another renderer, but for now this seems acceptable given the simplicity.
SkASSERT(fPoints.back() == SkPoint::Make(p0[0], p0[1]));
- p3.store(&fPoints.push_back());
- fVerbs.push_back(Verb::kLineTo);
+ this->appendLine(p3);
return;
}
- Sk2f tan0, tan3, c;
- if (!is_cubic_nearly_quadratic(p0, p1, p2, p3, tan0, tan3, c) && maxSubdivisions) {
+ Sk2f tan0, tan1, c;
+ if (!is_cubic_nearly_quadratic(p0, p1, p2, p3, tan0, tan1, c) && maxSubdivisions) {
this->chopCubicAtMidTangent<&GrCCGeometry::appendCubicApproximation>(p0, p1, p2, p3,
- tan0, tan3,
+ tan0, tan1,
maxSubdivisions - 1);
return;
}
@@ -581,7 +580,7 @@ GrCCGeometry::PrimitiveTallies GrCCGeometry::endContour() {
// The fTriangles field currently contains this contour's starting verb index. We can now
// use it to calculate the size of the contour's fan.
int fanSize = fVerbs.count() - fCurrContourTallies.fTriangles;
- if (fCurrFanPoint == fCurrAnchorPoint) {
+ if (fPoints.back() == fCurrAnchorPoint) {
--fanSize;
fVerbs.push_back(Verb::kEndClosedContour);
} else {
diff --git a/src/gpu/ccpr/GrCCGeometry.h b/src/gpu/ccpr/GrCCGeometry.h
index f593744b70..01cf16c68d 100644
--- a/src/gpu/ccpr/GrCCGeometry.h
+++ b/src/gpu/ccpr/GrCCGeometry.h
@@ -72,9 +72,9 @@ public:
}
void beginPath();
- void beginContour(const SkPoint& devPt);
- void lineTo(const SkPoint& devPt);
- void quadraticTo(const SkPoint& devP1, const SkPoint& devP2);
+ void beginContour(const SkPoint&);
+ void lineTo(const SkPoint&);
+ void quadraticTo(const SkPoint[3]);
// We pass through inflection points and loop intersections using a line and quadratic(s)
// respectively. 'inflectPad' and 'loopIntersectPad' specify how close (in pixels) cubic
@@ -87,12 +87,13 @@ public:
// through the loop intersection can be approximated with a single quadratic anyway,
// regardless of whether we are use one pixel of pad or two (1.622 avg. quads per loop
// intersection vs. 1.489 on the tiger).
- void cubicTo(const SkPoint& devP1, const SkPoint& devP2, const SkPoint& devP3,
- float inflectPad = 0.55f, float loopIntersectPad = 2);
+ void cubicTo(const SkPoint[4], float inflectPad = 0.55f, float loopIntersectPad = 2);
PrimitiveTallies endContour(); // Returns the numbers of primitives needed to draw the contour.
private:
+ inline void appendLine(const Sk2f& endpt);
+
inline void appendMonotonicQuadratics(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2);
inline void appendSingleMonotonicQuadratic(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2);
@@ -117,7 +118,6 @@ private:
// Transient state used while building a contour.
SkPoint fCurrAnchorPoint;
- SkPoint fCurrFanPoint;
PrimitiveTallies fCurrContourTallies;
SkCubicType fCurrCubicType;
SkDEBUGCODE(bool fBuildingContour = false);
diff --git a/src/gpu/ccpr/GrCCPathParser.cpp b/src/gpu/ccpr/GrCCPathParser.cpp
index 506efc752f..f77c52e6f1 100644
--- a/src/gpu/ccpr/GrCCPathParser.cpp
+++ b/src/gpu/ccpr/GrCCPathParser.cpp
@@ -134,12 +134,11 @@ void GrCCPathParser::parsePath(const SkPath& path, const SkPoint* deviceSpacePts
++ptsIdx;
continue;
case SkPath::kQuad_Verb:
- fGeometry.quadraticTo(deviceSpacePts[ptsIdx], deviceSpacePts[ptsIdx + 1]);
+ fGeometry.quadraticTo(&deviceSpacePts[ptsIdx - 1]);
ptsIdx += 2;
continue;
case SkPath::kCubic_Verb:
- fGeometry.cubicTo(deviceSpacePts[ptsIdx], deviceSpacePts[ptsIdx + 1],
- deviceSpacePts[ptsIdx + 2]);
+ fGeometry.cubicTo(&deviceSpacePts[ptsIdx - 1]);
ptsIdx += 3;
continue;
case SkPath::kConic_Verb: