diff options
author | Chris Dalton <csmartdalton@google.com> | 2017-12-07 12:47:02 -0700 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-12-07 23:44:20 +0000 |
commit | 43646533fa6fb7cd6724cf00f6b8af15ac1649ea (patch) | |
tree | 8ae9d47982693a9cd43f5e84c1fdf609f3ad21e4 /src | |
parent | 032d924ba85397b3f523c54f6337c80748d3e545 (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.h | 10 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCPRCoverageProcessor_GSImpl.cpp | 19 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCPRCubicShader.cpp | 19 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCPRCubicShader.h | 4 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCPRGeometry.cpp | 59 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCPRGeometry.h | 4 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCPRQuadraticShader.cpp | 16 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCPRQuadraticShader.h | 4 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCPRTriangleShader.cpp | 6 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCPRTriangleShader.h | 20 |
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; |