Use clipped bounds for tessellation heuristic

The heuristic estimates the fill cost of the path based on its bounds.
The goal is to use the inner triangulator for large paths with a low
vertex count so that filling is simpler (no stencil), but triangulation
cost is manageable.

Considering the unclipped bounds means that very large path coordinates
can mislead the heuristic into thinking there is substantial fill cost,
when in fact that's always bounded by the clip dimensions.

Bug: skia:12764
Change-Id: I9d14bbdd2b35df121b6a55d4a278656bf16ae8eb
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/488528
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
Michael Ludwig 2021-12-23 15:14:38 -05:00 committed by SkCQ
parent c1bc0205d9
commit bd05d877db

View File

@ -30,6 +30,7 @@ GrOp::Owner make_non_convex_fill_op(GrRecordingContext* rContext,
skgpu::v1::FillPathFlags fillPathFlags, skgpu::v1::FillPathFlags fillPathFlags,
GrAAType aaType, GrAAType aaType,
const SkRect& drawBounds, const SkRect& drawBounds,
const SkIRect& clipBounds,
const SkMatrix& viewMatrix, const SkMatrix& viewMatrix,
const SkPath& path, const SkPath& path,
GrPaint&& paint) { GrPaint&& paint) {
@ -40,19 +41,22 @@ GrOp::Owner make_non_convex_fill_op(GrRecordingContext* rContext,
// on the CPU. This is our fastest approach. It allows us to stencil only the curves, // on the CPU. This is our fastest approach. It allows us to stencil only the curves,
// and then fill the inner fan directly to the final render target, thus drawing the // and then fill the inner fan directly to the final render target, thus drawing the
// majority of pixels in a single render pass. // majority of pixels in a single render pass.
float gpuFragmentWork = drawBounds.height() * drawBounds.width(); SkRect clippedDrawBounds = SkRect::Make(clipBounds);
float cpuTessellationWork = numVerbs * SkNextLog2(numVerbs); // N log N. if (clippedDrawBounds.intersect(drawBounds)) {
constexpr static float kCpuWeight = 512; float gpuFragmentWork = clippedDrawBounds.height() * clippedDrawBounds.width();
constexpr static float kMinNumPixelsToTriangulate = 256 * 256; float cpuTessellationWork = numVerbs * SkNextLog2(numVerbs); // N log N.
if (cpuTessellationWork * kCpuWeight + kMinNumPixelsToTriangulate < gpuFragmentWork) { constexpr static float kCpuWeight = 512;
return GrOp::Make<skgpu::v1::PathInnerTriangulateOp>(rContext, constexpr static float kMinNumPixelsToTriangulate = 256 * 256;
viewMatrix, if (cpuTessellationWork * kCpuWeight + kMinNumPixelsToTriangulate < gpuFragmentWork) {
path, return GrOp::Make<skgpu::v1::PathInnerTriangulateOp>(rContext,
std::move(paint), viewMatrix,
aaType, path,
fillPathFlags, std::move(paint),
drawBounds); aaType,
} fillPathFlags,
drawBounds);
}
} // we should be clipped out when the GrClip is analyzed, so just return the default op
} }
return GrOp::Make<skgpu::v1::PathStencilCoverOp>(rContext, return GrOp::Make<skgpu::v1::PathStencilCoverOp>(rContext,
arena, arena,
@ -196,6 +200,7 @@ bool TessellationPathRenderer::onDrawPath(const DrawPathArgs& args) {
FillPathFlags::kNone, FillPathFlags::kNone,
args.fAAType, args.fAAType,
drawBounds, drawBounds,
*args.fClipConservativeBounds,
*args.fViewMatrix, *args.fViewMatrix,
path, path,
std::move(args.fPaint)); std::move(args.fPaint));
@ -254,6 +259,7 @@ void TessellationPathRenderer::onStencilPath(const StencilPathArgs& args) {
FillPathFlags::kStencilOnly, FillPathFlags::kStencilOnly,
aaType, aaType,
pathDevBounds, pathDevBounds,
*args.fClipConservativeBounds,
*args.fViewMatrix, *args.fViewMatrix,
path, path,
GrPaint()); GrPaint());