blob: 28ed003c3554a384840014d31b76af9578f616cb [file] [log] [blame]
Chris Daltonb832ce62020-01-06 19:49:37 -07001/*
2 * Copyright 2019 Google LLC.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Robert Phillipse453fa02021-08-19 14:57:05 -04008#include "src/gpu/ops/TessellationPathRenderer.h"
Chris Daltonb832ce62020-01-06 19:49:37 -07009
Chris Dalton50c3c242021-06-14 16:32:35 -060010#include "include/private/SkVx.h"
Chris Daltonb832ce62020-01-06 19:49:37 -070011#include "src/core/SkPathPriv.h"
12#include "src/gpu/GrClip.h"
13#include "src/gpu/GrMemoryPool.h"
14#include "src/gpu/GrRecordingContextPriv.h"
Chris Dalton50c3c242021-06-14 16:32:35 -060015#include "src/gpu/GrVx.h"
Robert Phillips550de7f2021-07-06 16:28:52 -040016#include "src/gpu/effects/GrDisableColorXP.h"
Michael Ludwig2686d692020-04-17 20:21:37 +000017#include "src/gpu/geometry/GrStyledShape.h"
Robert Phillipse453fa02021-08-19 14:57:05 -040018#include "src/gpu/ops/PathInnerTriangulateOp.h"
19#include "src/gpu/ops/PathStencilCoverOp.h"
20#include "src/gpu/ops/PathTessellateOp.h"
21#include "src/gpu/ops/StrokeTessellateOp.h"
Robert Phillips4dca8312021-07-28 15:13:20 -040022#include "src/gpu/v1/SurfaceDrawContext_v1.h"
Chris Daltond2dc8dd2020-05-19 16:32:02 -060023
Chris Dalton1413d112020-07-09 11:26:31 -060024bool GrTessellationPathRenderer::IsSupported(const GrCaps& caps) {
Chris Dalton8f282f52021-01-06 11:47:58 -070025 return !caps.avoidStencilBuffers() &&
26 caps.drawInstancedSupport() &&
Chris Daltoneae5c162020-12-29 10:18:21 -070027 !caps.disableTessellationPathRenderer();
Chris Dalton1413d112020-07-09 11:26:31 -060028}
29
Robert Phillipsdb0ec082021-08-19 12:30:12 -040030skgpu::v1::PathRenderer::StencilSupport GrTessellationPathRenderer::onGetStencilSupport(
Chris Dalton7ae272f2021-06-10 11:45:14 -060031 const GrStyledShape& shape) const {
Chris Daltonbaae2dd2021-06-25 14:52:49 -060032 if (!shape.style().isSimpleFill() || shape.inverseFilled()) {
33 // Don't bother with stroke stencilling or inverse fills yet. The Skia API doesn't support
34 // clipping by a stroke, and the stencilling code already knows how to invert a fill.
Chris Dalton7ae272f2021-06-10 11:45:14 -060035 return kNoSupport_StencilSupport;
36 }
37 return shape.knownToBeConvex() ? kNoRestriction_StencilSupport : kStencilOnly_StencilSupport;
38}
39
Robert Phillipsdb0ec082021-08-19 12:30:12 -040040skgpu::v1::PathRenderer::CanDrawPath GrTessellationPathRenderer::onCanDrawPath(
Chris Daltonb832ce62020-01-06 19:49:37 -070041 const CanDrawPathArgs& args) const {
Chris Dalton1c62a7b2020-06-29 22:01:14 -060042 const GrStyledShape& shape = *args.fShape;
Chris Dalton57ab06c2021-04-22 12:57:28 -060043 if (args.fAAType == GrAAType::kCoverage ||
44 shape.style().hasPathEffect() ||
Chris Dalton06b52ad2020-12-15 10:01:35 -070045 args.fViewMatrix->hasPerspective() ||
46 shape.style().strokeRec().getStyle() == SkStrokeRec::kStrokeAndFill_Style ||
Chris Dalton537293bf2021-05-03 15:54:24 -060047 !args.fProxy->canUseStencil(*args.fCaps)) {
Chris Daltonb832ce62020-01-06 19:49:37 -070048 return CanDrawPath::kNo;
49 }
Chris Daltona05ccc32021-06-29 19:42:13 -060050 if (!shape.style().isSimpleFill()) {
Chris Daltonbb995e62021-07-01 10:58:55 -060051 if (shape.inverseFilled()) {
Chris Daltona05ccc32021-06-29 19:42:13 -060052 return CanDrawPath::kNo;
53 }
54 }
Chris Dalton7ae272f2021-06-10 11:45:14 -060055 if (args.fHasUserStencilSettings) {
56 // Non-convex paths and strokes use the stencil buffer internally, so they can't support
57 // draws with stencil settings.
Chris Daltonbaae2dd2021-06-25 14:52:49 -060058 if (!shape.style().isSimpleFill() || !shape.knownToBeConvex() || shape.inverseFilled()) {
Chris Dalton7ae272f2021-06-10 11:45:14 -060059 return CanDrawPath::kNo;
60 }
61 }
Chris Daltonb832ce62020-01-06 19:49:37 -070062 return CanDrawPath::kYes;
63}
64
Chris Dalton7ae272f2021-06-10 11:45:14 -060065static GrOp::Owner make_non_convex_fill_op(GrRecordingContext* rContext,
Chris Dalton8a1bbaa2021-07-28 14:43:07 -060066 SkArenaAlloc* arena,
Robert Phillips832f3fb2021-08-18 13:05:15 -040067 GrTessellationPathFlags pathFlags,
Chris Dalton8a1bbaa2021-07-28 14:43:07 -060068 GrAAType aaType,
69 const SkRect& drawBounds,
70 const SkMatrix& viewMatrix,
71 const SkPath& path,
Chris Dalton7ae272f2021-06-10 11:45:14 -060072 GrPaint&& paint) {
Chris Daltonbaae2dd2021-06-25 14:52:49 -060073 SkASSERT(!path.isConvex() || path.isInverseFillType());
Chris Dalton7ae272f2021-06-10 11:45:14 -060074 int numVerbs = path.countVerbs();
Chris Daltonbaae2dd2021-06-25 14:52:49 -060075 if (numVerbs > 0 && !path.isInverseFillType()) {
Chris Dalton7ae272f2021-06-10 11:45:14 -060076 // Check if the path is large and/or simple enough that we can triangulate the inner fan
77 // on the CPU. This is our fastest approach. It allows us to stencil only the curves,
78 // and then fill the inner fan directly to the final render target, thus drawing the
79 // majority of pixels in a single render pass.
Chris Daltonbaae2dd2021-06-25 14:52:49 -060080 float gpuFragmentWork = drawBounds.height() * drawBounds.width();
Chris Dalton7ae272f2021-06-10 11:45:14 -060081 float cpuTessellationWork = numVerbs * SkNextLog2(numVerbs); // N log N.
82 constexpr static float kCpuWeight = 512;
83 constexpr static float kMinNumPixelsToTriangulate = 256 * 256;
84 if (cpuTessellationWork * kCpuWeight + kMinNumPixelsToTriangulate < gpuFragmentWork) {
Chris Dalton8a1bbaa2021-07-28 14:43:07 -060085 return GrOp::Make<GrPathInnerTriangulateOp>(rContext,
86 viewMatrix,
87 path,
88 std::move(paint),
89 aaType,
90 pathFlags,
Chris Daltonbaae2dd2021-06-25 14:52:49 -060091 drawBounds);
Chris Dalton70a0d2c2021-01-26 12:01:21 -070092 }
Chris Daltonc2a17462020-12-09 16:46:22 -070093 }
Chris Dalton8a1bbaa2021-07-28 14:43:07 -060094 return GrOp::Make<GrPathStencilCoverOp>(rContext,
95 arena,
96 viewMatrix,
97 path,
98 std::move(paint),
99 aaType,
100 pathFlags,
101 drawBounds);
Chris Daltonc2a17462020-12-09 16:46:22 -0700102}
103
Chris Dalton0a22b1e2020-03-26 11:52:15 -0600104bool GrTessellationPathRenderer::onDrawPath(const DrawPathArgs& args) {
Robert Phillips4dca8312021-07-28 15:13:20 -0400105 auto sdc = args.fSurfaceDrawContext;
Chris Daltonb832ce62020-01-06 19:49:37 -0700106
Chris Dalton7ae272f2021-06-10 11:45:14 -0600107 SkPath path;
108 args.fShape->asPath(&path);
109
110 // Handle strokes first.
111 if (!args.fShape->style().isSimpleFill()) {
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600112 SkASSERT(!path.isInverseFillType()); // See onGetStencilSupport().
Chris Dalton7ae272f2021-06-10 11:45:14 -0600113 SkASSERT(args.fUserStencilSettings->isUnused());
114 const SkStrokeRec& stroke = args.fShape->style().strokeRec();
115 SkASSERT(stroke.getStyle() != SkStrokeRec::kStrokeAndFill_Style);
116 auto op = GrOp::Make<GrStrokeTessellateOp>(args.fContext, args.fAAType, *args.fViewMatrix,
117 path, stroke, std::move(args.fPaint));
Robert Phillips4dca8312021-07-28 15:13:20 -0400118 sdc->addDrawOp(args.fClip, std::move(op));
Chris Dalton7ae272f2021-06-10 11:45:14 -0600119 return true;
120 }
121
Chris Daltonc3176002021-07-23 15:33:09 -0600122 // Handle empty paths.
Chris Dalton2346aa02021-07-14 22:55:35 -0600123 const SkRect pathDevBounds = args.fViewMatrix->mapRect(args.fShape->bounds());
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600124 if (pathDevBounds.isEmpty()) {
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600125 if (path.isInverseFillType()) {
126 args.fSurfaceDrawContext->drawPaint(args.fClip, std::move(args.fPaint),
127 *args.fViewMatrix);
128 }
129 return true;
130 }
Chris Daltonb96995d2020-06-04 16:44:29 -0600131
Chris Daltonc3176002021-07-23 15:33:09 -0600132 // Handle convex paths.
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600133 if (args.fShape->knownToBeConvex() && !path.isInverseFillType()) {
Chris Dalton7ae272f2021-06-10 11:45:14 -0600134 auto op = GrOp::Make<GrPathTessellateOp>(args.fContext, *args.fViewMatrix, path,
135 std::move(args.fPaint), args.fAAType,
136 args.fUserStencilSettings, pathDevBounds);
Robert Phillips4dca8312021-07-28 15:13:20 -0400137 sdc->addDrawOp(args.fClip, std::move(op));
Chris Dalton7ae272f2021-06-10 11:45:14 -0600138 return true;
Chris Daltonb96995d2020-06-04 16:44:29 -0600139 }
Chris Dalton7ae272f2021-06-10 11:45:14 -0600140
141 SkASSERT(args.fUserStencilSettings->isUnused()); // See onGetStencilSupport().
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600142 const SkRect& drawBounds = path.isInverseFillType()
143 ? args.fSurfaceDrawContext->asSurfaceProxy()->backingStoreBoundsRect()
144 : pathDevBounds;
Chris Dalton8a1bbaa2021-07-28 14:43:07 -0600145 auto op = make_non_convex_fill_op(args.fContext,
146 args.fSurfaceDrawContext->arenaAlloc(),
Robert Phillips832f3fb2021-08-18 13:05:15 -0400147 GrTessellationPathFlags::kNone,
Chris Dalton8a1bbaa2021-07-28 14:43:07 -0600148 args.fAAType,
149 drawBounds,
150 *args.fViewMatrix,
151 path,
152 std::move(args.fPaint));
Robert Phillips4dca8312021-07-28 15:13:20 -0400153 sdc->addDrawOp(args.fClip, std::move(op));
Chris Dalton4e998532020-02-10 11:06:42 -0700154 return true;
155}
156
Chris Dalton7ae272f2021-06-10 11:45:14 -0600157void GrTessellationPathRenderer::onStencilPath(const StencilPathArgs& args) {
158 SkASSERT(args.fShape->style().isSimpleFill()); // See onGetStencilSupport().
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600159 SkASSERT(!args.fShape->inverseFilled()); // See onGetStencilSupport().
Chris Dalton7ae272f2021-06-10 11:45:14 -0600160
Robert Phillips4dca8312021-07-28 15:13:20 -0400161 auto sdc = args.fSurfaceDrawContext;
Chris Dalton7ae272f2021-06-10 11:45:14 -0600162 GrAAType aaType = (GrAA::kYes == args.fDoStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone;
163
164 SkRect pathDevBounds;
165 args.fViewMatrix->mapRect(&pathDevBounds, args.fShape->bounds());
166
167 SkPath path;
168 args.fShape->asPath(&path);
169
170 if (args.fShape->knownToBeConvex()) {
171 constexpr static GrUserStencilSettings kMarkStencil(
172 GrUserStencilSettings::StaticInit<
173 0x0001,
174 GrUserStencilTest::kAlways,
175 0xffff,
176 GrUserStencilOp::kReplace,
177 GrUserStencilOp::kKeep,
178 0xffff>());
179
180 GrPaint stencilPaint;
181 stencilPaint.setXPFactory(GrDisableColorXPFactory::Get());
182 auto op = GrOp::Make<GrPathTessellateOp>(args.fContext, *args.fViewMatrix, path,
183 std::move(stencilPaint), aaType, &kMarkStencil,
184 pathDevBounds);
Robert Phillips4dca8312021-07-28 15:13:20 -0400185 sdc->addDrawOp(args.fClip, std::move(op));
Chris Dalton7ae272f2021-06-10 11:45:14 -0600186 return;
Chris Daltonb0643342020-12-15 01:04:12 -0700187 }
188
Chris Dalton8a1bbaa2021-07-28 14:43:07 -0600189 auto op = make_non_convex_fill_op(args.fContext,
190 args.fSurfaceDrawContext->arenaAlloc(),
Robert Phillips832f3fb2021-08-18 13:05:15 -0400191 GrTessellationPathFlags::kStencilOnly,
Chris Dalton8a1bbaa2021-07-28 14:43:07 -0600192 aaType,
193 pathDevBounds,
194 *args.fViewMatrix,
195 path,
196 GrPaint());
Robert Phillips4dca8312021-07-28 15:13:20 -0400197 sdc->addDrawOp(args.fClip, std::move(op));
Chris Dalton7ae272f2021-06-10 11:45:14 -0600198}