blob: 62b98534c399cb4c4959a07e3b7ed253e9655d01 [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
Chris Dalton078f8752020-07-30 19:50:46 -06008#include "src/gpu/tessellate/GrPathTessellateOp.h"
Chris Daltonb832ce62020-01-06 19:49:37 -07009
Chris Daltond081dce2020-01-23 12:09:04 -070010#include "src/gpu/GrEagerVertexAllocator.h"
Chris Daltone4652052021-01-21 18:31:28 -070011#include "src/gpu/GrInnerFanTriangulator.h"
Chris Daltonb832ce62020-01-06 19:49:37 -070012#include "src/gpu/GrOpFlushState.h"
Chris Daltone74cebe2020-09-24 09:32:54 -060013#include "src/gpu/GrRecordingContextPriv.h"
Chris Dalton5e1545f2020-09-25 16:24:03 -060014#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
Chris Dalton4328e922020-01-29 13:16:14 -070015#include "src/gpu/tessellate/GrFillPathShader.h"
Chris Daltonf5132a02020-04-27 23:40:03 -060016#include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h"
Chris Daltonf9aea7f2020-01-21 11:19:26 -070017#include "src/gpu/tessellate/GrStencilPathShader.h"
Chris Daltonb96995d2020-06-04 16:44:29 -060018#include "src/gpu/tessellate/GrTessellationPathRenderer.h"
Chris Daltonb96995d2020-06-04 16:44:29 -060019
20using OpFlags = GrTessellationPathRenderer::OpFlags;
Chris Daltonb5391d92020-05-24 14:55:54 -060021
Chris Daltonb0643342020-12-15 01:04:12 -070022void GrPathTessellateOp::visitProxies(const VisitProxyFunc& fn) const {
23 if (fPipelineForFills) {
24 fPipelineForFills->visitProxies(fn);
25 } else {
26 fProcessors.visitProxies(fn);
27 }
28}
29
Chris Dalton078f8752020-07-30 19:50:46 -060030GrPathTessellateOp::FixedFunctionFlags GrPathTessellateOp::fixedFunctionFlags() const {
Chris Daltonb832ce62020-01-06 19:49:37 -070031 auto flags = FixedFunctionFlags::kUsesStencil;
32 if (GrAAType::kNone != fAAType) {
33 flags |= FixedFunctionFlags::kUsesHWAA;
34 }
35 return flags;
36}
37
Chris Daltone74cebe2020-09-24 09:32:54 -060038void GrPathTessellateOp::onPrePrepare(GrRecordingContext* context,
Adlai Hollere2296f72020-11-19 13:41:26 -050039 const GrSurfaceProxyView& writeView, GrAppliedClip* clip,
Chris Daltone74cebe2020-09-24 09:32:54 -060040 const GrXferProcessor::DstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -050041 GrXferBarrierFlags renderPassXferBarriers,
42 GrLoadOp colorLoadOp) {
Chris Daltone74cebe2020-09-24 09:32:54 -060043 SkArenaAlloc* recordTimeAllocator = context->priv().recordTimeAllocator();
Chris Dalton5e1545f2020-09-25 16:24:03 -060044 GrAppliedHardClip hardClip = GrAppliedHardClip(
45 (clip) ? clip->hardClip() : GrAppliedHardClip::Disabled());
Chris Dalton5e1545f2020-09-25 16:24:03 -060046 PrePrepareArgs args{recordTimeAllocator, writeView, &hardClip, clip, &dstProxyView,
Chris Daltone4652052021-01-21 18:31:28 -070047 renderPassXferBarriers, colorLoadOp, context->priv().caps()};
Chris Dalton5e1545f2020-09-25 16:24:03 -060048
49 this->prePreparePrograms(args);
50
Chris Daltone74cebe2020-09-24 09:32:54 -060051 if (fStencilTrianglesProgram) {
52 context->priv().recordProgramInfo(fStencilTrianglesProgram);
53 }
54 if (fStencilCubicsProgram) {
55 context->priv().recordProgramInfo(fStencilCubicsProgram);
56 }
Chris Dalton5e1545f2020-09-25 16:24:03 -060057 if (fFillTrianglesProgram) {
58 context->priv().recordProgramInfo(fFillTrianglesProgram);
59 }
60 if (fFillPathProgram) {
61 context->priv().recordProgramInfo(fFillPathProgram);
62 }
Chris Daltone74cebe2020-09-24 09:32:54 -060063}
64
65void GrPathTessellateOp::prePreparePrograms(const PrePrepareArgs& args) {
Chris Daltond7177432021-01-15 13:12:50 -070066 using DrawInnerFan = GrPathIndirectTessellator::DrawInnerFan;
Chris Dalton4328e922020-01-29 13:16:14 -070067 int numVerbs = fPath.countVerbs();
68 if (numVerbs <= 0) {
69 return;
70 }
Chris Daltonb5391d92020-05-24 14:55:54 -060071
72 // First check if the path is large and/or simple enough that we can actually triangulate the
73 // inner polygon(s) on the CPU. This is our fastest approach. It allows us to stencil only the
74 // curves, and then fill the internal polygons directly to the final render target, thus drawing
75 // the majority of pixels in a single render pass.
76 SkScalar scales[2];
77 SkAssertResult(fViewMatrix.getMinMaxScales(scales)); // Will fail if perspective.
78 const SkRect& bounds = fPath.getBounds();
Chris Dalton4328e922020-01-29 13:16:14 -070079 float gpuFragmentWork = bounds.height() * scales[0] * bounds.width() * scales[1];
80 float cpuTessellationWork = (float)numVerbs * SkNextLog2(numVerbs); // N log N.
Chris Dalton70a0d2c2021-01-26 12:01:21 -070081 if (cpuTessellationWork * 500 + (256 * 256) < gpuFragmentWork) { // Don't try below 256x256.
Chris Dalton86d4cfd2020-11-03 13:51:21 -070082 bool isLinear;
Chris Dalton04f9cda2020-04-23 10:04:25 -060083 // This will fail if the inner triangles do not form a simple polygon (e.g., self
84 // intersection, double winding).
Chris Dalton86d4cfd2020-11-03 13:51:21 -070085 if (this->prePrepareInnerPolygonTriangulation(args, &isLinear)) {
86 if (!isLinear) {
Chris Daltone74cebe2020-09-24 09:32:54 -060087 // Always use indirect draws for cubics instead of tessellation here. Our goal in
88 // this mode is to maximize GPU performance, and the middle-out topology used by our
89 // indirect draws is easier on the rasterizer than a tessellated fan. There also
90 // seems to be a small amount of fixed tessellation overhead that this avoids.
91 this->prePrepareStencilCubicsProgram<GrMiddleOutCubicShader>(args);
Chris Dalton5e1545f2020-09-25 16:24:03 -060092 // We will need one final pass to cover the convex hulls of the cubics after
93 // drawing the inner triangles.
94 this->prePrepareFillCubicHullsProgram(args);
Chris Daltond7177432021-01-15 13:12:50 -070095 fTessellator = args.fArena->make<GrPathIndirectTessellator>(fViewMatrix, fPath,
96 DrawInnerFan::kNo);
Chris Daltonb5391d92020-05-24 14:55:54 -060097 }
Chris Dalton4328e922020-01-29 13:16:14 -070098 return;
99 }
100 }
101
Chris Dalton5e1545f2020-09-25 16:24:03 -0600102 // If we didn't triangulate the inner fan then the fill program will be a simple bounding box.
103 this->prePrepareFillBoundingBoxProgram(args);
104
Chris Daltonb5391d92020-05-24 14:55:54 -0600105 // When there are only a few verbs, it seems to always be fastest to make a single indirect draw
106 // that contains both the inner triangles and the outer cubics, instead of using hardware
107 // tessellation. Also take this path if tessellation is not supported.
108 bool drawTrianglesAsIndirectCubicDraw = (numVerbs < 50);
Chris Daltonb96995d2020-06-04 16:44:29 -0600109 if (drawTrianglesAsIndirectCubicDraw || (fOpFlags & OpFlags::kDisableHWTessellation)) {
Chris Daltone74cebe2020-09-24 09:32:54 -0600110 if (!drawTrianglesAsIndirectCubicDraw) {
111 this->prePrepareStencilTrianglesProgram(args);
112 }
113 this->prePrepareStencilCubicsProgram<GrMiddleOutCubicShader>(args);
Chris Daltond7177432021-01-15 13:12:50 -0700114 fTessellator = args.fArena->make<GrPathIndirectTessellator>(
115 fViewMatrix, fPath, DrawInnerFan(drawTrianglesAsIndirectCubicDraw));
Chris Daltonb5391d92020-05-24 14:55:54 -0600116 return;
117 }
118
Chris Daltonb96995d2020-06-04 16:44:29 -0600119 // The caller should have sent Flags::kDisableHWTessellation if it was not supported.
Chris Daltone74cebe2020-09-24 09:32:54 -0600120 SkASSERT(args.fCaps->shaderCaps()->tessellationSupport());
Chris Daltonb96995d2020-06-04 16:44:29 -0600121
Chris Daltonb5391d92020-05-24 14:55:54 -0600122 // Next see if we can split up the inner triangles and outer cubics into two draw calls. This
123 // allows for a more efficient inner triangle topology that can reduce the rasterizer load by a
124 // large margin on complex paths, but also causes greater CPU overhead due to the extra shader
125 // switches and draw calls.
Chris Dalton4328e922020-01-29 13:16:14 -0700126 // NOTE: Raster-edge work is 1-dimensional, so we sum height and width instead of multiplying.
127 float rasterEdgeWork = (bounds.height() + bounds.width()) * scales[1] * fPath.countVerbs();
Chris Daltonb5391d92020-05-24 14:55:54 -0600128 if (rasterEdgeWork > 300 * 300) {
Chris Daltone74cebe2020-09-24 09:32:54 -0600129 this->prePrepareStencilTrianglesProgram(args);
130 this->prePrepareStencilCubicsProgram<GrCubicTessellateShader>(args);
Chris Daltond7177432021-01-15 13:12:50 -0700131 fTessellator = args.fArena->make<GrPathOuterCurveTessellator>();
Chris Daltonf9aea7f2020-01-21 11:19:26 -0700132 return;
133 }
134
135 // Fastest CPU approach: emit one cubic wedge per verb, fanning out from the center.
Chris Daltone74cebe2020-09-24 09:32:54 -0600136 this->prePrepareStencilCubicsProgram<GrWedgeTessellateShader>(args);
Chris Daltond7177432021-01-15 13:12:50 -0700137 fTessellator = args.fArena->make<GrPathWedgeTessellator>();
Chris Daltonb832ce62020-01-06 19:49:37 -0700138}
139
Chris Daltone74cebe2020-09-24 09:32:54 -0600140bool GrPathTessellateOp::prePrepareInnerPolygonTriangulation(const PrePrepareArgs& args,
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700141 bool* isLinear) {
Chris Dalton04f9cda2020-04-23 10:04:25 -0600142 SkASSERT(!fTriangleBuffer);
Chris Daltone74cebe2020-09-24 09:32:54 -0600143 SkASSERT(fTriangleVertexCount == 0);
144 SkASSERT(!fStencilTrianglesProgram);
Chris Dalton5e1545f2020-09-25 16:24:03 -0600145 SkASSERT(!fFillTrianglesProgram);
Chris Dalton8a42b092021-01-21 22:09:26 -0700146 fInnerFanTriangulator = args.fArena->make<GrInnerFanTriangulator>(fPath, args.fArena, nullptr);
Chris Daltone4652052021-01-21 18:31:28 -0700147 fInnerFanPolys = fInnerFanTriangulator->pathToPolys(isLinear);
148 if (!fInnerFanPolys) {
149 // pathToPolys will fail if the inner polygon(s) are not simple.
Chris Dalton04f9cda2020-04-23 10:04:25 -0600150 return false;
151 }
Chris Dalton5e1545f2020-09-25 16:24:03 -0600152 if ((fOpFlags & (OpFlags::kStencilOnly | OpFlags::kWireframe)) ||
Chris Daltonb96995d2020-06-04 16:44:29 -0600153 GrAAType::kCoverage == fAAType ||
Chris Daltone74cebe2020-09-24 09:32:54 -0600154 (args.fClip && args.fClip->hasStencilClip())) {
Chris Dalton04f9cda2020-04-23 10:04:25 -0600155 // If we have certain flags, mixed samples, or a stencil clip then we unfortunately
156 // can't fill the inner polygon directly. Indicate that these triangles need to be
157 // stencilled.
Chris Daltone74cebe2020-09-24 09:32:54 -0600158 this->prePrepareStencilTrianglesProgram(args);
Chris Dalton04f9cda2020-04-23 10:04:25 -0600159 }
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700160 this->prePrepareFillTrianglesProgram(args, *isLinear);
Chris Dalton04f9cda2020-04-23 10:04:25 -0600161 return true;
162}
163
Chris Dalton1b6a43c2020-09-25 12:21:18 -0600164// Increments clockwise triangles and decrements counterclockwise. Used for "winding" fill.
165constexpr static GrUserStencilSettings kIncrDecrStencil(
166 GrUserStencilSettings::StaticInitSeparate<
167 0x0000, 0x0000,
168 GrUserStencilTest::kAlwaysIfInClip, GrUserStencilTest::kAlwaysIfInClip,
169 0xffff, 0xffff,
170 GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
171 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
172 0xffff, 0xffff>());
173
174// Inverts the bottom stencil bit. Used for "even/odd" fill.
175constexpr static GrUserStencilSettings kInvertStencil(
176 GrUserStencilSettings::StaticInit<
177 0x0000,
178 GrUserStencilTest::kAlwaysIfInClip,
179 0xffff,
180 GrUserStencilOp::kInvert,
181 GrUserStencilOp::kKeep,
182 0x0001>());
183
184constexpr static const GrUserStencilSettings* stencil_pass_settings(SkPathFillType fillType) {
185 return (fillType == SkPathFillType::kWinding) ? &kIncrDecrStencil : &kInvertStencil;
186}
187
Chris Daltone74cebe2020-09-24 09:32:54 -0600188void GrPathTessellateOp::prePrepareStencilTrianglesProgram(const PrePrepareArgs& args) {
189 SkASSERT(!fStencilTrianglesProgram);
Chris Dalton5e1545f2020-09-25 16:24:03 -0600190
191 this->prePreparePipelineForStencils(args);
192
Chris Daltone74cebe2020-09-24 09:32:54 -0600193 auto* shader = args.fArena->make<GrStencilTriangleShader>(fViewMatrix);
Chris Dalton1b6a43c2020-09-25 12:21:18 -0600194 fStencilTrianglesProgram = GrPathShader::MakeProgramInfo(
Chris Dalton5e1545f2020-09-25 16:24:03 -0600195 shader, args.fArena, args.fWriteView, fPipelineForStencils, *args.fDstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500196 args.fXferBarrierFlags, args.fColorLoadOp, stencil_pass_settings(fPath.getFillType()),
197 *args.fCaps);
Chris Daltone74cebe2020-09-24 09:32:54 -0600198}
199
200template<typename ShaderType>
201void GrPathTessellateOp::prePrepareStencilCubicsProgram(const PrePrepareArgs& args) {
202 SkASSERT(!fStencilCubicsProgram);
Chris Dalton5e1545f2020-09-25 16:24:03 -0600203
204 this->prePreparePipelineForStencils(args);
205
Chris Daltone74cebe2020-09-24 09:32:54 -0600206 auto* shader = args.fArena->make<ShaderType>(fViewMatrix);
Chris Dalton1b6a43c2020-09-25 12:21:18 -0600207 fStencilCubicsProgram = GrPathShader::MakeProgramInfo(
Chris Dalton5e1545f2020-09-25 16:24:03 -0600208 shader, args.fArena, args.fWriteView, fPipelineForStencils, *args.fDstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500209 args.fXferBarrierFlags, args.fColorLoadOp, stencil_pass_settings(fPath.getFillType()),
210 *args.fCaps);
Chris Daltone74cebe2020-09-24 09:32:54 -0600211}
212
Chris Dalton5e1545f2020-09-25 16:24:03 -0600213void GrPathTessellateOp::prePreparePipelineForStencils(const PrePrepareArgs& args) {
214 if (fPipelineForStencils) {
Chris Daltone74cebe2020-09-24 09:32:54 -0600215 return;
216 }
217
Chris Daltone74cebe2020-09-24 09:32:54 -0600218 GrPipeline::InitArgs initArgs;
219 if (GrAAType::kNone != fAAType) {
220 initArgs.fInputFlags |= GrPipeline::InputFlags::kHWAntialias;
221 }
222 if (args.fCaps->wireframeSupport() && (OpFlags::kWireframe & fOpFlags)) {
223 initArgs.fInputFlags |= GrPipeline::InputFlags::kWireframe;
224 }
225 SkASSERT(SkPathFillType::kWinding == fPath.getFillType() ||
226 SkPathFillType::kEvenOdd == fPath.getFillType());
Chris Daltone74cebe2020-09-24 09:32:54 -0600227 initArgs.fCaps = args.fCaps;
Chris Dalton5e1545f2020-09-25 16:24:03 -0600228 fPipelineForStencils = args.fArena->make<GrPipeline>(
229 initArgs, GrDisableColorXPFactory::MakeXferProcessor(), *args.fHardClip);
230}
231
232// Allows non-zero stencil values to pass and write a color, and resets the stencil value back to
233// zero; discards immediately on stencil values of zero.
234// NOTE: It's ok to not check the clip here because the previous stencil pass will have only written
235// to samples already inside the clip.
236constexpr static GrUserStencilSettings kTestAndResetStencil(
237 GrUserStencilSettings::StaticInit<
238 0x0000,
239 GrUserStencilTest::kNotEqual,
240 0xffff,
241 GrUserStencilOp::kZero,
242 GrUserStencilOp::kKeep,
243 0xffff>());
244
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700245void GrPathTessellateOp::prePrepareFillTrianglesProgram(const PrePrepareArgs& args, bool isLinear) {
Chris Dalton5e1545f2020-09-25 16:24:03 -0600246 SkASSERT(!fFillTrianglesProgram);
247
248 if (fOpFlags & OpFlags::kStencilOnly) {
249 return;
250 }
251
252 // These are a twist on the standard red book stencil settings that allow us to fill the inner
253 // polygon directly to the final render target. At this point, the curves are already stencilled
254 // in. So if the stencil value is zero, then it means the path at our sample is not affected by
255 // any curves and we fill the path in directly. If the stencil value is nonzero, then we don't
256 // fill and instead continue the standard red book stencil process.
257 //
258 // NOTE: These settings are currently incompatible with a stencil clip.
259 constexpr static GrUserStencilSettings kFillOrIncrDecrStencil(
260 GrUserStencilSettings::StaticInitSeparate<
261 0x0000, 0x0000,
262 GrUserStencilTest::kEqual, GrUserStencilTest::kEqual,
263 0xffff, 0xffff,
264 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
265 GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
266 0xffff, 0xffff>());
267
268 constexpr static GrUserStencilSettings kFillOrInvertStencil(
269 GrUserStencilSettings::StaticInit<
270 0x0000,
271 GrUserStencilTest::kEqual,
272 0xffff,
273 GrUserStencilOp::kKeep,
274 GrUserStencilOp::kZero,
275 0xffff>());
276
277 this->prePreparePipelineForFills(args);
278
279 const GrUserStencilSettings* stencil;
280 if (fStencilTrianglesProgram) {
281 // The path was already stencilled. Here we just need to do a cover pass.
282 stencil = &kTestAndResetStencil;
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700283 } else if (isLinear) {
Chris Dalton5e1545f2020-09-25 16:24:03 -0600284 // There are no stencilled curves. We can ignore stencil and fill the path directly.
285 stencil = &GrUserStencilSettings::kUnused;
286 } else if (SkPathFillType::kWinding == fPath.getFillType()) {
287 // Fill in the path pixels not touched by curves, incr/decr stencil otherwise.
288 SkASSERT(!fPipelineForFills->hasStencilClip());
289 stencil = &kFillOrIncrDecrStencil;
290 } else {
291 // Fill in the path pixels not touched by curves, invert stencil otherwise.
292 SkASSERT(!fPipelineForFills->hasStencilClip());
293 stencil = &kFillOrInvertStencil;
294 }
295
296 auto* fillTriangleShader = args.fArena->make<GrFillTriangleShader>(fViewMatrix, fColor);
297 fFillTrianglesProgram = GrPathShader::MakeProgramInfo(
298 fillTriangleShader, args.fArena, args.fWriteView, fPipelineForFills,
Greg Daniel42dbca52020-11-20 10:22:43 -0500299 *args.fDstProxyView, args.fXferBarrierFlags, args.fColorLoadOp, stencil, *args.fCaps);
Chris Dalton5e1545f2020-09-25 16:24:03 -0600300}
301
302void GrPathTessellateOp::prePrepareFillCubicHullsProgram(const PrePrepareArgs& args) {
303 SkASSERT(!fFillPathProgram);
304
305 if (fOpFlags & OpFlags::kStencilOnly) {
306 return;
307 }
308
309 this->prePreparePipelineForFills(args);
310
311 auto* fillCubicHullsShader = args.fArena->make<GrFillCubicHullShader>(fViewMatrix, fColor);
312 fFillPathProgram = GrPathShader::MakeProgramInfo(
313 fillCubicHullsShader, args.fArena, args.fWriteView, fPipelineForFills,
Greg Daniel42dbca52020-11-20 10:22:43 -0500314 *args.fDstProxyView, args.fXferBarrierFlags, args.fColorLoadOp, &kTestAndResetStencil,
315 *args.fCaps);
Chris Dalton5e1545f2020-09-25 16:24:03 -0600316}
317
318void GrPathTessellateOp::prePrepareFillBoundingBoxProgram(const PrePrepareArgs& args) {
319 SkASSERT(!fFillPathProgram);
320
321 if (fOpFlags & OpFlags::kStencilOnly) {
322 return;
323 }
324
325 this->prePreparePipelineForFills(args);
326
327 auto* fillBoundingBoxShader = args.fArena->make<GrFillBoundingBoxShader>(fViewMatrix, fColor,
328 fPath.getBounds());
329 fFillPathProgram = GrPathShader::MakeProgramInfo(
330 fillBoundingBoxShader, args.fArena, args.fWriteView, fPipelineForFills,
Greg Daniel42dbca52020-11-20 10:22:43 -0500331 *args.fDstProxyView, args.fXferBarrierFlags, args.fColorLoadOp, &kTestAndResetStencil,
332 *args.fCaps);
Chris Dalton5e1545f2020-09-25 16:24:03 -0600333}
334
335void GrPathTessellateOp::prePreparePipelineForFills(const PrePrepareArgs& args) {
336 SkASSERT(!(fOpFlags & OpFlags::kStencilOnly));
337
338 if (fPipelineForFills) {
339 return;
340 }
341
342 auto pipelineFlags = GrPipeline::InputFlags::kNone;
343 if (GrAAType::kNone != fAAType) {
Adlai Hollere2296f72020-11-19 13:41:26 -0500344 if (args.fWriteView.asRenderTargetProxy()->numSamples() == 1) {
Chris Dalton5e1545f2020-09-25 16:24:03 -0600345 // We are mixed sampled. We need to either enable conservative raster (preferred) or
346 // disable MSAA in order to avoid double blend artifacts. (Even if we disable MSAA for
347 // the cover geometry, the stencil test is still multisampled and will still produce
348 // smooth results.)
349 SkASSERT(GrAAType::kCoverage == fAAType);
350 if (args.fCaps->conservativeRasterSupport()) {
351 pipelineFlags |= GrPipeline::InputFlags::kHWAntialias;
352 pipelineFlags |= GrPipeline::InputFlags::kConservativeRaster;
353 }
354 } else {
355 // We are standard MSAA. Leave MSAA enabled for the cover geometry.
356 pipelineFlags |= GrPipeline::InputFlags::kHWAntialias;
357 }
358 }
359
360 fPipelineForFills = GrSimpleMeshDrawOpHelper::CreatePipeline(
Chris Daltonb0643342020-12-15 01:04:12 -0700361 args.fCaps, args.fArena, args.fWriteView.swizzle(),
362 (args.fClip) ? std::move(*args.fClip) : GrAppliedClip::Disabled(), *args.fDstProxyView,
363 std::move(fProcessors), pipelineFlags);
Chris Daltone74cebe2020-09-24 09:32:54 -0600364}
365
366void GrPathTessellateOp::onPrepare(GrOpFlushState* flushState) {
367 int numVerbs = fPath.countVerbs();
368 if (numVerbs <= 0) {
369 return;
370 }
371
Chris Dalton5e1545f2020-09-25 16:24:03 -0600372 if (!fPipelineForStencils && !fPipelineForFills) {
Chris Daltone74cebe2020-09-24 09:32:54 -0600373 // Nothing has been prePrepared yet. Do it now.
Chris Dalton5e1545f2020-09-25 16:24:03 -0600374 GrAppliedHardClip hardClip = GrAppliedHardClip(flushState->appliedHardClip());
375 GrAppliedClip clip = flushState->detachAppliedClip();
376 PrePrepareArgs args{flushState->allocator(), flushState->writeView(), &hardClip,
377 &clip, &flushState->dstProxyView(),
Greg Daniel42dbca52020-11-20 10:22:43 -0500378 flushState->renderPassBarriers(), flushState->colorLoadOp(),
Chris Daltone4652052021-01-21 18:31:28 -0700379 &flushState->caps()};
Chris Dalton5e1545f2020-09-25 16:24:03 -0600380 this->prePreparePrograms(args);
Chris Daltone74cebe2020-09-24 09:32:54 -0600381 }
382
Chris Daltone4652052021-01-21 18:31:28 -0700383 if (fInnerFanPolys) {
Chris Daltone74cebe2020-09-24 09:32:54 -0600384 // prePreparePrograms was able to generate an inner polygon triangulation. It will exist in
385 // either fOffThreadInnerTriangulation or fTriangleBuffer exclusively.
Chris Daltone4652052021-01-21 18:31:28 -0700386 SkASSERT(fInnerFanTriangulator);
387 GrEagerDynamicVertexAllocator alloc(flushState, &fTriangleBuffer, &fBaseTriangleVertex);
388 fTriangleVertexCount = fInnerFanTriangulator->polysToTriangles(fInnerFanPolys, &alloc);
Chris Daltond7177432021-01-15 13:12:50 -0700389 } else if (fStencilTrianglesProgram) {
390 // The inner fan isn't built into the tessellator. Generate a standard Redbook fan with a
391 // middle-out topology.
392 GrEagerDynamicVertexAllocator vertexAlloc(flushState, &fTriangleBuffer,
393 &fBaseTriangleVertex);
394 // No initial moveTo, plus an implicit close at the end; n-2 triangles fill an n-gon.
395 int maxInnerTriangles = fPath.countVerbs() - 1;
396 auto* triangleVertexData = vertexAlloc.lock<SkPoint>(maxInnerTriangles * 3);
397 fTriangleVertexCount = GrMiddleOutPolygonTriangulator::WritePathInnerFan(
398 triangleVertexData, 3/*perTriangleVertexAdvance*/, fPath) * 3;
399 vertexAlloc.unlock(fTriangleVertexCount);
Chris Daltone74cebe2020-09-24 09:32:54 -0600400 }
401
Chris Daltond7177432021-01-15 13:12:50 -0700402 if (fTessellator) {
403 fTessellator->prepare(flushState, fViewMatrix, fPath);
Chris Daltone74cebe2020-09-24 09:32:54 -0600404 }
Chris Dalton42915c22020-04-22 16:24:43 -0600405}
406
Chris Dalton078f8752020-07-30 19:50:46 -0600407void GrPathTessellateOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
Chris Daltonb5391d92020-05-24 14:55:54 -0600408 this->drawStencilPass(flushState);
Chris Dalton5e1545f2020-09-25 16:24:03 -0600409 this->drawCoverPass(flushState);
Chris Daltonb832ce62020-01-06 19:49:37 -0700410}
411
Chris Dalton078f8752020-07-30 19:50:46 -0600412void GrPathTessellateOp::drawStencilPass(GrOpFlushState* flushState) {
Chris Daltone74cebe2020-09-24 09:32:54 -0600413 if (fStencilTrianglesProgram && fTriangleVertexCount > 0) {
Chris Dalton04f9cda2020-04-23 10:04:25 -0600414 SkASSERT(fTriangleBuffer);
Chris Daltone74cebe2020-09-24 09:32:54 -0600415 flushState->bindPipelineAndScissorClip(*fStencilTrianglesProgram, this->bounds());
Chris Dalton85138672020-07-24 08:47:03 -0600416 flushState->bindBuffers(nullptr, nullptr, fTriangleBuffer);
Chris Daltonb5391d92020-05-24 14:55:54 -0600417 flushState->draw(fTriangleVertexCount, fBaseTriangleVertex);
Chris Daltonf9aea7f2020-01-21 11:19:26 -0700418 }
419
Chris Daltond7177432021-01-15 13:12:50 -0700420 if (fTessellator) {
Chris Daltone74cebe2020-09-24 09:32:54 -0600421 flushState->bindPipelineAndScissorClip(*fStencilCubicsProgram, this->bounds());
Chris Daltond7177432021-01-15 13:12:50 -0700422 fTessellator->draw(flushState);
Chris Daltonb832ce62020-01-06 19:49:37 -0700423 }
424}
425
Chris Dalton078f8752020-07-30 19:50:46 -0600426void GrPathTessellateOp::drawCoverPass(GrOpFlushState* flushState) {
Chris Dalton5e1545f2020-09-25 16:24:03 -0600427 if (fFillTrianglesProgram) {
Chris Dalton04f9cda2020-04-23 10:04:25 -0600428 SkASSERT(fTriangleBuffer);
Chris Daltonb832ce62020-01-06 19:49:37 -0700429
Chris Dalton5e1545f2020-09-25 16:24:03 -0600430 // We have a triangulation of the path's inner polygon. This is the fast path. Fill those
431 // triangles directly to the screen.
Chris Daltone4652052021-01-21 18:31:28 -0700432 if (fTriangleVertexCount > 0) {
433 flushState->bindPipelineAndScissorClip(*fFillTrianglesProgram, this->bounds());
434 flushState->bindTextures(fFillTrianglesProgram->primProc(), nullptr,
435 *fPipelineForFills);
436 flushState->bindBuffers(nullptr, nullptr, fTriangleBuffer);
437 flushState->draw(fTriangleVertexCount, fBaseTriangleVertex);
438 }
Chris Dalton04f9cda2020-04-23 10:04:25 -0600439
Chris Daltond7177432021-01-15 13:12:50 -0700440 if (fTessellator) {
Chris Dalton5e1545f2020-09-25 16:24:03 -0600441 // At this point, every pixel is filled in except the ones touched by curves.
442 // fFillPathProgram will issue a final cover pass over the curves by drawing their
443 // convex hulls. This will fill in any remaining samples and reset the stencil buffer.
Chris Daltond7177432021-01-15 13:12:50 -0700444 SkASSERT(fFillPathProgram);
Chris Dalton5e1545f2020-09-25 16:24:03 -0600445 flushState->bindPipelineAndScissorClip(*fFillPathProgram, this->bounds());
446 flushState->bindTextures(fFillPathProgram->primProc(), nullptr, *fPipelineForFills);
Chris Daltond7177432021-01-15 13:12:50 -0700447 fTessellator->drawHullInstances(flushState);
Chris Dalton4328e922020-01-29 13:16:14 -0700448 }
Chris Dalton5e1545f2020-09-25 16:24:03 -0600449 } else if (fFillPathProgram) {
450 // There are no triangles to fill. Just draw a bounding box.
451 flushState->bindPipelineAndScissorClip(*fFillPathProgram, this->bounds());
452 flushState->bindTextures(fFillPathProgram->primProc(), nullptr, *fPipelineForFills);
453 flushState->bindBuffers(nullptr, nullptr, nullptr);
454 flushState->draw(4, 0);
Chris Dalton4328e922020-01-29 13:16:14 -0700455 }
Chris Daltonb832ce62020-01-06 19:49:37 -0700456}