aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Chris Dalton <csmartdalton@google.com>2017-12-07 12:47:02 -0700
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-12-07 23:44:20 +0000
commit43646533fa6fb7cd6724cf00f6b8af15ac1649ea (patch)
tree8ae9d47982693a9cd43f5e84c1fdf609f3ad21e4 /src
parent032d924ba85397b3f523c54f6337c80748d3e545 (diff)
CCPR: Move flatness checks from geometry shaders to CPU
Vertex shaders can't discard geometry. Bug: skia: Change-Id: Iec22a103b7a4eda9a59fd99e48644183b0880f5f Reviewed-on: https://skia-review.googlesource.com/82260 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Chris Dalton <csmartdalton@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/gpu/ccpr/GrCCPRCoverageProcessor.h10
-rw-r--r--src/gpu/ccpr/GrCCPRCoverageProcessor_GSImpl.cpp19
-rw-r--r--src/gpu/ccpr/GrCCPRCubicShader.cpp19
-rw-r--r--src/gpu/ccpr/GrCCPRCubicShader.h4
-rw-r--r--src/gpu/ccpr/GrCCPRGeometry.cpp59
-rw-r--r--src/gpu/ccpr/GrCCPRGeometry.h4
-rw-r--r--src/gpu/ccpr/GrCCPRQuadraticShader.cpp16
-rw-r--r--src/gpu/ccpr/GrCCPRQuadraticShader.h4
-rw-r--r--src/gpu/ccpr/GrCCPRTriangleShader.cpp6
-rw-r--r--src/gpu/ccpr/GrCCPRTriangleShader.h20
10 files changed, 58 insertions, 103 deletions
diff --git a/src/gpu/ccpr/GrCCPRCoverageProcessor.h b/src/gpu/ccpr/GrCCPRCoverageProcessor.h
index 3c4050a73b..75cc45b8eb 100644
--- a/src/gpu/ccpr/GrCCPRCoverageProcessor.h
+++ b/src/gpu/ccpr/GrCCPRCoverageProcessor.h
@@ -117,17 +117,11 @@ public:
};
virtual GeometryType getGeometryType() const = 0;
- virtual int getNumInputPoints() const = 0;
// Returns the number of independent geometric segments to generate for the render pass
// (number of wedges for a hull, number of edges, or number of corners.)
virtual int getNumSegments() const = 0;
- // Determines the winding direction of the primitive. The subclass must write a value of
- // either -1, 0, or +1 to "outputWind" (e.g. "sign(area)"). Fractional values are not valid.
- virtual void emitWind(GrGLSLShaderBuilder*, const char* pts,
- const char* outputWind) const = 0;
-
union GeometryVars {
struct {
const char* fAlternatePoints; // floatNx2 (if left null, will use input points).
@@ -223,6 +217,10 @@ private:
// accidentally bleed into neighbor pixels.
static constexpr float kAABloatRadius = 0.491111f;
+ int numInputPoints() const {
+ return RenderPassIsCubic(fRenderPass) ? 4 : 3;
+ }
+
static GrGLSLPrimitiveProcessor* CreateGSImpl(std::unique_ptr<Shader>);
const RenderPass fRenderPass;
diff --git a/src/gpu/ccpr/GrCCPRCoverageProcessor_GSImpl.cpp b/src/gpu/ccpr/GrCCPRCoverageProcessor_GSImpl.cpp
index 51791a1628..5c9ba3bfc2 100644
--- a/src/gpu/ccpr/GrCCPRCoverageProcessor_GSImpl.cpp
+++ b/src/gpu/ccpr/GrCCPRCoverageProcessor_GSImpl.cpp
@@ -49,11 +49,11 @@ protected:
using InputType = GrGLSLGeometryBuilder::InputType;
using OutputType = GrGLSLGeometryBuilder::OutputType;
- int numPts = fShader->getNumInputPoints();
- SkASSERT(3 == numPts || 4 == numPts);
+ int numInputPoints = proc.numInputPoints();
+ SkASSERT(3 == numInputPoints || 4 == numInputPoints);
- g->codeAppendf("float%ix2 pts = float%ix2(", numPts, numPts);
- for (int i = 0; i < numPts; ++i) {
+ g->codeAppendf("float%ix2 pts = float%ix2(", numInputPoints, numInputPoints);
+ for (int i = 0; i < numInputPoints; ++i) {
g->codeAppend (i ? ", " : "");
g->codeAppendf("sk_in[%i].sk_Position.xy", i);
}
@@ -61,7 +61,11 @@ protected:
GrShaderVar wind("wind", kHalf_GrSLType);
g->declareGlobal(wind);
- fShader->emitWind(g, "pts", wind.c_str());
+ 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());
SkString emitVertexFn;
SkSTArray<2, GrShaderVar> emitArgs;
@@ -85,12 +89,8 @@ protected:
Shader::GeometryVars vars;
fShader->emitSetupCode(g, "pts", "sk_InvocationID", wind.c_str(), &vars);
int maxPoints = this->onEmitGeometryShader(g, wind, emitVertexFn.c_str(), vars);
-
- int numInputPoints = fShader->getNumInputPoints();
- SkASSERT(3 == numInputPoints || 4 == numInputPoints);
InputType inputType = (3 == numInputPoints) ? InputType::kTriangles
: InputType::kLinesAdjacency;
-
g->configure(inputType, OutputType::kTriangleStrip, maxPoints, fShader->getNumSegments());
}
@@ -117,7 +117,6 @@ public:
const char* hullPts = vars.fHullVars.fAlternatePoints;
if (!hullPts) {
- SkASSERT(fShader->getNumInputPoints() == numSides);
hullPts = "pts";
}
diff --git a/src/gpu/ccpr/GrCCPRCubicShader.cpp b/src/gpu/ccpr/GrCCPRCubicShader.cpp
index 59cd2a8537..1c29862bea 100644
--- a/src/gpu/ccpr/GrCCPRCubicShader.cpp
+++ b/src/gpu/ccpr/GrCCPRCubicShader.cpp
@@ -9,25 +9,6 @@
#include "glsl/GrGLSLFragmentShaderBuilder.h"
-void GrCCPRCubicShader::emitWind(GrGLSLShaderBuilder* s, const char* pts,
- const char* outputWind) const {
-
- s->codeAppendf("float area_times_2 = determinant(float3x3(1, %s[0], "
- "1, %s[2], "
- "0, %s[3] - %s[1]));",
- pts, pts, pts, pts);
- // Drop curves that are nearly flat. The KLM math becomes unstable in this case.
- s->codeAppendf("if (2 * abs(area_times_2) < length(%s[3] - %s[0])) {", pts, pts);
-#ifndef SK_BUILD_FOR_MAC
- s->codeAppend ( "return;");
-#else
- // Returning from this geometry shader makes Mac very unhappy. Instead we make wind 0.
- s->codeAppend ( "area_times_2 = 0;");
-#endif
- s->codeAppend ("}");
- s->codeAppendf("%s = sign(area_times_2);", outputWind);
-}
-
void GrCCPRCubicShader::emitSetupCode(GrGLSLShaderBuilder* s, const char* pts,
const char* segmentId, const char* wind,
GeometryVars* vars) const {
diff --git a/src/gpu/ccpr/GrCCPRCubicShader.h b/src/gpu/ccpr/GrCCPRCubicShader.h
index 8cfacd61bb..c0cb0757d1 100644
--- a/src/gpu/ccpr/GrCCPRCubicShader.h
+++ b/src/gpu/ccpr/GrCCPRCubicShader.h
@@ -31,10 +31,6 @@ public:
protected:
GrCCPRCubicShader(CubicType cubicType) : fCubicType(cubicType) {}
- int getNumInputPoints() const final { return 4; }
-
- void emitWind(GrGLSLShaderBuilder*, const char* pts, const char* outputWind) const final;
-
void emitSetupCode(GrGLSLShaderBuilder*, const char* pts, const char* segmentId,
const char* wind, GeometryVars*) const final;
diff --git a/src/gpu/ccpr/GrCCPRGeometry.cpp b/src/gpu/ccpr/GrCCPRGeometry.cpp
index bbf5e4fc0f..d6423effa3 100644
--- a/src/gpu/ccpr/GrCCPRGeometry.cpp
+++ b/src/gpu/ccpr/GrCCPRGeometry.cpp
@@ -58,7 +58,7 @@ static inline float dot(const Sk2f& a, const Sk2f& b) {
}
static inline bool are_collinear(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2) {
- static constexpr float kFlatnessTolerance = 16; // 1/16 of a pixel.
+ static constexpr float kFlatnessTolerance = 4; // 1/4 of a pixel.
// Area (times 2) of the triangle.
Sk2f a = (p0 - p1) * SkNx_shuffle<1,0>(p1 - p2);
@@ -99,28 +99,17 @@ void GrCCPRGeometry::quadraticTo(const SkPoint& devP0, const SkPoint& devP1) {
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;
- }
-
this->appendMonotonicQuadratics(p0, p1, p2);
}
inline void GrCCPRGeometry::appendMonotonicQuadratics(const Sk2f& p0, const Sk2f& p1,
- const Sk2f& p2, bool allowChop) {
- SkASSERT(fPoints.back() == SkPoint::Make(p0[0], p0[1]));
+ const Sk2f& p2) {
Sk2f tan0 = p1 - p0;
Sk2f tan1 = p2 - p1;
// This should almost always be this case for well-behaved curves in the real world.
- if (!allowChop || is_convex_curve_monotonic(p0, tan0, p2, tan1)) {
- p1.store(&fPoints.push_back());
- p2.store(&fPoints.push_back());
- fVerbs.push_back(Verb::kMonotonicQuadraticTo);
- ++fCurrContourTallies.fQuadratics;
+ if (is_convex_curve_monotonic(p0, tan0, p2, tan1)) {
+ this->appendSingleMonotonicQuadratic(p0, p1, p2);
return;
}
@@ -148,12 +137,25 @@ inline void GrCCPRGeometry::appendMonotonicQuadratics(const Sk2f& p0, const Sk2f
Sk2f p12 = SkNx_fma(t, tan1, p1);
Sk2f p012 = lerp(p01, p12, t);
- p01.store(&fPoints.push_back());
- p012.store(&fPoints.push_back());
- p12.store(&fPoints.push_back());
+ this->appendSingleMonotonicQuadratic(p0, p01, p012);
+ this->appendSingleMonotonicQuadratic(p012, p12, p2);
+}
+
+inline void GrCCPRGeometry::appendSingleMonotonicQuadratic(const Sk2f& p0, const Sk2f& p1,
+ const Sk2f& p2) {
+ SkASSERT(fPoints.back() == SkPoint::Make(p0[0], p0[1]));
+
+ // 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);
+ return;
+ }
+
+ p1.store(&fPoints.push_back());
p2.store(&fPoints.push_back());
- fVerbs.push_back_n(2, Verb::kMonotonicQuadraticTo);
- fCurrContourTallies.fQuadratics += 2;
+ fVerbs.push_back(Verb::kMonotonicQuadraticTo);
+ ++fCurrContourTallies.fQuadratics;
}
using ExcludedTerm = GrPathUtils::ExcludedTerm;
@@ -295,7 +297,7 @@ 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).
+ // Don't crunch on the curve and inflate geometry if it is nearly flat (or just very small).
if (are_collinear(p0, p1, p2) &&
are_collinear(p1, p2, p3) &&
are_collinear(p0, (p1 + p2) * .5f, p3)) {
@@ -524,6 +526,15 @@ void GrCCPRGeometry::appendMonotonicCubics(const Sk2f& p0, const Sk2f& p1, const
}
SkASSERT(fPoints.back() == SkPoint::Make(p0[0], p0[1]));
+
+ // 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);
+ return;
+ }
+
p1.store(&fPoints.push_back());
p2.store(&fPoints.push_back());
p3.store(&fPoints.push_back());
@@ -561,7 +572,11 @@ void GrCCPRGeometry::appendCubicApproximation(const Sk2f& p0, const Sk2f& p1, co
return;
}
- this->appendMonotonicQuadratics(p0, c, p3, SkToBool(maxSubdivisions));
+ if (maxSubdivisions) {
+ this->appendMonotonicQuadratics(p0, c, p3);
+ } else {
+ this->appendSingleMonotonicQuadratic(p0, c, p3);
+ }
}
GrCCPRGeometry::PrimitiveTallies GrCCPRGeometry::endContour() {
diff --git a/src/gpu/ccpr/GrCCPRGeometry.h b/src/gpu/ccpr/GrCCPRGeometry.h
index 1cb4719b1e..407e655916 100644
--- a/src/gpu/ccpr/GrCCPRGeometry.h
+++ b/src/gpu/ccpr/GrCCPRGeometry.h
@@ -93,8 +93,8 @@ public:
PrimitiveTallies endContour(); // Returns the numbers of primitives needed to draw the contour.
private:
- inline void appendMonotonicQuadratics(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2,
- bool allowChop = true);
+ inline void appendMonotonicQuadratics(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2);
+ inline void appendSingleMonotonicQuadratic(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2);
using AppendCubicFn = void(GrCCPRGeometry::*)(const Sk2f& p0, const Sk2f& p1,
const Sk2f& p2, const Sk2f& p3,
diff --git a/src/gpu/ccpr/GrCCPRQuadraticShader.cpp b/src/gpu/ccpr/GrCCPRQuadraticShader.cpp
index 6dd062b923..01527d0017 100644
--- a/src/gpu/ccpr/GrCCPRQuadraticShader.cpp
+++ b/src/gpu/ccpr/GrCCPRQuadraticShader.cpp
@@ -9,22 +9,6 @@
#include "glsl/GrGLSLFragmentShaderBuilder.h"
-void GrCCPRQuadraticShader::emitWind(GrGLSLShaderBuilder* s, const char* pts,
- const char* outputWind) const {
- s->codeAppendf("float area_times_2 = determinant(float2x2(%s[1] - %s[0], %s[2] - %s[0]));",
- pts, pts, pts, pts);
- // Drop curves that are nearly flat, in favor of the higher quality triangle antialiasing.
- s->codeAppendf("if (2 * abs(area_times_2) < length(%s[2] - %s[0])) {", pts, pts);
-#ifndef SK_BUILD_FOR_MAC
- s->codeAppend ( "return;");
-#else
- // Returning from this geometry shader makes Mac very unhappy. Instead we make wind 0.
- s->codeAppend ( "area_times_2 = 0;");
-#endif
- s->codeAppend ("}");
- s->codeAppendf("%s = sign(area_times_2);", outputWind);
-}
-
void GrCCPRQuadraticShader::emitSetupCode(GrGLSLShaderBuilder* s, const char* pts,
const char* segmentId, const char* wind,
GeometryVars* vars) const {
diff --git a/src/gpu/ccpr/GrCCPRQuadraticShader.h b/src/gpu/ccpr/GrCCPRQuadraticShader.h
index 4877edec44..d04e82d249 100644
--- a/src/gpu/ccpr/GrCCPRQuadraticShader.h
+++ b/src/gpu/ccpr/GrCCPRQuadraticShader.h
@@ -22,10 +22,6 @@
*/
class GrCCPRQuadraticShader : public GrCCPRCoverageProcessor::Shader {
protected:
- int getNumInputPoints() const final { return 3; }
-
- void emitWind(GrGLSLShaderBuilder*, const char* pts, const char* outputWind) const final;
-
void emitSetupCode(GrGLSLShaderBuilder*, const char* pts, const char* segmentId,
const char* wind, GeometryVars*) const final;
diff --git a/src/gpu/ccpr/GrCCPRTriangleShader.cpp b/src/gpu/ccpr/GrCCPRTriangleShader.cpp
index c2c624b1ae..836be31e43 100644
--- a/src/gpu/ccpr/GrCCPRTriangleShader.cpp
+++ b/src/gpu/ccpr/GrCCPRTriangleShader.cpp
@@ -10,12 +10,6 @@
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLVertexGeoBuilder.h"
-void GrCCPRTriangleShader::emitWind(GrGLSLShaderBuilder* s, const char* pts,
- const char* outputWind) const {
- s->codeAppendf("%s = sign(determinant(float2x2(%s[1] - %s[0], %s[2] - %s[0])));",
- outputWind, pts, pts, pts, pts);
-}
-
GrCCPRTriangleHullShader::WindHandling
GrCCPRTriangleHullShader::onEmitVaryings(GrGLSLVaryingHandler*, SkString* code,
const char* /*position*/, const char* /*coverage*/,
diff --git a/src/gpu/ccpr/GrCCPRTriangleShader.h b/src/gpu/ccpr/GrCCPRTriangleShader.h
index a0bbb66819..0d7fc8abde 100644
--- a/src/gpu/ccpr/GrCCPRTriangleShader.h
+++ b/src/gpu/ccpr/GrCCPRTriangleShader.h
@@ -11,23 +11,13 @@
#include "ccpr/GrCCPRCoverageProcessor.h"
/**
- * This class renders the coverage of triangles. Triangles are rendered in three passes, as
- * described below.
- */
-class GrCCPRTriangleShader : public GrCCPRCoverageProcessor::Shader {
-public:
- int getNumInputPoints() const final { return 3; }
- int getNumSegments() const final { return 3; } // 3 wedges, 3 edges, 3 corners.
- void emitWind(GrGLSLShaderBuilder* s, const char* pts, const char* outputWind) const final;
-};
-
-/**
* Pass 1: Draw the triangle's conservative raster hull with a coverage of 1. (Conservative raster
* is drawn by considering 3 pixel size boxes, one centered at each vertex, and drawing the
* convex hull of those boxes.)
*/
-class GrCCPRTriangleHullShader : public GrCCPRTriangleShader {
+class GrCCPRTriangleHullShader : public GrCCPRCoverageProcessor::Shader {
GeometryType getGeometryType() const override { return GeometryType::kHull; }
+ int getNumSegments() const final { return 3; }
WindHandling onEmitVaryings(GrGLSLVaryingHandler*, SkString* code, const char* position,
const char* coverage, const char* wind) override;
@@ -39,8 +29,9 @@ class GrCCPRTriangleHullShader : public GrCCPRTriangleShader {
* each edge (i.e. convex hull of two pixel-size boxes at the endpoints), interpolating from
* coverage=-1 on the outside edge to coverage=0 on the inside edge.
*/
-class GrCCPRTriangleEdgeShader : public GrCCPRTriangleShader {
+class GrCCPRTriangleEdgeShader : public GrCCPRCoverageProcessor::Shader {
GeometryType getGeometryType() const override { return GeometryType::kEdges; }
+ int getNumSegments() const final { return 3; }
WindHandling onEmitVaryings(GrGLSLVaryingHandler*, SkString* code, const char* position,
const char* coverage, const char* wind) override;
@@ -54,8 +45,9 @@ class GrCCPRTriangleEdgeShader : public GrCCPRTriangleShader {
* done previously so that it takes into account the region that is outside both edges at
* the same time.
*/
-class GrCCPRTriangleCornerShader : public GrCCPRTriangleShader {
+class GrCCPRTriangleCornerShader : public GrCCPRCoverageProcessor::Shader {
GeometryType getGeometryType() const override { return GeometryType::kCorners; }
+ int getNumSegments() const final { return 3; }
void emitSetupCode(GrGLSLShaderBuilder*, const char* pts, const char* cornerId,
const char* wind, GeometryVars*) const override;