Reland "Wean tessellation off SkPathOps"
This is a reland of 6b2121d0ec5719e60d8b61621de2ae54e78183c6
Original change's description:
> Wean tessellation off SkPathOps
>
> Now that chopping and culling are fully implemented, and the indirect
> tessellators are gone, we don't need to crop huge paths anymore. The
> recursive chopping and culling will just do their thing.
>
> Bug: skia:9795
> Bug: skia:11268
> Bug: chromium:800804
> Change-Id: Ie34920c59af67035cf37eead69c5335693703001
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/416080
> Commit-Queue: Chris Dalton <csmartdalton@google.com>
> Reviewed-by: Mike Reed <reed@google.com>
Bug: skia:9795
Bug: skia:11268
Bug: chromium:800804
Change-Id: I0d35c309a62e4dc6983b57b0592eac95c69c0889
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/417239
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/tessellate/GrTessellationPathRenderer.cpp b/src/gpu/tessellate/GrTessellationPathRenderer.cpp
index 09f2769..e0edb7c 100644
--- a/src/gpu/tessellate/GrTessellationPathRenderer.cpp
+++ b/src/gpu/tessellate/GrTessellationPathRenderer.cpp
@@ -7,7 +7,6 @@
#include "src/gpu/tessellate/GrTessellationPathRenderer.h"
-#include "include/pathops/SkPathOps.h"
#include "src/core/SkIPoint16.h"
#include "src/core/SkPathPriv.h"
#include "src/gpu/GrClip.h"
@@ -85,58 +84,8 @@
GrTessellationPathRenderer::PathFlags pathFlags, GrAAType aaType,
const SkRect& shapeDevBounds, const SkMatrix& viewMatrix,
const GrStyledShape& shape, GrPaint&& paint) {
- constexpr static auto kLinearizationPrecision =
- GrTessellationPathRenderer::kLinearizationPrecision;
- constexpr static auto kMaxResolveLevel = GrTessellationPathRenderer::kMaxResolveLevel;
SkPath path;
shape.asPath(&path);
-
- // Find the worst-case log2 number of line segments that a curve in this path might need to be
- // divided into.
- int worstCaseResolveLevel = GrWangsFormula::worst_case_cubic_log2(kLinearizationPrecision,
- shapeDevBounds.width(),
- shapeDevBounds.height());
- if (worstCaseResolveLevel > kMaxResolveLevel) {
- // The path is too large for our internal indirect draw shaders. Crop it to the viewport.
- auto viewport = SkRect::MakeIWH(surfaceContext->width(), surfaceContext->height());
- float inflationRadius = 1;
- const SkStrokeRec& stroke = shape.style().strokeRec();
- if (stroke.getStyle() == SkStrokeRec::kHairline_Style) {
- inflationRadius += SkStrokeRec::GetInflationRadius(stroke.getJoin(), stroke.getMiter(),
- stroke.getCap(), 1);
- } else if (stroke.getStyle() != SkStrokeRec::kFill_Style) {
- inflationRadius += stroke.getInflationRadius() * viewMatrix.getMaxScale();
- }
- viewport.outset(inflationRadius, inflationRadius);
-
- SkPath viewportPath;
- viewportPath.addRect(viewport);
- // Perform the crop in device space so it's a simple rect-path intersection.
- path.transform(viewMatrix);
- if (!Op(viewportPath, path, kIntersect_SkPathOp, &path)) {
- // The crop can fail if the PathOps encounter NaN or infinities. Return true
- // because drawing nothing is acceptable behavior for FP overflow.
- return nullptr;
- }
-
- // Transform the path back to its own local space.
- SkMatrix inverse;
- if (!viewMatrix.invert(&inverse)) {
- return nullptr; // Singular view matrix. Nothing would have drawn anyway. Return null.
- }
- path.transform(inverse);
- path.setIsVolatile(true);
-
- SkRect newDevBounds;
- viewMatrix.mapRect(&newDevBounds, path.getBounds());
- worstCaseResolveLevel = GrWangsFormula::worst_case_cubic_log2(kLinearizationPrecision,
- newDevBounds.width(),
- newDevBounds.height());
- // kMaxResolveLevel should be large enough to tessellate paths the size of any screen we
- // might encounter.
- SkASSERT(worstCaseResolveLevel <= kMaxResolveLevel);
- }
-
if (!shape.style().isSimpleFill()) {
const SkStrokeRec& stroke = shape.style().strokeRec();
SkASSERT(stroke.getStyle() != SkStrokeRec::kStrokeAndFill_Style);
diff --git a/src/gpu/tessellate/GrTessellationPathRenderer.h b/src/gpu/tessellate/GrTessellationPathRenderer.h
index a34877c..d934e8a 100644
--- a/src/gpu/tessellate/GrTessellationPathRenderer.h
+++ b/src/gpu/tessellate/GrTessellationPathRenderer.h
@@ -22,17 +22,6 @@
// Don't allow linearized segments to be off by more than 1/4th of a pixel from the true curve.
constexpr static float kLinearizationPrecision = 4;
- // This is the maximum resolve level supported by our internal indirect draw shaders. (Indirect
- // draws are an alternative to hardware tessellation, and we can use them when hardware support
- // is lacking.)
- //
- // At a given resolveLevel, a curve gets linearized into 2^resolveLevel line segments. So the
- // finest resolveLevel supported by our indirect draw shaders is 2^10 == 1024 line segments.
- //
- // 1024 line segments is enough resolution (with precision == 4) to guarantee we can render a
- // 123575px x 123575px path. (See GrWangsFormula::worst_case_cubic.)
- constexpr static int kMaxResolveLevel = 10;
-
// We send these flags to the internal path filling Ops to control how a path gets rendered.
enum class PathFlags {
kNone = 0,
diff --git a/src/gpu/tessellate/shaders/GrStrokeTessellationShader.cpp b/src/gpu/tessellate/shaders/GrStrokeTessellationShader.cpp
index e71ac43..b1e6232 100644
--- a/src/gpu/tessellate/shaders/GrStrokeTessellationShader.cpp
+++ b/src/gpu/tessellate/shaders/GrStrokeTessellationShader.cpp
@@ -27,6 +27,7 @@
const char* GrStrokeTessellationShader::Impl::kCosineBetweenVectorsFn = R"(
float cosine_between_vectors(float2 a, float2 b) {
+ // FIXME(crbug.com/800804,skbug.com/11268): This can overflow if we don't normalize exponents.
float ab_cosTheta = dot(a,b);
float ab_pow2 = dot(a,a) * dot(b,b);
return (ab_pow2 == 0.0) ? 1.0 : clamp(ab_cosTheta * inversesqrt(ab_pow2), -1.0, 1.0);
@@ -115,6 +116,8 @@
B = E - C;
A = fma(float2(-3), E, D);
}
+ // FIXME(crbug.com/800804,skbug.com/11268): Consider normalizing the exponents in A,B,C at
+ // this point in order to prevent fp32 overflow.
// Now find the coefficients that give a tangent direction from a parametric edge ID:
//
@@ -133,6 +136,7 @@
//
float lastParametricEdgeID = 0.0;
float maxParametricEdgeID = min(numParametricSegments - 1.0, combinedEdgeID);
+ // FIXME(crbug.com/800804,skbug.com/11268): This normalize() can overflow.
float2 tan0norm = normalize(tan0);
float negAbsRadsPerSegment = -abs(radsPerSegment);
float maxRotation0 = (1.0 + combinedEdgeID) * abs(radsPerSegment);
@@ -230,6 +234,7 @@
})", shader.maxParametricSegments_log2() /* Parametric/radial sort loop count. */);
code->append(R"(
+ // FIXME(crbug.com/800804,skbug.com/11268): This normalize() can overflow.
float2 ortho = normalize(float2(tangent.y, -tangent.x));
strokeCoord += ortho * (STROKE_RADIUS * strokeOutset);)");