aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Chris Dalton <csmartdalton@google.com>2018-04-23 21:14:42 -0600
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-04-24 15:23:06 +0000
commit6f5e77a08faf9d967eba8194811cbf2391092c23 (patch)
tree577ea1030e16bd68c47eaa5cd3c494785c7204e6
parentb97f28b90399c2571712401a30b0299d37b4b52e (diff)
ccpr: Cull extremely thin triangles
When triangles get too thin it's possible for FP round-off error to actually give us the wrong winding direction, causing rendering artifacts. This change also allows us to unblacklist ANGLE. Bug: skia:7805 Bug: skia:7820 Change-Id: Ibaa0f033eba625d720e3a594c4515d8264cc413d Reviewed-on: https://skia-review.googlesource.com/123262 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Chris Dalton <csmartdalton@google.com>
-rw-r--r--bench/GrCCGeometryBench.cpp5
-rw-r--r--gm/mandoline.cpp202
-rw-r--r--gn/gm.gni1
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor.cpp30
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor.h10
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp24
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp14
-rw-r--r--src/gpu/ccpr/GrCCGeometry.cpp56
-rw-r--r--src/gpu/ccpr/GrCCGeometry.h4
-rw-r--r--src/gpu/ccpr/GrCCPathParser.cpp5
-rw-r--r--src/gpu/gl/GrGLCaps.cpp19
11 files changed, 295 insertions, 75 deletions
diff --git a/bench/GrCCGeometryBench.cpp b/bench/GrCCGeometryBench.cpp
index 5e47df042c..0628644ab9 100644
--- a/bench/GrCCGeometryBench.cpp
+++ b/bench/GrCCGeometryBench.cpp
@@ -22,6 +22,7 @@ public:
fPoints[1].set(x1, y1);
fPoints[2].set(x2, y2);
fPoints[3].set(x3, y3);
+ fPoints[4].set(x0, y0); // Flat closing edge.
fName = "ccprgeometry";
switch (SkClassifyCubic(fPoints)) {
@@ -52,7 +53,7 @@ public:
fGeometry.beginContour(fPoints[0]);
for (int i = 0; i < kNumBaseLoops; ++i) {
fGeometry.cubicTo(fPoints);
- fGeometry.lineTo(fPoints[0]);
+ fGeometry.lineTo(fPoints+3);
}
fGeometry.endContour();
fGeometry.reset();
@@ -60,7 +61,7 @@ public:
}
private:
- SkPoint fPoints[4];
+ SkPoint fPoints[5];
SkString fName;
GrCCGeometry fGeometry{4*100*kNumBaseLoops, 2*100*kNumBaseLoops};
diff --git a/gm/mandoline.cpp b/gm/mandoline.cpp
new file mode 100644
index 0000000000..17dd02f7e0
--- /dev/null
+++ b/gm/mandoline.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "sk_tool_utils.h"
+#include "SkPaint.h"
+#include "SkPath.h"
+#include "SkPoint.h"
+#include "SkGeometry.h"
+#include <math.h>
+
+namespace skiagm {
+
+// Slices paths into sliver-size contours shaped like ice cream cones.
+class MandolineSlicer {
+public:
+ static constexpr int kDefaultSubdivisions = 10;
+
+ MandolineSlicer(SkPoint anchorPt) {
+ fPath.setFillType(SkPath::kEvenOdd_FillType);
+ fPath.setIsVolatile(true);
+ this->reset(anchorPt);
+ }
+
+ void reset(SkPoint anchorPt) {
+ fPath.reset();
+ fLastPt = fAnchorPt = anchorPt;
+ }
+
+ void sliceLine(SkPoint pt, int numSubdivisions = kDefaultSubdivisions) {
+ if (numSubdivisions <= 0) {
+ fPath.moveTo(fAnchorPt);
+ fPath.lineTo(fLastPt);
+ fPath.lineTo(pt);
+ fPath.close();
+ fLastPt = pt;
+ return;
+ }
+ float T = this->chooseChopT(numSubdivisions);
+ if (0 == T) {
+ fPath.lineTo(fLastPt);
+ this->sliceLine(pt, numSubdivisions - 1);
+ return;
+ }
+ SkPoint midpt = fLastPt * (1 - T) + pt * T;
+ this->sliceLine(midpt, numSubdivisions - 1);
+ this->sliceLine(pt, numSubdivisions - 1);
+ }
+
+ void sliceQuadratic(SkPoint p1, SkPoint p2, int numSubdivisions = kDefaultSubdivisions) {
+ if (numSubdivisions <= 0) {
+ fPath.moveTo(fAnchorPt);
+ fPath.lineTo(fLastPt);
+ fPath.quadTo(p1, p2);
+ fPath.close();
+ fLastPt = p2;
+ return;
+ }
+ float T = this->chooseChopT(numSubdivisions);
+ if (0 == T) {
+ fPath.quadTo(fLastPt, fLastPt);
+ this->sliceQuadratic(p1, p2, numSubdivisions - 1);
+ return;
+ }
+ SkPoint P[3] = {fLastPt, p1, p2}, PP[5];
+ SkChopQuadAt(P, PP, T);
+ this->sliceQuadratic(PP[1], PP[2], numSubdivisions - 1);
+ this->sliceQuadratic(PP[3], PP[4], numSubdivisions - 1);
+ }
+
+ void sliceCubic(SkPoint p1, SkPoint p2, SkPoint p3,
+ int numSubdivisions = kDefaultSubdivisions) {
+ if (numSubdivisions <= 0) {
+ fPath.moveTo(fAnchorPt);
+ fPath.lineTo(fLastPt);
+ fPath.cubicTo(p1, p2, p3);
+ fPath.close();
+ fLastPt = p3;
+ return;
+ }
+ float T = this->chooseChopT(numSubdivisions);
+ if (0 == T) {
+ fPath.cubicTo(fLastPt, fLastPt, fLastPt);
+ this->sliceCubic(p1, p2, p3, numSubdivisions - 1);
+ return;
+ }
+ SkPoint P[4] = {fLastPt, p1, p2, p3}, PP[7];
+ SkChopCubicAt(P, PP, T);
+ this->sliceCubic(PP[1], PP[2], PP[3], numSubdivisions - 1);
+ this->sliceCubic(PP[4], PP[5], PP[6], numSubdivisions - 1);
+ }
+
+ void sliceConic(SkPoint p1, SkPoint p2, float w, int numSubdivisions = kDefaultSubdivisions) {
+ if (numSubdivisions <= 0) {
+ fPath.moveTo(fAnchorPt);
+ fPath.lineTo(fLastPt);
+ fPath.conicTo(p1, p2, w);
+ fPath.close();
+ fLastPt = p2;
+ return;
+ }
+ float T = this->chooseChopT(numSubdivisions);
+ if (0 == T) {
+ fPath.conicTo(fLastPt, fLastPt, w);
+ this->sliceConic(p1, p2, w, numSubdivisions - 1);
+ return;
+ }
+ SkConic conic(fLastPt, p1, p2, w), halves[2];
+ if (!conic.chopAt(T, halves)) {
+ SK_ABORT("SkConic::chopAt failed");
+ }
+ this->sliceConic(halves[0].fPts[1], halves[0].fPts[2], halves[0].fW, numSubdivisions - 1);
+ this->sliceConic(halves[1].fPts[1], halves[1].fPts[2], halves[1].fW, numSubdivisions - 1);
+ }
+
+ const SkPath& path() const { return fPath; }
+
+private:
+ float chooseChopT(int numSubdivisions) {
+ SkASSERT(numSubdivisions > 0);
+ if (numSubdivisions > 1) {
+ return .5f;
+ }
+ float T = (0 == fRand.nextU() % 10) ? 0 : scalbnf(1, -(int)fRand.nextRangeU(10, 149));
+ SkASSERT(T >= 0 && T < 1);
+ return T;
+ }
+
+ SkRandom fRand;
+ SkPath fPath;
+ SkPoint fAnchorPt;
+ SkPoint fLastPt;
+};
+
+class SliverPathsGM : public GM {
+public:
+ SliverPathsGM() {
+ this->setBGColor(sk_tool_utils::color_to_565(SK_ColorBLACK));
+ }
+
+protected:
+ SkString onShortName() override {
+ return SkString("mandoline");
+ }
+
+ SkISize onISize() override {
+ return SkISize::Make(560, 475);
+ }
+
+ void onDraw(SkCanvas* canvas) override {
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ paint.setAntiAlias(true);
+
+ MandolineSlicer mandoline({41, 43});
+ mandoline.sliceCubic({5, 277}, {381, -74}, {243, 162});
+ mandoline.sliceLine({41, 43});
+ canvas->drawPath(mandoline.path(), paint);
+
+ mandoline.reset({357.049988f, 446.049988f});
+ mandoline.sliceCubic({472.750000f, -71.950012f}, {639.750000f, 531.950012f},
+ {309.049988f, 347.950012f});
+ mandoline.sliceLine({309.049988f, 419});
+ mandoline.sliceLine({357.049988f, 446.049988f});
+ canvas->drawPath(mandoline.path(), paint);
+
+ canvas->save();
+ canvas->translate(421, 105);
+ canvas->scale(100, 81);
+ mandoline.reset({-cosf(SkDegreesToRadians(-60)), sinf(SkDegreesToRadians(-60))});
+ mandoline.sliceConic({-2, 0},
+ {-cosf(SkDegreesToRadians(60)), sinf(SkDegreesToRadians(60))}, .5f);
+ mandoline.sliceConic({-cosf(SkDegreesToRadians(120))*2, sinf(SkDegreesToRadians(120))*2},
+ {1, 0}, .5f);
+ mandoline.sliceLine({0, 0});
+ mandoline.sliceLine({-cosf(SkDegreesToRadians(-60)), sinf(SkDegreesToRadians(-60))});
+ canvas->drawPath(mandoline.path(), paint);
+ canvas->restore();
+
+ canvas->save();
+ canvas->translate(150, 300);
+ canvas->scale(75, 75);
+ mandoline.reset({1, 0});
+ constexpr int nquads = 5;
+ for (int i = 0; i < nquads; ++i) {
+ float theta1 = 2*SK_ScalarPI/nquads * (i + .5f);
+ float theta2 = 2*SK_ScalarPI/nquads * (i + 1);
+ mandoline.sliceQuadratic({cosf(theta1)*2, sinf(theta1)*2},
+ {cosf(theta2), sinf(theta2)});
+ }
+ canvas->drawPath(mandoline.path(), paint);
+ canvas->restore();
+ }
+};
+
+DEF_GM(return new SliverPathsGM;)
+
+}
diff --git a/gn/gm.gni b/gn/gm.gni
index 0e5055b29b..a02ff958a7 100644
--- a/gn/gm.gni
+++ b/gn/gm.gni
@@ -206,6 +206,7 @@ gm_sources = [
"$_gm/lumafilter.cpp",
"$_gm/makecolorspace.cpp",
"$_gm/makeRasterImage.cpp",
+ "$_gm/mandoline.cpp",
"$_gm/manypaths.cpp",
"$_gm/matrixconvolution.cpp",
"$_gm/matriximagefilter.cpp",
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.cpp b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
index d38db27a19..75d0667b09 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
@@ -44,6 +44,36 @@ class GrCCCoverageProcessor::TriangleShader : public GrCCCoverageProcessor::Shad
GrGLSLVarying fCoverages;
};
+void GrCCCoverageProcessor::Shader::CalcWind(const GrCCCoverageProcessor& proc,
+ GrGLSLVertexGeoBuilder* s, const char* pts,
+ const char* outputWind) {
+ if (3 == proc.numInputPoints()) {
+ s->codeAppendf("float2 a = %s[0] - %s[1], "
+ "b = %s[0] - %s[2];", pts, pts, pts, pts);
+ } else {
+ // All inputs are convex, so it's sufficient to just average the middle two input points.
+ SkASSERT(4 == proc.numInputPoints());
+ s->codeAppendf("float2 p12 = (%s[1] + %s[2]) * .5;", pts, pts);
+ s->codeAppendf("float2 a = %s[0] - p12, "
+ "b = %s[0] - %s[3];", pts, pts, pts);
+ }
+
+ s->codeAppend ("float area_x2 = determinant(float2x2(a, b));");
+ if (proc.isTriangles()) {
+ // We cull extremely thin triangles by zeroing wind. When a triangle gets too thin it's
+ // possible for FP round-off error to actually give us the wrong winding direction, causing
+ // rendering artifacts. The criteria we choose is "height <~ 1/1024". So we drop a triangle
+ // if the max effect it can have on any single pixel is <~ 1/1024, or 1/4 of a bit in 8888.
+ s->codeAppend ("float2 bbox_size = max(abs(a), abs(b));");
+ s->codeAppend ("float basewidth = max(bbox_size.x + bbox_size.y, 1);");
+ s->codeAppendf("%s = (abs(area_x2 * 1024) > basewidth) ? sign(area_x2) : 0;", outputWind);
+ } else {
+ // We already converted nearly-flat curves to lines on the CPU, so no need to worry about
+ // thin curve hulls at this point.
+ s->codeAppendf("%s = sign(area_x2);", outputWind);
+ }
+}
+
void GrCCCoverageProcessor::Shader::EmitEdgeDistanceEquation(GrGLSLVertexGeoBuilder* s,
const char* leftPt,
const char* rightPt,
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.h b/src/gpu/ccpr/GrCCCoverageProcessor.h
index 454e728ae9..e3ea34f8dd 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor.h
+++ b/src/gpu/ccpr/GrCCCoverageProcessor.h
@@ -133,6 +133,11 @@ public:
void emitFragmentCode(const GrCCCoverageProcessor&, GrGLSLFPFragmentBuilder*,
const char* skOutputColor, const char* skOutputCoverage) const;
+ // Calculates the winding direction of the input points (+1, -1, or 0). Wind for extremely
+ // thin triangles gets rounded to zero.
+ static void CalcWind(const GrCCCoverageProcessor&, GrGLSLVertexGeoBuilder*, const char* pts,
+ const char* outputWind);
+
// Defines an equation ("dot(float3(pt, 1), distance_equation)") that is -1 on the outside
// border of a conservative raster edge and 0 on the inside. 'leftPt' and 'rightPt' must be
// ordered clockwise.
@@ -207,6 +212,11 @@ private:
// Number of bezier points for curves, or 3 for triangles.
int numInputPoints() const { return PrimitiveType::kCubics == fPrimitiveType ? 4 : 3; }
+ bool isTriangles() const {
+ return PrimitiveType::kTriangles == fPrimitiveType ||
+ PrimitiveType::kWeightedTriangles == fPrimitiveType;
+ }
+
int hasInputWeight() const {
return PrimitiveType::kWeightedTriangles == fPrimitiveType ||
PrimitiveType::kConics == fPrimitiveType;
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp b/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp
index b1d886cf8c..61bb4ec7cf 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp
@@ -59,18 +59,11 @@ protected:
GrShaderVar wind("wind", kHalf_GrSLType);
g->declareGlobal(wind);
- if (PrimitiveType::kWeightedTriangles != proc.fPrimitiveType) {
- g->codeAppend ("float area_x2 = determinant(float2x2(pts[0] - pts[1], "
- "pts[0] - pts[2]));");
- if (4 == numInputPoints) {
- g->codeAppend ("area_x2 += determinant(float2x2(pts[0] - pts[2], "
- "pts[0] - pts[3]));");
- }
- g->codeAppendf("%s = sign(area_x2);", wind.c_str());
- } else {
+ Shader::CalcWind(proc, g, "pts", wind.c_str());
+ if (PrimitiveType::kWeightedTriangles == proc.fPrimitiveType) {
SkASSERT(3 == numInputPoints);
SkASSERT(kFloat4_GrVertexAttribType == proc.getAttrib(0).fType);
- g->codeAppendf("%s = sk_in[0].sk_Position.w;", wind.c_str());
+ g->codeAppendf("%s *= sk_in[0].sk_Position.w;", wind.c_str());
}
SkString emitVertexFn;
@@ -306,10 +299,8 @@ public:
const GrShaderVar& wind, const char* emitVertexFn) const override {
fShader->emitSetupCode(g, "pts", wind.c_str());
- bool isTriangle = PrimitiveType::kTriangles == proc.fPrimitiveType ||
- PrimitiveType::kWeightedTriangles == proc.fPrimitiveType;
g->codeAppendf("int corneridx = sk_InvocationID;");
- if (!isTriangle) {
+ if (!proc.isTriangles()) {
g->codeAppendf("corneridx *= %i;", proc.numInputPoints() - 1);
}
@@ -336,7 +327,7 @@ public:
Shader::CalcCornerAttenuation(g, "leftdir", "rightdir", "attenuation");
g->codeAppend ("}");
- if (isTriangle) {
+ if (proc.isTriangles()) {
g->codeAppend ("half2 left_coverages; {");
Shader::CalcEdgeCoveragesAtBloatVertices(g, "left", "corner", "-outbloat",
"-crossbloat", "left_coverages");
@@ -384,7 +375,7 @@ public:
g->codeAppendf("%s(corner + crossbloat * bloat, -1, half2(1));", emitVertexFn);
}
- g->configure(InputType::kLines, OutputType::kTriangleStrip, 4, isTriangle ? 3 : 2);
+ g->configure(InputType::kLines, OutputType::kTriangleStrip, 4, proc.isTriangles() ? 3 : 2);
}
};
@@ -416,8 +407,7 @@ void GrCCCoverageProcessor::appendGSMesh(GrBuffer* instanceBuffer, int instanceC
GrGLSLPrimitiveProcessor* GrCCCoverageProcessor::createGSImpl(std::unique_ptr<Shader> shadr) const {
if (GSSubpass::kHulls == fGSSubpass) {
- return (PrimitiveType::kTriangles == fPrimitiveType ||
- PrimitiveType::kWeightedTriangles == fPrimitiveType)
+ return this->isTriangles()
? (GSImpl*) new GSTriangleHullImpl(std::move(shadr))
: (GSImpl*) new GSCurveHullImpl(std::move(shadr));
}
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
index dd8da96f82..08b8886aed 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
@@ -263,18 +263,12 @@ void GrCCCoverageProcessor::VSImpl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs)
inputWidth, inputWidth, proc.getAttrib(kAttribIdx_X).fName, swizzle,
proc.getAttrib(kAttribIdx_Y).fName, swizzle);
- if (PrimitiveType::kWeightedTriangles != proc.fPrimitiveType) {
- v->codeAppend ("float area_x2 = determinant(float2x2(pts[0] - pts[1], "
- "pts[0] - pts[2]));");
- if (4 == numInputPoints) {
- v->codeAppend ("area_x2 += determinant(float2x2(pts[0] - pts[2], "
- "pts[0] - pts[3]));");
- }
- v->codeAppend ("half wind = sign(area_x2);");
- } else {
+ v->codeAppend ("half wind;");
+ Shader::CalcWind(proc, v, "pts", "wind");
+ if (PrimitiveType::kWeightedTriangles == proc.fPrimitiveType) {
SkASSERT(3 == numInputPoints);
SkASSERT(kFloat4_GrVertexAttribType == proc.getAttrib(kAttribIdx_X).fType);
- v->codeAppendf("half wind = %s.w;", proc.getAttrib(kAttribIdx_X).fName);
+ v->codeAppendf("wind *= %s.w;", proc.getAttrib(kAttribIdx_X).fName);
}
float bloat = kAABloatRadius;
diff --git a/src/gpu/ccpr/GrCCGeometry.cpp b/src/gpu/ccpr/GrCCGeometry.cpp
index 9fbf3e61f8..30d93ad416 100644
--- a/src/gpu/ccpr/GrCCGeometry.cpp
+++ b/src/gpu/ccpr/GrCCGeometry.cpp
@@ -38,14 +38,20 @@ void GrCCGeometry::beginContour(const SkPoint& pt) {
SkDEBUGCODE(fBuildingContour = true);
}
-void GrCCGeometry::lineTo(const SkPoint& pt) {
+void GrCCGeometry::lineTo(const SkPoint P[2]) {
SkASSERT(fBuildingContour);
- fPoints.push_back(pt);
- fVerbs.push_back(Verb::kLineTo);
+ SkASSERT(P[0] == fPoints.back());
+ Sk2f p0 = Sk2f::Load(P);
+ Sk2f p1 = Sk2f::Load(P+1);
+ this->appendLine(p0, p1);
}
-void GrCCGeometry::appendLine(const Sk2f& endpt) {
- endpt.store(&fPoints.push_back());
+inline void GrCCGeometry::appendLine(const Sk2f& p0, const Sk2f& p1) {
+ SkASSERT(fPoints.back() == SkPoint::Make(p0[0], p0[1]));
+ if ((p0 == p1).allTrue()) {
+ return;
+ }
+ p1.store(&fPoints.push_back());
fVerbs.push_back(Verb::kLineTo);
}
@@ -142,7 +148,7 @@ void GrCCGeometry::quadraticTo(const SkPoint P[3]) {
// 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);
+ this->appendLine(p0, p2);
return;
}
@@ -190,12 +196,12 @@ inline void GrCCGeometry::appendQuadratics(const Sk2f& p0, const Sk2f& p1, const
inline void GrCCGeometry::appendMonotonicQuadratic(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2) {
// Don't send curves to the GPU if we know they are nearly flat (or just very small).
if (are_collinear(p0, p1, p2)) {
- SkASSERT(fPoints.back() == SkPoint::Make(p0[0], p0[1]));
- this->appendLine(p2);
+ this->appendLine(p0, p2);
return;
}
SkASSERT(fPoints.back() == SkPoint::Make(p0[0], p0[1]));
+ SkASSERT((p0 != p2).anyTrue());
p1.store(&fPoints.push_back());
p2.store(&fPoints.push_back());
fVerbs.push_back(Verb::kMonotonicQuadraticTo);
@@ -466,7 +472,9 @@ void GrCCGeometry::cubicTo(const SkPoint P[4], float inflectPad, float loopInter
// 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(P)) {
- this->lineTo(P[3]);
+ Sk2f p0 = Sk2f::Load(P);
+ Sk2f p3 = Sk2f::Load(P+3);
+ this->appendLine(p0, p3);
return;
}
@@ -570,10 +578,6 @@ void GrCCGeometry::appendCubics(AppendCubicMode mode, const Sk2f& p0, const Sk2f
void GrCCGeometry::appendCubics(AppendCubicMode mode, const Sk2f& p0, const Sk2f& p1,
const Sk2f& p2, const Sk2f& p3, int maxSubdivisions) {
- if ((p0 == p3).allTrue()) {
- return;
- }
-
if (SkCubicType::kLoop != fCurrCubicType) {
// Serpentines and cusps are always monotonic after chopping around inflection points.
SkASSERT(!SkCubicIsDegenerate(fCurrCubicType));
@@ -583,8 +587,7 @@ void GrCCGeometry::appendCubics(AppendCubicMode mode, const Sk2f& p0, const Sk2f
// 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]));
- this->appendLine(p3);
+ this->appendLine(p0, p3);
return;
}
} else {
@@ -613,12 +616,12 @@ void GrCCGeometry::appendCubics(AppendCubicMode mode, const Sk2f& p0, const Sk2f
// 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)) {
- SkASSERT(fPoints.back() == SkPoint::Make(p0[0], p0[1]));
- this->appendLine(p3);
+ this->appendLine(p0, p3);
return;
}
SkASSERT(fPoints.back() == SkPoint::Make(p0[0], p0[1]));
+ SkASSERT((p0 != p3).anyTrue());
p1.store(&fPoints.push_back());
p2.store(&fPoints.push_back());
p3.store(&fPoints.push_back());
@@ -686,7 +689,7 @@ inline void GrCCGeometry::chopAndAppendCubicAtMidTangent(AppendCubicMode mode, c
// near-flat cubics in cubicTo().)
if (!(midT > 0 && midT < 1)) {
// The cubic is flat. Otherwise there would be a real midtangent inside T=0..1.
- this->appendLine(p3);
+ this->appendLine(p0, p3);
return;
}
@@ -720,7 +723,7 @@ void GrCCGeometry::conicTo(const SkPoint P[3], float w) {
// midtangents.)
if (!(midT > 0 && midT < 1)) {
// The conic is flat. Otherwise there would be a real midtangent inside T=0..1.
- this->appendLine(p2);
+ this->appendLine(p0, p2);
return;
}
@@ -747,7 +750,6 @@ void GrCCGeometry::conicTo(const SkPoint P[3], float w) {
void GrCCGeometry::appendMonotonicConic(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2, float w) {
SkASSERT(w >= 0);
- SkASSERT(fPoints.back() == SkPoint::Make(p0[0], p0[1]));
Sk2f base = p2 - p0;
Sk2f baseAbs = base.abs();
@@ -758,24 +760,28 @@ void GrCCGeometry::appendMonotonicConic(const Sk2f& p0, const Sk2f& p1, const Sk
float h1 = std::abs(d[1] - d[0]); // Height of p1 above the base.
float ht = h1*w, hs = 1 + w; // Height of the conic = ht/hs.
- if (ht < (baseWidth*hs) * kFlatnessThreshold) { // i.e. ht/hs < baseWidth * kFlatnessThreshold
+ // i.e. (ht/hs <= baseWidth * kFlatnessThreshold). Use "<=" in case base == 0.
+ if (ht <= (baseWidth*hs) * kFlatnessThreshold) {
// We are flat. (See rationale in are_collinear.)
- this->appendLine(p2);
+ this->appendLine(p0, p2);
return;
}
- if (w > 1 && h1*hs - ht < baseWidth*hs) { // i.e. w > 1 && h1 - ht/hs < baseWidth
+ // i.e. (w > 1 && h1 - ht/hs < baseWidth).
+ if (w > 1 && h1*hs - ht < baseWidth*hs) {
// If we get within 1px of p1 when w > 1, we will pick up artifacts from the implicit
// function's reflection. Chop at max height (T=.5) and draw a triangle instead.
Sk2f p1w = p1*w;
Sk2f ab = p0 + p1w;
Sk2f bc = p1w + p2;
Sk2f highpoint = (ab + bc) / (2*(1 + w));
- this->appendLine(highpoint);
- this->appendLine(p2);
+ this->appendLine(p0, highpoint);
+ this->appendLine(highpoint, p2);
return;
}
+ SkASSERT(fPoints.back() == SkPoint::Make(p0[0], p0[1]));
+ SkASSERT((p0 != p2).anyTrue());
p1.store(&fPoints.push_back());
p2.store(&fPoints.push_back());
fConicWeights.push_back(w);
diff --git a/src/gpu/ccpr/GrCCGeometry.h b/src/gpu/ccpr/GrCCGeometry.h
index 96a38e94e7..571b3c0a52 100644
--- a/src/gpu/ccpr/GrCCGeometry.h
+++ b/src/gpu/ccpr/GrCCGeometry.h
@@ -76,7 +76,7 @@ public:
void beginPath();
void beginContour(const SkPoint&);
- void lineTo(const SkPoint&);
+ void lineTo(const SkPoint P[2]);
void quadraticTo(const SkPoint[3]);
// We pass through inflection points and loop intersections using a line and quadratic(s)
@@ -97,7 +97,7 @@ public:
PrimitiveTallies endContour(); // Returns the numbers of primitives needed to draw the contour.
private:
- inline void appendLine(const Sk2f& endpt);
+ inline void appendLine(const Sk2f& p0, const Sk2f& p1);
inline void appendQuadratics(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2);
inline void appendMonotonicQuadratic(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2);
diff --git a/src/gpu/ccpr/GrCCPathParser.cpp b/src/gpu/ccpr/GrCCPathParser.cpp
index 2740569fe6..1629a191a5 100644
--- a/src/gpu/ccpr/GrCCPathParser.cpp
+++ b/src/gpu/ccpr/GrCCPathParser.cpp
@@ -132,7 +132,7 @@ void GrCCPathParser::parsePath(const SkPath& path, const SkPoint* deviceSpacePts
insideContour = false;
continue;
case SkPath::kLine_Verb:
- fGeometry.lineTo(deviceSpacePts[ptsIdx]);
+ fGeometry.lineTo(&deviceSpacePts[ptsIdx - 1]);
++ptsIdx;
continue;
case SkPath::kQuad_Verb:
@@ -340,8 +340,7 @@ static void emit_tessellated_fan(const GrTessellator::WindingVertex* vertices, i
} else {
quadPointInstanceData[indices->fWeightedTriangles++].setW(
vertices[i].fPos, vertices[i+1].fPos, vertices[i + 2].fPos, atlasOffset,
- // Tessellator has opposite winding sense.
- -static_cast<float>(vertices[i].fWinding));
+ static_cast<float>(abs(vertices[i].fWinding)));
}
}
}
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index c569e031e2..3bd857d53a 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -2271,7 +2271,9 @@ void GrGLCaps::applyDriverCorrectnessWorkarounds(const GrGLContextInfo& ctxInfo,
fRequiresCullFaceEnableDisableWhenDrawingLinesAfterNonLines = true;
}
- if (kIntelSkylake_GrGLRenderer == ctxInfo.renderer()) {
+ if (kIntelSkylake_GrGLRenderer == ctxInfo.renderer() ||
+ (kANGLE_GrGLRenderer == ctxInfo.renderer() &&
+ GrGLANGLERenderer::kSkylake == ctxInfo.angleRenderer())) {
fRequiresFlushBetweenNonAndInstancedDraws = true;
}
@@ -2319,21 +2321,6 @@ void GrGLCaps::applyDriverCorrectnessWorkarounds(const GrGLContextInfo& ctxInfo,
fDrawArraysBaseVertexIsBroken = true;
}
- // Blacklisting CCPR on ANGLE while we investigate http://skbug.com/7805.
- if (kANGLE_GrGLRenderer == ctxInfo.renderer()) {
- fBlacklistCoverageCounting = true;
- }
-
- // The ccpr vertex-shader implementation does not work on this platform. Only allow CCPR with
- // GS.
- if (kANGLE_GrGLRenderer == ctxInfo.renderer() &&
- GrGLANGLERenderer::kSkylake == ctxInfo.angleRenderer()) {
- bool gsSupport = fShaderCaps->geometryShaderSupport();
-#if GR_TEST_UTILS
- gsSupport &= !contextOptions.fSuppressGeometryShaders;
-#endif
- fBlacklistCoverageCounting = !gsSupport;
- }
// Currently the extension is advertised but fb fetch is broken on 500 series Adrenos like the
// Galaxy S7.
// TODO: Once this is fixed we can update the check here to look at a driver version number too.