blob: 5c78c5d6fea50144e445abe3cf48688718aa5410 [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 Daltonb67a3362021-01-21 22:06:04 -070081 if (!(fOpFlags & OpFlags::kDisableInnerFanTriangulation) &&
82 cpuTessellationWork * 500 + (256 * 256) < gpuFragmentWork) { // Don't try below 256x256.
Chris Dalton86d4cfd2020-11-03 13:51:21 -070083 bool isLinear;
Chris Dalton04f9cda2020-04-23 10:04:25 -060084 // This will fail if the inner triangles do not form a simple polygon (e.g., self
85 // intersection, double winding).
Chris Dalton86d4cfd2020-11-03 13:51:21 -070086 if (this->prePrepareInnerPolygonTriangulation(args, &isLinear)) {
87 if (!isLinear) {
Chris Daltone74cebe2020-09-24 09:32:54 -060088 // Always use indirect draws for cubics instead of tessellation here. Our goal in
89 // this mode is to maximize GPU performance, and the middle-out topology used by our
90 // indirect draws is easier on the rasterizer than a tessellated fan. There also
91 // seems to be a small amount of fixed tessellation overhead that this avoids.
92 this->prePrepareStencilCubicsProgram<GrMiddleOutCubicShader>(args);
Chris Dalton5e1545f2020-09-25 16:24:03 -060093 // We will need one final pass to cover the convex hulls of the cubics after
94 // drawing the inner triangles.
95 this->prePrepareFillCubicHullsProgram(args);
Chris Daltond7177432021-01-15 13:12:50 -070096 fTessellator = args.fArena->make<GrPathIndirectTessellator>(fViewMatrix, fPath,
97 DrawInnerFan::kNo);
Chris Daltonb5391d92020-05-24 14:55:54 -060098 }
Chris Dalton4328e922020-01-29 13:16:14 -070099 return;
100 }
101 }
102
Chris Dalton5e1545f2020-09-25 16:24:03 -0600103 // If we didn't triangulate the inner fan then the fill program will be a simple bounding box.
104 this->prePrepareFillBoundingBoxProgram(args);
105
Chris Daltonb5391d92020-05-24 14:55:54 -0600106 // When there are only a few verbs, it seems to always be fastest to make a single indirect draw
107 // that contains both the inner triangles and the outer cubics, instead of using hardware
108 // tessellation. Also take this path if tessellation is not supported.
109 bool drawTrianglesAsIndirectCubicDraw = (numVerbs < 50);
Chris Daltonb96995d2020-06-04 16:44:29 -0600110 if (drawTrianglesAsIndirectCubicDraw || (fOpFlags & OpFlags::kDisableHWTessellation)) {
Chris Daltone74cebe2020-09-24 09:32:54 -0600111 if (!drawTrianglesAsIndirectCubicDraw) {
112 this->prePrepareStencilTrianglesProgram(args);
113 }
114 this->prePrepareStencilCubicsProgram<GrMiddleOutCubicShader>(args);
Chris Daltond7177432021-01-15 13:12:50 -0700115 fTessellator = args.fArena->make<GrPathIndirectTessellator>(
116 fViewMatrix, fPath, DrawInnerFan(drawTrianglesAsIndirectCubicDraw));
Chris Daltonb5391d92020-05-24 14:55:54 -0600117 return;
118 }
119
Chris Daltonb96995d2020-06-04 16:44:29 -0600120 // The caller should have sent Flags::kDisableHWTessellation if it was not supported.
Chris Daltone74cebe2020-09-24 09:32:54 -0600121 SkASSERT(args.fCaps->shaderCaps()->tessellationSupport());
Chris Daltonb96995d2020-06-04 16:44:29 -0600122
Chris Daltonb5391d92020-05-24 14:55:54 -0600123 // Next see if we can split up the inner triangles and outer cubics into two draw calls. This
124 // allows for a more efficient inner triangle topology that can reduce the rasterizer load by a
125 // large margin on complex paths, but also causes greater CPU overhead due to the extra shader
126 // switches and draw calls.
Chris Dalton4328e922020-01-29 13:16:14 -0700127 // NOTE: Raster-edge work is 1-dimensional, so we sum height and width instead of multiplying.
128 float rasterEdgeWork = (bounds.height() + bounds.width()) * scales[1] * fPath.countVerbs();
Chris Daltonb5391d92020-05-24 14:55:54 -0600129 if (rasterEdgeWork > 300 * 300) {
Chris Daltone74cebe2020-09-24 09:32:54 -0600130 this->prePrepareStencilTrianglesProgram(args);
131 this->prePrepareStencilCubicsProgram<GrCubicTessellateShader>(args);
Chris Daltond7177432021-01-15 13:12:50 -0700132 fTessellator = args.fArena->make<GrPathOuterCurveTessellator>();
Chris Daltonf9aea7f2020-01-21 11:19:26 -0700133 return;
134 }
135
136 // Fastest CPU approach: emit one cubic wedge per verb, fanning out from the center.
Chris Daltone74cebe2020-09-24 09:32:54 -0600137 this->prePrepareStencilCubicsProgram<GrWedgeTessellateShader>(args);
Chris Daltond7177432021-01-15 13:12:50 -0700138 fTessellator = args.fArena->make<GrPathWedgeTessellator>();
Chris Daltonb832ce62020-01-06 19:49:37 -0700139}
140
Chris Daltone74cebe2020-09-24 09:32:54 -0600141bool GrPathTessellateOp::prePrepareInnerPolygonTriangulation(const PrePrepareArgs& args,
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700142 bool* isLinear) {
Chris Dalton04f9cda2020-04-23 10:04:25 -0600143 SkASSERT(!fTriangleBuffer);
Chris Daltone74cebe2020-09-24 09:32:54 -0600144 SkASSERT(fTriangleVertexCount == 0);
145 SkASSERT(!fStencilTrianglesProgram);
Chris Dalton5e1545f2020-09-25 16:24:03 -0600146 SkASSERT(!fFillTrianglesProgram);
Chris Daltone4652052021-01-21 18:31:28 -0700147 fInnerFanTriangulator = args.fArena->make<GrInnerFanTriangulator>(fPath, nullptr);
148 fInnerFanPolys = fInnerFanTriangulator->pathToPolys(isLinear);
149 if (!fInnerFanPolys) {
150 // pathToPolys will fail if the inner polygon(s) are not simple.
Chris Dalton04f9cda2020-04-23 10:04:25 -0600151 return false;
152 }
Chris Dalton5e1545f2020-09-25 16:24:03 -0600153 if ((fOpFlags & (OpFlags::kStencilOnly | OpFlags::kWireframe)) ||
Chris Daltonb96995d2020-06-04 16:44:29 -0600154 GrAAType::kCoverage == fAAType ||
Chris Daltone74cebe2020-09-24 09:32:54 -0600155 (args.fClip && args.fClip->hasStencilClip())) {
Chris Dalton04f9cda2020-04-23 10:04:25 -0600156 // If we have certain flags, mixed samples, or a stencil clip then we unfortunately
157 // can't fill the inner polygon directly. Indicate that these triangles need to be
158 // stencilled.
Chris Daltone74cebe2020-09-24 09:32:54 -0600159 this->prePrepareStencilTrianglesProgram(args);
Chris Dalton04f9cda2020-04-23 10:04:25 -0600160 }
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700161 this->prePrepareFillTrianglesProgram(args, *isLinear);
Chris Dalton04f9cda2020-04-23 10:04:25 -0600162 return true;
163}
164
Chris Dalton1b6a43c2020-09-25 12:21:18 -0600165// Increments clockwise triangles and decrements counterclockwise. Used for "winding" fill.
166constexpr static GrUserStencilSettings kIncrDecrStencil(
167 GrUserStencilSettings::StaticInitSeparate<
168 0x0000, 0x0000,
169 GrUserStencilTest::kAlwaysIfInClip, GrUserStencilTest::kAlwaysIfInClip,
170 0xffff, 0xffff,
171 GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
172 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
173 0xffff, 0xffff>());
174
175// Inverts the bottom stencil bit. Used for "even/odd" fill.
176constexpr static GrUserStencilSettings kInvertStencil(
177 GrUserStencilSettings::StaticInit<
178 0x0000,
179 GrUserStencilTest::kAlwaysIfInClip,
180 0xffff,
181 GrUserStencilOp::kInvert,
182 GrUserStencilOp::kKeep,
183 0x0001>());
184
185constexpr static const GrUserStencilSettings* stencil_pass_settings(SkPathFillType fillType) {
186 return (fillType == SkPathFillType::kWinding) ? &kIncrDecrStencil : &kInvertStencil;
187}
188
Chris Daltone74cebe2020-09-24 09:32:54 -0600189void GrPathTessellateOp::prePrepareStencilTrianglesProgram(const PrePrepareArgs& args) {
190 SkASSERT(!fStencilTrianglesProgram);
Chris Dalton5e1545f2020-09-25 16:24:03 -0600191
192 this->prePreparePipelineForStencils(args);
193
Chris Daltone74cebe2020-09-24 09:32:54 -0600194 auto* shader = args.fArena->make<GrStencilTriangleShader>(fViewMatrix);
Chris Dalton1b6a43c2020-09-25 12:21:18 -0600195 fStencilTrianglesProgram = GrPathShader::MakeProgramInfo(
Chris Dalton5e1545f2020-09-25 16:24:03 -0600196 shader, args.fArena, args.fWriteView, fPipelineForStencils, *args.fDstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500197 args.fXferBarrierFlags, args.fColorLoadOp, stencil_pass_settings(fPath.getFillType()),
198 *args.fCaps);
Chris Daltone74cebe2020-09-24 09:32:54 -0600199}
200
201template<typename ShaderType>
202void GrPathTessellateOp::prePrepareStencilCubicsProgram(const PrePrepareArgs& args) {
203 SkASSERT(!fStencilCubicsProgram);
Chris Dalton5e1545f2020-09-25 16:24:03 -0600204
205 this->prePreparePipelineForStencils(args);
206
Chris Daltone74cebe2020-09-24 09:32:54 -0600207 auto* shader = args.fArena->make<ShaderType>(fViewMatrix);
Chris Dalton1b6a43c2020-09-25 12:21:18 -0600208 fStencilCubicsProgram = GrPathShader::MakeProgramInfo(
Chris Dalton5e1545f2020-09-25 16:24:03 -0600209 shader, args.fArena, args.fWriteView, fPipelineForStencils, *args.fDstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500210 args.fXferBarrierFlags, args.fColorLoadOp, stencil_pass_settings(fPath.getFillType()),
211 *args.fCaps);
Chris Daltone74cebe2020-09-24 09:32:54 -0600212}
213
Chris Dalton5e1545f2020-09-25 16:24:03 -0600214void GrPathTessellateOp::prePreparePipelineForStencils(const PrePrepareArgs& args) {
215 if (fPipelineForStencils) {
Chris Daltone74cebe2020-09-24 09:32:54 -0600216 return;
217 }
218
Chris Daltone74cebe2020-09-24 09:32:54 -0600219 GrPipeline::InitArgs initArgs;
220 if (GrAAType::kNone != fAAType) {
221 initArgs.fInputFlags |= GrPipeline::InputFlags::kHWAntialias;
222 }
223 if (args.fCaps->wireframeSupport() && (OpFlags::kWireframe & fOpFlags)) {
224 initArgs.fInputFlags |= GrPipeline::InputFlags::kWireframe;
225 }
226 SkASSERT(SkPathFillType::kWinding == fPath.getFillType() ||
227 SkPathFillType::kEvenOdd == fPath.getFillType());
Chris Daltone74cebe2020-09-24 09:32:54 -0600228 initArgs.fCaps = args.fCaps;
Chris Dalton5e1545f2020-09-25 16:24:03 -0600229 fPipelineForStencils = args.fArena->make<GrPipeline>(
230 initArgs, GrDisableColorXPFactory::MakeXferProcessor(), *args.fHardClip);
231}
232
233// Allows non-zero stencil values to pass and write a color, and resets the stencil value back to
234// zero; discards immediately on stencil values of zero.
235// NOTE: It's ok to not check the clip here because the previous stencil pass will have only written
236// to samples already inside the clip.
237constexpr static GrUserStencilSettings kTestAndResetStencil(
238 GrUserStencilSettings::StaticInit<
239 0x0000,
240 GrUserStencilTest::kNotEqual,
241 0xffff,
242 GrUserStencilOp::kZero,
243 GrUserStencilOp::kKeep,
244 0xffff>());
245
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700246void GrPathTessellateOp::prePrepareFillTrianglesProgram(const PrePrepareArgs& args, bool isLinear) {
Chris Dalton5e1545f2020-09-25 16:24:03 -0600247 SkASSERT(!fFillTrianglesProgram);
248
249 if (fOpFlags & OpFlags::kStencilOnly) {
250 return;
251 }
252
253 // These are a twist on the standard red book stencil settings that allow us to fill the inner
254 // polygon directly to the final render target. At this point, the curves are already stencilled
255 // in. So if the stencil value is zero, then it means the path at our sample is not affected by
256 // any curves and we fill the path in directly. If the stencil value is nonzero, then we don't
257 // fill and instead continue the standard red book stencil process.
258 //
259 // NOTE: These settings are currently incompatible with a stencil clip.
260 constexpr static GrUserStencilSettings kFillOrIncrDecrStencil(
261 GrUserStencilSettings::StaticInitSeparate<
262 0x0000, 0x0000,
263 GrUserStencilTest::kEqual, GrUserStencilTest::kEqual,
264 0xffff, 0xffff,
265 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
266 GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
267 0xffff, 0xffff>());
268
269 constexpr static GrUserStencilSettings kFillOrInvertStencil(
270 GrUserStencilSettings::StaticInit<
271 0x0000,
272 GrUserStencilTest::kEqual,
273 0xffff,
274 GrUserStencilOp::kKeep,
275 GrUserStencilOp::kZero,
276 0xffff>());
277
278 this->prePreparePipelineForFills(args);
279
280 const GrUserStencilSettings* stencil;
281 if (fStencilTrianglesProgram) {
282 // The path was already stencilled. Here we just need to do a cover pass.
283 stencil = &kTestAndResetStencil;
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700284 } else if (isLinear) {
Chris Dalton5e1545f2020-09-25 16:24:03 -0600285 // There are no stencilled curves. We can ignore stencil and fill the path directly.
286 stencil = &GrUserStencilSettings::kUnused;
287 } else if (SkPathFillType::kWinding == fPath.getFillType()) {
288 // Fill in the path pixels not touched by curves, incr/decr stencil otherwise.
289 SkASSERT(!fPipelineForFills->hasStencilClip());
290 stencil = &kFillOrIncrDecrStencil;
291 } else {
292 // Fill in the path pixels not touched by curves, invert stencil otherwise.
293 SkASSERT(!fPipelineForFills->hasStencilClip());
294 stencil = &kFillOrInvertStencil;
295 }
296
297 auto* fillTriangleShader = args.fArena->make<GrFillTriangleShader>(fViewMatrix, fColor);
298 fFillTrianglesProgram = GrPathShader::MakeProgramInfo(
299 fillTriangleShader, args.fArena, args.fWriteView, fPipelineForFills,
Greg Daniel42dbca52020-11-20 10:22:43 -0500300 *args.fDstProxyView, args.fXferBarrierFlags, args.fColorLoadOp, stencil, *args.fCaps);
Chris Dalton5e1545f2020-09-25 16:24:03 -0600301}
302
303void GrPathTessellateOp::prePrepareFillCubicHullsProgram(const PrePrepareArgs& args) {
304 SkASSERT(!fFillPathProgram);
305
306 if (fOpFlags & OpFlags::kStencilOnly) {
307 return;
308 }
309
310 this->prePreparePipelineForFills(args);
311
312 auto* fillCubicHullsShader = args.fArena->make<GrFillCubicHullShader>(fViewMatrix, fColor);
313 fFillPathProgram = GrPathShader::MakeProgramInfo(
314 fillCubicHullsShader, args.fArena, args.fWriteView, fPipelineForFills,
Greg Daniel42dbca52020-11-20 10:22:43 -0500315 *args.fDstProxyView, args.fXferBarrierFlags, args.fColorLoadOp, &kTestAndResetStencil,
316 *args.fCaps);
Chris Dalton5e1545f2020-09-25 16:24:03 -0600317}
318
319void GrPathTessellateOp::prePrepareFillBoundingBoxProgram(const PrePrepareArgs& args) {
320 SkASSERT(!fFillPathProgram);
321
322 if (fOpFlags & OpFlags::kStencilOnly) {
323 return;
324 }
325
326 this->prePreparePipelineForFills(args);
327
328 auto* fillBoundingBoxShader = args.fArena->make<GrFillBoundingBoxShader>(fViewMatrix, fColor,
329 fPath.getBounds());
330 fFillPathProgram = GrPathShader::MakeProgramInfo(
331 fillBoundingBoxShader, args.fArena, args.fWriteView, fPipelineForFills,
Greg Daniel42dbca52020-11-20 10:22:43 -0500332 *args.fDstProxyView, args.fXferBarrierFlags, args.fColorLoadOp, &kTestAndResetStencil,
333 *args.fCaps);
Chris Dalton5e1545f2020-09-25 16:24:03 -0600334}
335
336void GrPathTessellateOp::prePreparePipelineForFills(const PrePrepareArgs& args) {
337 SkASSERT(!(fOpFlags & OpFlags::kStencilOnly));
338
339 if (fPipelineForFills) {
340 return;
341 }
342
343 auto pipelineFlags = GrPipeline::InputFlags::kNone;
344 if (GrAAType::kNone != fAAType) {
Adlai Hollere2296f72020-11-19 13:41:26 -0500345 if (args.fWriteView.asRenderTargetProxy()->numSamples() == 1) {
Chris Dalton5e1545f2020-09-25 16:24:03 -0600346 // We are mixed sampled. We need to either enable conservative raster (preferred) or
347 // disable MSAA in order to avoid double blend artifacts. (Even if we disable MSAA for
348 // the cover geometry, the stencil test is still multisampled and will still produce
349 // smooth results.)
350 SkASSERT(GrAAType::kCoverage == fAAType);
351 if (args.fCaps->conservativeRasterSupport()) {
352 pipelineFlags |= GrPipeline::InputFlags::kHWAntialias;
353 pipelineFlags |= GrPipeline::InputFlags::kConservativeRaster;
354 }
355 } else {
356 // We are standard MSAA. Leave MSAA enabled for the cover geometry.
357 pipelineFlags |= GrPipeline::InputFlags::kHWAntialias;
358 }
359 }
360
361 fPipelineForFills = GrSimpleMeshDrawOpHelper::CreatePipeline(
Chris Daltonb0643342020-12-15 01:04:12 -0700362 args.fCaps, args.fArena, args.fWriteView.swizzle(),
363 (args.fClip) ? std::move(*args.fClip) : GrAppliedClip::Disabled(), *args.fDstProxyView,
364 std::move(fProcessors), pipelineFlags);
Chris Daltone74cebe2020-09-24 09:32:54 -0600365}
366
367void GrPathTessellateOp::onPrepare(GrOpFlushState* flushState) {
368 int numVerbs = fPath.countVerbs();
369 if (numVerbs <= 0) {
370 return;
371 }
372
Chris Dalton5e1545f2020-09-25 16:24:03 -0600373 if (!fPipelineForStencils && !fPipelineForFills) {
Chris Daltone74cebe2020-09-24 09:32:54 -0600374 // Nothing has been prePrepared yet. Do it now.
Chris Dalton5e1545f2020-09-25 16:24:03 -0600375 GrAppliedHardClip hardClip = GrAppliedHardClip(flushState->appliedHardClip());
376 GrAppliedClip clip = flushState->detachAppliedClip();
377 PrePrepareArgs args{flushState->allocator(), flushState->writeView(), &hardClip,
378 &clip, &flushState->dstProxyView(),
Greg Daniel42dbca52020-11-20 10:22:43 -0500379 flushState->renderPassBarriers(), flushState->colorLoadOp(),
Chris Daltone4652052021-01-21 18:31:28 -0700380 &flushState->caps()};
Chris Dalton5e1545f2020-09-25 16:24:03 -0600381 this->prePreparePrograms(args);
Chris Daltone74cebe2020-09-24 09:32:54 -0600382 }
383
Chris Daltone4652052021-01-21 18:31:28 -0700384 if (fInnerFanPolys) {
Chris Daltone74cebe2020-09-24 09:32:54 -0600385 // prePreparePrograms was able to generate an inner polygon triangulation. It will exist in
386 // either fOffThreadInnerTriangulation or fTriangleBuffer exclusively.
Chris Daltone4652052021-01-21 18:31:28 -0700387 SkASSERT(fInnerFanTriangulator);
388 GrEagerDynamicVertexAllocator alloc(flushState, &fTriangleBuffer, &fBaseTriangleVertex);
389 fTriangleVertexCount = fInnerFanTriangulator->polysToTriangles(fInnerFanPolys, &alloc);
Chris Daltond7177432021-01-15 13:12:50 -0700390 } else if (fStencilTrianglesProgram) {
391 // The inner fan isn't built into the tessellator. Generate a standard Redbook fan with a
392 // middle-out topology.
393 GrEagerDynamicVertexAllocator vertexAlloc(flushState, &fTriangleBuffer,
394 &fBaseTriangleVertex);
395 // No initial moveTo, plus an implicit close at the end; n-2 triangles fill an n-gon.
396 int maxInnerTriangles = fPath.countVerbs() - 1;
397 auto* triangleVertexData = vertexAlloc.lock<SkPoint>(maxInnerTriangles * 3);
398 fTriangleVertexCount = GrMiddleOutPolygonTriangulator::WritePathInnerFan(
399 triangleVertexData, 3/*perTriangleVertexAdvance*/, fPath) * 3;
400 vertexAlloc.unlock(fTriangleVertexCount);
Chris Daltone74cebe2020-09-24 09:32:54 -0600401 }
402
Chris Daltond7177432021-01-15 13:12:50 -0700403 if (fTessellator) {
404 fTessellator->prepare(flushState, fViewMatrix, fPath);
Chris Daltone74cebe2020-09-24 09:32:54 -0600405 }
Chris Dalton42915c22020-04-22 16:24:43 -0600406}
407
Chris Dalton078f8752020-07-30 19:50:46 -0600408void GrPathTessellateOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
Chris Daltonb5391d92020-05-24 14:55:54 -0600409 this->drawStencilPass(flushState);
Chris Dalton5e1545f2020-09-25 16:24:03 -0600410 this->drawCoverPass(flushState);
Chris Daltonb832ce62020-01-06 19:49:37 -0700411}
412
Chris Dalton078f8752020-07-30 19:50:46 -0600413void GrPathTessellateOp::drawStencilPass(GrOpFlushState* flushState) {
Chris Daltone74cebe2020-09-24 09:32:54 -0600414 if (fStencilTrianglesProgram && fTriangleVertexCount > 0) {
Chris Dalton04f9cda2020-04-23 10:04:25 -0600415 SkASSERT(fTriangleBuffer);
Chris Daltone74cebe2020-09-24 09:32:54 -0600416 flushState->bindPipelineAndScissorClip(*fStencilTrianglesProgram, this->bounds());
Chris Dalton85138672020-07-24 08:47:03 -0600417 flushState->bindBuffers(nullptr, nullptr, fTriangleBuffer);
Chris Daltonb5391d92020-05-24 14:55:54 -0600418 flushState->draw(fTriangleVertexCount, fBaseTriangleVertex);
Chris Daltonf9aea7f2020-01-21 11:19:26 -0700419 }
420
Chris Daltond7177432021-01-15 13:12:50 -0700421 if (fTessellator) {
Chris Daltone74cebe2020-09-24 09:32:54 -0600422 flushState->bindPipelineAndScissorClip(*fStencilCubicsProgram, this->bounds());
Chris Daltond7177432021-01-15 13:12:50 -0700423 fTessellator->draw(flushState);
Chris Daltonb832ce62020-01-06 19:49:37 -0700424 }
425}
426
Chris Dalton078f8752020-07-30 19:50:46 -0600427void GrPathTessellateOp::drawCoverPass(GrOpFlushState* flushState) {
Chris Dalton5e1545f2020-09-25 16:24:03 -0600428 if (fFillTrianglesProgram) {
Chris Dalton04f9cda2020-04-23 10:04:25 -0600429 SkASSERT(fTriangleBuffer);
Chris Daltonb832ce62020-01-06 19:49:37 -0700430
Chris Dalton5e1545f2020-09-25 16:24:03 -0600431 // We have a triangulation of the path's inner polygon. This is the fast path. Fill those
432 // triangles directly to the screen.
Chris Daltone4652052021-01-21 18:31:28 -0700433 if (fTriangleVertexCount > 0) {
434 flushState->bindPipelineAndScissorClip(*fFillTrianglesProgram, this->bounds());
435 flushState->bindTextures(fFillTrianglesProgram->primProc(), nullptr,
436 *fPipelineForFills);
437 flushState->bindBuffers(nullptr, nullptr, fTriangleBuffer);
438 flushState->draw(fTriangleVertexCount, fBaseTriangleVertex);
439 }
Chris Dalton04f9cda2020-04-23 10:04:25 -0600440
Chris Daltond7177432021-01-15 13:12:50 -0700441 if (fTessellator) {
Chris Dalton5e1545f2020-09-25 16:24:03 -0600442 // At this point, every pixel is filled in except the ones touched by curves.
443 // fFillPathProgram will issue a final cover pass over the curves by drawing their
444 // convex hulls. This will fill in any remaining samples and reset the stencil buffer.
Chris Daltond7177432021-01-15 13:12:50 -0700445 SkASSERT(fFillPathProgram);
Chris Dalton5e1545f2020-09-25 16:24:03 -0600446 flushState->bindPipelineAndScissorClip(*fFillPathProgram, this->bounds());
447 flushState->bindTextures(fFillPathProgram->primProc(), nullptr, *fPipelineForFills);
Chris Daltond7177432021-01-15 13:12:50 -0700448 fTessellator->drawHullInstances(flushState);
Chris Dalton4328e922020-01-29 13:16:14 -0700449 }
Chris Dalton5e1545f2020-09-25 16:24:03 -0600450 } else if (fFillPathProgram) {
451 // There are no triangles to fill. Just draw a bounding box.
452 flushState->bindPipelineAndScissorClip(*fFillPathProgram, this->bounds());
453 flushState->bindTextures(fFillPathProgram->primProc(), nullptr, *fPipelineForFills);
454 flushState->bindBuffers(nullptr, nullptr, nullptr);
455 flushState->draw(4, 0);
Chris Dalton4328e922020-01-29 13:16:14 -0700456 }
Chris Daltonb832ce62020-01-06 19:49:37 -0700457}