blob: 7e0950ac460ff84082d34e6687aaf7f06e4f68cf [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
8#include "src/gpu/tessellate/GrTessellatePathOp.h"
9
Chris Daltond081dce2020-01-23 12:09:04 -070010#include "src/gpu/GrEagerVertexAllocator.h"
Chris Daltonb832ce62020-01-06 19:49:37 -070011#include "src/gpu/GrGpu.h"
12#include "src/gpu/GrOpFlushState.h"
Chris Dalton17dc4182020-03-25 16:18:16 -060013#include "src/gpu/GrTriangulator.h"
Chris Dalton4328e922020-01-29 13:16:14 -070014#include "src/gpu/tessellate/GrFillPathShader.h"
Chris Daltonf5132a02020-04-27 23:40:03 -060015#include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h"
Chris Dalton42915c22020-04-22 16:24:43 -060016#include "src/gpu/tessellate/GrMidpointContourParser.h"
Chris Daltonf9aea7f2020-01-21 11:19:26 -070017#include "src/gpu/tessellate/GrStencilPathShader.h"
Chris Daltonb832ce62020-01-06 19:49:37 -070018
19GrTessellatePathOp::FixedFunctionFlags GrTessellatePathOp::fixedFunctionFlags() const {
20 auto flags = FixedFunctionFlags::kUsesStencil;
21 if (GrAAType::kNone != fAAType) {
22 flags |= FixedFunctionFlags::kUsesHWAA;
23 }
24 return flags;
25}
26
Robert Phillipsc655c3a2020-03-18 13:23:45 -040027void GrTessellatePathOp::onPrePrepare(GrRecordingContext*,
Brian Salomon8afde5f2020-04-01 16:22:00 -040028 const GrSurfaceProxyView* writeView,
Robert Phillipsc655c3a2020-03-18 13:23:45 -040029 GrAppliedClip*,
30 const GrXferProcessor::DstProxyView&) {
31}
32
Chris Daltonb832ce62020-01-06 19:49:37 -070033void GrTessellatePathOp::onPrepare(GrOpFlushState* state) {
Chris Dalton04f9cda2020-04-23 10:04:25 -060034 // First check if the path is large and/or simple enough that we can actually triangulate the
Chris Dalton4328e922020-01-29 13:16:14 -070035 // inner polygon(s) on the CPU. This is our fastest approach. It allows us to stencil only the
Chris Dalton04f9cda2020-04-23 10:04:25 -060036 // curves, and then fill the internal polygons directly to the final render target, thus filling
Chris Dalton4328e922020-01-29 13:16:14 -070037 // in the majority of pixels in a single render pass.
38 SkScalar scales[2];
39 SkAssertResult(fViewMatrix.getMinMaxScales(scales)); // Will fail if perspective.
40 const SkRect& bounds = fPath.getBounds();
41 int numVerbs = fPath.countVerbs();
42 if (numVerbs <= 0) {
43 return;
44 }
45 float gpuFragmentWork = bounds.height() * scales[0] * bounds.width() * scales[1];
46 float cpuTessellationWork = (float)numVerbs * SkNextLog2(numVerbs); // N log N.
47 if (cpuTessellationWork * 500 + (256 * 256) < gpuFragmentWork) { // Don't try below 256x256.
Chris Dalton8e2b6942020-04-22 15:55:00 -060048 int numCountedCurves;
Chris Dalton04f9cda2020-04-23 10:04:25 -060049 // This will fail if the inner triangles do not form a simple polygon (e.g., self
50 // intersection, double winding).
Chris Daltonf5132a02020-04-27 23:40:03 -060051 if (this->prepareNonOverlappingInnerTriangles(state, &numCountedCurves)) {
Chris Dalton04f9cda2020-04-23 10:04:25 -060052 // Prepare cubics on an instance boundary so we can use the buffer to fill local convex
53 // hulls as well.
54 this->prepareOuterCubics(state, numCountedCurves,
55 CubicDataAlignment::kInstanceBoundary);
Chris Dalton4328e922020-01-29 13:16:14 -070056 return;
57 }
58 }
59
60 // Next see if we can split up inner polygon triangles and curves, and triangulate the inner
Chris Daltonf9aea7f2020-01-21 11:19:26 -070061 // polygon(s) more efficiently. This causes greater CPU overhead due to the extra shaders and
62 // draw calls, but the better triangulation can reduce the rasterizer load by a great deal on
63 // complex paths.
Chris Dalton4328e922020-01-29 13:16:14 -070064 // NOTE: Raster-edge work is 1-dimensional, so we sum height and width instead of multiplying.
65 float rasterEdgeWork = (bounds.height() + bounds.width()) * scales[1] * fPath.countVerbs();
Chris Daltonf9aea7f2020-01-21 11:19:26 -070066 if (rasterEdgeWork > 1000 * 1000) {
Chris Dalton42915c22020-04-22 16:24:43 -060067 int numCountedCurves;
Chris Daltonf5132a02020-04-27 23:40:03 -060068 this->prepareMiddleOutInnerTriangles(state, &numCountedCurves);
Chris Dalton04f9cda2020-04-23 10:04:25 -060069 // We will fill the path with a bounding box instead local cubic convex hulls, so there is
70 // no need to prepare the cubics on an instance boundary.
71 this->prepareOuterCubics(state, numCountedCurves, CubicDataAlignment::kVertexBoundary);
Chris Daltonf9aea7f2020-01-21 11:19:26 -070072 return;
73 }
74
75 // Fastest CPU approach: emit one cubic wedge per verb, fanning out from the center.
Chris Dalton04f9cda2020-04-23 10:04:25 -060076 this->prepareCubicWedges(state);
Chris Daltonb832ce62020-01-06 19:49:37 -070077}
78
Chris Dalton2f2d81c2020-05-13 17:57:37 -060079bool GrTessellatePathOp::prepareNonOverlappingInnerTriangles(GrMeshDrawOp::Target* target,
Chris Daltonf5132a02020-04-27 23:40:03 -060080 int* numCountedCurves) {
Chris Dalton04f9cda2020-04-23 10:04:25 -060081 SkASSERT(!fTriangleBuffer);
82 SkASSERT(!fDoStencilTriangleBuffer);
83 SkASSERT(!fDoFillTriangleBuffer);
84
85 using GrTriangulator::Mode;
86
Chris Dalton2f2d81c2020-05-13 17:57:37 -060087 GrEagerDynamicVertexAllocator vertexAlloc(target, &fTriangleBuffer, &fBaseTriangleVertex);
Chris Dalton04f9cda2020-04-23 10:04:25 -060088 fTriangleVertexCount = GrTriangulator::PathToTriangles(fPath, 0, SkRect::MakeEmpty(),
89 &vertexAlloc, Mode::kSimpleInnerPolygons,
90 numCountedCurves);
91 if (fTriangleVertexCount == 0) {
92 // Mode::kSimpleInnerPolygons causes PathToTriangles to fail if the inner polygon(s) are not
93 // simple.
94 return false;
95 }
96 if (((Flags::kStencilOnly | Flags::kWireframe) & fFlags) || GrAAType::kCoverage == fAAType ||
Chris Dalton2f2d81c2020-05-13 17:57:37 -060097 (target->appliedClip() && target->appliedClip()->hasStencilClip())) {
Chris Dalton04f9cda2020-04-23 10:04:25 -060098 // If we have certain flags, mixed samples, or a stencil clip then we unfortunately
99 // can't fill the inner polygon directly. Indicate that these triangles need to be
100 // stencilled.
101 fDoStencilTriangleBuffer = true;
102 }
103 if (!(Flags::kStencilOnly & fFlags)) {
104 fDoFillTriangleBuffer = true;
105 }
106 return true;
107}
108
Chris Dalton2f2d81c2020-05-13 17:57:37 -0600109void GrTessellatePathOp::prepareMiddleOutInnerTriangles(GrMeshDrawOp::Target* target,
Chris Daltonf5132a02020-04-27 23:40:03 -0600110 int* numCountedCurves) {
Chris Dalton04f9cda2020-04-23 10:04:25 -0600111 SkASSERT(!fTriangleBuffer);
112 SkASSERT(!fDoStencilTriangleBuffer);
113 SkASSERT(!fDoFillTriangleBuffer);
114
Chris Daltonf5132a02020-04-27 23:40:03 -0600115 // No initial moveTo, plus an implicit close at the end; n-2 triangles fill an n-gon.
Chris Dalton42915c22020-04-22 16:24:43 -0600116 // Each triangle has 3 vertices.
117 int maxVertices = (fPath.countVerbs() - 1) * 3;
118
Chris Dalton2f2d81c2020-05-13 17:57:37 -0600119 GrEagerDynamicVertexAllocator vertexAlloc(target, &fTriangleBuffer, &fBaseTriangleVertex);
Chris Dalton42915c22020-04-22 16:24:43 -0600120 auto* vertexData = vertexAlloc.lock<SkPoint>(maxVertices);
121 if (!vertexData) {
Chris Dalton04f9cda2020-04-23 10:04:25 -0600122 return;
Chris Dalton42915c22020-04-22 16:24:43 -0600123 }
Chris Dalton42915c22020-04-22 16:24:43 -0600124
Chris Daltonf5132a02020-04-27 23:40:03 -0600125 GrMiddleOutPolygonTriangulator middleOut(vertexData, maxVertices);
126 int localCurveCount = 0;
Chris Daltonf7a33072020-05-01 10:33:08 -0600127 for (auto [verb, pts, w] : SkPathPriv::Iterate(fPath)) {
128 switch (verb) {
129 case SkPathVerb::kMove:
Chris Daltonf5132a02020-04-27 23:40:03 -0600130 middleOut.closeAndMove(*pts++);
131 break;
Chris Daltonf7a33072020-05-01 10:33:08 -0600132 case SkPathVerb::kLine:
133 middleOut.pushVertex(pts[1]);
134 break;
135 case SkPathVerb::kQuad:
136 middleOut.pushVertex(pts[2]);
137 ++localCurveCount;
138 break;
139 case SkPathVerb::kCubic:
140 middleOut.pushVertex(pts[3]);
141 ++localCurveCount;
142 break;
143 case SkPathVerb::kClose:
Chris Daltonf5132a02020-04-27 23:40:03 -0600144 middleOut.close();
145 break;
Chris Daltonf7a33072020-05-01 10:33:08 -0600146 case SkPathVerb::kConic:
Chris Daltonf7a33072020-05-01 10:33:08 -0600147 SkUNREACHABLE;
Chris Daltonf5132a02020-04-27 23:40:03 -0600148 }
Chris Dalton42915c22020-04-22 16:24:43 -0600149 }
Chris Daltonf5132a02020-04-27 23:40:03 -0600150 fTriangleVertexCount = middleOut.close();
151 *numCountedCurves = localCurveCount;
Chris Dalton42915c22020-04-22 16:24:43 -0600152
Chris Dalton04f9cda2020-04-23 10:04:25 -0600153 vertexAlloc.unlock(fTriangleVertexCount);
154
155 if (fTriangleVertexCount) {
156 fDoStencilTriangleBuffer = true;
157 }
Chris Dalton42915c22020-04-22 16:24:43 -0600158}
159
160static SkPoint lerp(const SkPoint& a, const SkPoint& b, float T) {
161 SkASSERT(1 != T); // The below does not guarantee lerp(a, b, 1) === b.
162 return (b - a) * T + a;
163}
164
Chris Daltonf7a33072020-05-01 10:33:08 -0600165static void line2cubic(const SkPoint& p0, const SkPoint& p1, SkPoint* out) {
166 out[0] = p0;
167 out[1] = lerp(p0, p1, 1/3.f);
168 out[2] = lerp(p0, p1, 2/3.f);
169 out[3] = p1;
Chris Dalton42915c22020-04-22 16:24:43 -0600170}
171
Chris Daltonf7a33072020-05-01 10:33:08 -0600172static void quad2cubic(const SkPoint pts[], SkPoint* out) {
173 out[0] = pts[0];
174 out[1] = lerp(pts[0], pts[1], 2/3.f);
175 out[2] = lerp(pts[1], pts[2], 1/3.f);
176 out[3] = pts[2];
Chris Dalton42915c22020-04-22 16:24:43 -0600177}
178
Chris Dalton2f2d81c2020-05-13 17:57:37 -0600179void GrTessellatePathOp::prepareOuterCubics(GrMeshDrawOp::Target* target, int numCountedCurves,
Chris Dalton04f9cda2020-04-23 10:04:25 -0600180 CubicDataAlignment alignment) {
181 SkASSERT(!fCubicBuffer);
182 SkASSERT(!fStencilCubicsShader);
Chris Dalton42915c22020-04-22 16:24:43 -0600183
184 if (numCountedCurves == 0) {
185 return;
186 }
187
Chris Dalton04f9cda2020-04-23 10:04:25 -0600188 bool instanceAligned = (alignment == CubicDataAlignment::kInstanceBoundary);
189 int instanceOrVertexStride = (instanceAligned) ? sizeof(SkPoint) * 4 : sizeof(SkPoint);
190 int instanceOrVertexCount = (instanceAligned) ? numCountedCurves : numCountedCurves * 4;
191 int baseInstanceOrVertex;
192
Chris Dalton2f2d81c2020-05-13 17:57:37 -0600193 auto* vertexData = static_cast<SkPoint*>(target->makeVertexSpace(
Chris Dalton04f9cda2020-04-23 10:04:25 -0600194 instanceOrVertexStride, instanceOrVertexCount, &fCubicBuffer, &baseInstanceOrVertex));
195 if (!vertexData) {
Chris Dalton42915c22020-04-22 16:24:43 -0600196 return;
197 }
Chris Dalton04f9cda2020-04-23 10:04:25 -0600198 fBaseCubicVertex = (instanceAligned) ? baseInstanceOrVertex * 4 : baseInstanceOrVertex;
199 fCubicVertexCount = 0;
Chris Dalton42915c22020-04-22 16:24:43 -0600200
Chris Daltonf7a33072020-05-01 10:33:08 -0600201 for (auto [verb, pts, w] : SkPathPriv::Iterate(fPath)) {
202 switch (verb) {
203 case SkPathVerb::kQuad:
204 SkASSERT(fCubicVertexCount < numCountedCurves * 4);
205 quad2cubic(pts, vertexData + fCubicVertexCount);
206 fCubicVertexCount += 4;
207 break;
208 case SkPathVerb::kCubic:
209 SkASSERT(fCubicVertexCount < numCountedCurves * 4);
210 memcpy(vertexData + fCubicVertexCount, pts, sizeof(SkPoint) * 4);
211 fCubicVertexCount += 4;
212 break;
213 default:
214 break;
Chris Dalton42915c22020-04-22 16:24:43 -0600215 }
216 }
Chris Dalton04f9cda2020-04-23 10:04:25 -0600217 SkASSERT(fCubicVertexCount == numCountedCurves * 4);
218
Chris Dalton2f2d81c2020-05-13 17:57:37 -0600219 fStencilCubicsShader = target->allocator()->make<GrStencilCubicShader>(fViewMatrix);
Chris Dalton42915c22020-04-22 16:24:43 -0600220}
221
Chris Dalton2f2d81c2020-05-13 17:57:37 -0600222void GrTessellatePathOp::prepareCubicWedges(GrMeshDrawOp::Target* target) {
Chris Dalton04f9cda2020-04-23 10:04:25 -0600223 SkASSERT(!fCubicBuffer);
224 SkASSERT(!fStencilCubicsShader);
225
Chris Dalton42915c22020-04-22 16:24:43 -0600226 // No initial moveTo, one wedge per verb, plus an implicit close at the end.
227 // Each wedge has 5 vertices.
228 int maxVertices = (fPath.countVerbs() + 1) * 5;
229
Chris Dalton2f2d81c2020-05-13 17:57:37 -0600230 GrEagerDynamicVertexAllocator vertexAlloc(target, &fCubicBuffer, &fBaseCubicVertex);
Chris Dalton42915c22020-04-22 16:24:43 -0600231 auto* vertexData = vertexAlloc.lock<SkPoint>(maxVertices);
232 if (!vertexData) {
Chris Dalton04f9cda2020-04-23 10:04:25 -0600233 return;
Chris Dalton42915c22020-04-22 16:24:43 -0600234 }
Chris Dalton04f9cda2020-04-23 10:04:25 -0600235 fCubicVertexCount = 0;
Chris Dalton42915c22020-04-22 16:24:43 -0600236
237 GrMidpointContourParser parser(fPath);
238 while (parser.parseNextContour()) {
Chris Daltonf7a33072020-05-01 10:33:08 -0600239 SkPoint midpoint = parser.currentMidpoint();
240 SkPoint startPoint = {0, 0};
241 SkPoint lastPoint = startPoint;
242 for (auto [verb, pts, w] : parser.currentContour()) {
243 switch (verb) {
244 case SkPathVerb::kMove:
245 startPoint = lastPoint = pts[0];
Chris Dalton42915c22020-04-22 16:24:43 -0600246 continue;
Chris Daltonf7a33072020-05-01 10:33:08 -0600247 case SkPathVerb::kClose:
248 continue; // Ignore. We can assume an implicit close at the end.
Chris Dalton42915c22020-04-22 16:24:43 -0600249 case SkPathVerb::kLine:
Chris Daltonf7a33072020-05-01 10:33:08 -0600250 line2cubic(pts[0], pts[1], vertexData + fCubicVertexCount);
251 lastPoint = pts[1];
Chris Dalton42915c22020-04-22 16:24:43 -0600252 break;
253 case SkPathVerb::kQuad:
Chris Daltonf7a33072020-05-01 10:33:08 -0600254 quad2cubic(pts, vertexData + fCubicVertexCount);
255 lastPoint = pts[2];
Chris Dalton42915c22020-04-22 16:24:43 -0600256 break;
257 case SkPathVerb::kCubic:
Chris Daltonf7a33072020-05-01 10:33:08 -0600258 memcpy(vertexData + fCubicVertexCount, pts, sizeof(SkPoint) * 4);
259 lastPoint = pts[3];
Chris Dalton42915c22020-04-22 16:24:43 -0600260 break;
261 case SkPathVerb::kConic:
262 SkUNREACHABLE;
263 }
Chris Daltonf7a33072020-05-01 10:33:08 -0600264 vertexData[fCubicVertexCount + 4] = midpoint;
265 fCubicVertexCount += 5;
266 }
267 if (lastPoint != startPoint) {
268 line2cubic(lastPoint, startPoint, vertexData + fCubicVertexCount);
269 vertexData[fCubicVertexCount + 4] = midpoint;
Chris Dalton04f9cda2020-04-23 10:04:25 -0600270 fCubicVertexCount += 5;
Chris Dalton42915c22020-04-22 16:24:43 -0600271 }
272 }
273
Chris Dalton04f9cda2020-04-23 10:04:25 -0600274 vertexAlloc.unlock(fCubicVertexCount);
275
276 if (fCubicVertexCount) {
Chris Dalton2f2d81c2020-05-13 17:57:37 -0600277 fStencilCubicsShader = target->allocator()->make<GrStencilWedgeShader>(fViewMatrix);
Chris Dalton04f9cda2020-04-23 10:04:25 -0600278 }
Chris Dalton42915c22020-04-22 16:24:43 -0600279}
280
Chris Daltonb832ce62020-01-06 19:49:37 -0700281void GrTessellatePathOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) {
Chris Daltonaa0e45c2020-03-16 10:05:11 -0600282 this->drawStencilPass(state);
Chris Daltonb832ce62020-01-06 19:49:37 -0700283 if (!(Flags::kStencilOnly & fFlags)) {
Chris Daltonaa0e45c2020-03-16 10:05:11 -0600284 this->drawCoverPass(state);
Chris Daltonb832ce62020-01-06 19:49:37 -0700285 }
286}
287
Chris Daltonaa0e45c2020-03-16 10:05:11 -0600288void GrTessellatePathOp::drawStencilPass(GrOpFlushState* state) {
Chris Daltonb832ce62020-01-06 19:49:37 -0700289 // Increments clockwise triangles and decrements counterclockwise. Used for "winding" fill.
290 constexpr static GrUserStencilSettings kIncrDecrStencil(
291 GrUserStencilSettings::StaticInitSeparate<
292 0x0000, 0x0000,
293 GrUserStencilTest::kAlwaysIfInClip, GrUserStencilTest::kAlwaysIfInClip,
294 0xffff, 0xffff,
295 GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
296 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
297 0xffff, 0xffff>());
298
299 // Inverts the bottom stencil bit. Used for "even/odd" fill.
300 constexpr static GrUserStencilSettings kInvertStencil(
301 GrUserStencilSettings::StaticInit<
302 0x0000,
303 GrUserStencilTest::kAlwaysIfInClip,
304 0xffff,
305 GrUserStencilOp::kInvert,
306 GrUserStencilOp::kKeep,
307 0x0001>());
308
309 GrPipeline::InitArgs initArgs;
310 if (GrAAType::kNone != fAAType) {
311 initArgs.fInputFlags |= GrPipeline::InputFlags::kHWAntialias;
312 }
313 if (state->caps().wireframeSupport() && (Flags::kWireframe & fFlags)) {
314 initArgs.fInputFlags |= GrPipeline::InputFlags::kWireframe;
315 }
316 SkASSERT(SkPathFillType::kWinding == fPath.getFillType() ||
317 SkPathFillType::kEvenOdd == fPath.getFillType());
318 initArgs.fUserStencil = (SkPathFillType::kWinding == fPath.getFillType()) ?
319 &kIncrDecrStencil : &kInvertStencil;
320 initArgs.fCaps = &state->caps();
Chris Daltonaa0e45c2020-03-16 10:05:11 -0600321 GrPipeline pipeline(initArgs, GrDisableColorXPFactory::MakeXferProcessor(),
322 state->appliedHardClip());
Chris Dalton012f8492020-03-05 11:49:15 -0700323
Chris Dalton04f9cda2020-04-23 10:04:25 -0600324 if (fDoStencilTriangleBuffer) {
325 SkASSERT(fTriangleBuffer);
326 GrStencilTriangleShader stencilTriangleShader(fViewMatrix);
327 GrPathShader::ProgramInfo programInfo(state->writeView(), &pipeline,
328 &stencilTriangleShader);
Chris Daltonaa0e45c2020-03-16 10:05:11 -0600329 state->bindPipelineAndScissorClip(programInfo, this->bounds());
Chris Dalton04f9cda2020-04-23 10:04:25 -0600330 state->bindBuffers(nullptr, nullptr, fTriangleBuffer.get());
331 state->draw(fTriangleVertexCount, fBaseTriangleVertex);
Chris Daltonf9aea7f2020-01-21 11:19:26 -0700332 }
333
Chris Dalton04f9cda2020-04-23 10:04:25 -0600334 if (fStencilCubicsShader) {
335 GrPathShader::ProgramInfo programInfo(state->writeView(), &pipeline, fStencilCubicsShader);
Chris Daltonaa0e45c2020-03-16 10:05:11 -0600336 state->bindPipelineAndScissorClip(programInfo, this->bounds());
Chris Dalton04f9cda2020-04-23 10:04:25 -0600337 state->bindBuffers(nullptr, nullptr, fCubicBuffer.get());
338 state->draw(fCubicVertexCount, fBaseCubicVertex);
Chris Daltonf9aea7f2020-01-21 11:19:26 -0700339 }
Chris Daltonb832ce62020-01-06 19:49:37 -0700340
341 // http://skbug.com/9739
342 if (state->caps().requiresManualFBBarrierAfterTessellatedStencilDraw()) {
343 state->gpu()->insertManualFramebufferBarrier();
344 }
345}
346
Chris Daltonaa0e45c2020-03-16 10:05:11 -0600347void GrTessellatePathOp::drawCoverPass(GrOpFlushState* state) {
Chris Daltonb832ce62020-01-06 19:49:37 -0700348 // Allows non-zero stencil values to pass and write a color, and resets the stencil value back
349 // to zero; discards immediately on stencil values of zero.
350 // NOTE: It's ok to not check the clip here because the previous stencil pass only wrote to
351 // samples already inside the clip.
352 constexpr static GrUserStencilSettings kTestAndResetStencil(
353 GrUserStencilSettings::StaticInit<
354 0x0000,
355 GrUserStencilTest::kNotEqual,
356 0xffff,
357 GrUserStencilOp::kZero,
358 GrUserStencilOp::kKeep,
359 0xffff>());
360
361 GrPipeline::InitArgs initArgs;
362 if (GrAAType::kNone != fAAType) {
363 initArgs.fInputFlags |= GrPipeline::InputFlags::kHWAntialias;
364 if (1 == state->proxy()->numSamples()) {
365 SkASSERT(GrAAType::kCoverage == fAAType);
366 // We are mixed sampled. Use conservative raster to make the sample coverage mask 100%
367 // at every fragment. This way we will still get a double hit on shared edges, but
368 // whichever side comes first will cover every sample and will clear the stencil. The
369 // other side will then be discarded and not cause a double blend.
370 initArgs.fInputFlags |= GrPipeline::InputFlags::kConservativeRaster;
371 }
372 }
Chris Daltonb832ce62020-01-06 19:49:37 -0700373 initArgs.fCaps = &state->caps();
374 initArgs.fDstProxyView = state->drawOpArgs().dstProxyView();
Brian Salomon982f5462020-03-30 12:52:33 -0400375 initArgs.fWriteSwizzle = state->drawOpArgs().writeSwizzle();
Chris Daltonaa0e45c2020-03-16 10:05:11 -0600376 GrPipeline pipeline(initArgs, std::move(fProcessors), state->detachAppliedClip());
Chris Daltonb832ce62020-01-06 19:49:37 -0700377
Chris Dalton04f9cda2020-04-23 10:04:25 -0600378 if (fDoFillTriangleBuffer) {
379 SkASSERT(fTriangleBuffer);
Chris Daltonb832ce62020-01-06 19:49:37 -0700380
Chris Dalton04f9cda2020-04-23 10:04:25 -0600381 // These are a twist on the standard red book stencil settings that allow us to fill the
Chris Dalton4328e922020-01-29 13:16:14 -0700382 // inner polygon directly to the final render target. At this point, the curves are already
383 // stencilled in. So if the stencil value is zero, then it means the path at our sample is
384 // not affected by any curves and we fill the path in directly. If the stencil value is
385 // nonzero, then we don't fill and instead continue the standard red book stencil process.
386 //
387 // NOTE: These settings are currently incompatible with a stencil clip.
388 constexpr static GrUserStencilSettings kFillOrIncrDecrStencil(
389 GrUserStencilSettings::StaticInitSeparate<
390 0x0000, 0x0000,
391 GrUserStencilTest::kEqual, GrUserStencilTest::kEqual,
392 0xffff, 0xffff,
393 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
394 GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
395 0xffff, 0xffff>());
396
397 constexpr static GrUserStencilSettings kFillOrInvertStencil(
398 GrUserStencilSettings::StaticInit<
399 0x0000,
400 GrUserStencilTest::kEqual,
401 0xffff,
402 GrUserStencilOp::kKeep,
403 GrUserStencilOp::kZero,
404 0xffff>());
405
Chris Dalton04f9cda2020-04-23 10:04:25 -0600406 if (fDoStencilTriangleBuffer) {
Chris Dalton4328e922020-01-29 13:16:14 -0700407 // The path was already stencilled. Here we just need to do a cover pass.
408 pipeline.setUserStencil(&kTestAndResetStencil);
Chris Dalton04f9cda2020-04-23 10:04:25 -0600409 } else if (!fStencilCubicsShader) {
410 // There are no stencilled curves. We can ignore stencil and fill the path directly.
Chris Dalton4328e922020-01-29 13:16:14 -0700411 pipeline.setUserStencil(&GrUserStencilSettings::kUnused);
412 } else if (SkPathFillType::kWinding == fPath.getFillType()) {
413 // Fill in the path pixels not touched by curves, incr/decr stencil otherwise.
414 SkASSERT(!pipeline.hasStencilClip());
415 pipeline.setUserStencil(&kFillOrIncrDecrStencil);
416 } else {
417 // Fill in the path pixels not touched by curves, invert stencil otherwise.
418 SkASSERT(!pipeline.hasStencilClip());
419 pipeline.setUserStencil(&kFillOrInvertStencil);
420 }
Chris Dalton4328e922020-01-29 13:16:14 -0700421
Chris Dalton04f9cda2020-04-23 10:04:25 -0600422 GrFillTriangleShader fillTriangleShader(fViewMatrix, fColor);
423 GrPathShader::ProgramInfo programInfo(state->writeView(), &pipeline, &fillTriangleShader);
424 state->bindPipelineAndScissorClip(programInfo, this->bounds());
425 state->bindTextures(fillTriangleShader, nullptr, pipeline);
426 state->bindBuffers(nullptr, nullptr, fTriangleBuffer.get());
427 state->draw(fTriangleVertexCount, fBaseTriangleVertex);
428
429 if (fStencilCubicsShader) {
Chris Dalton4328e922020-01-29 13:16:14 -0700430 // At this point, every pixel is filled in except the ones touched by curves. Issue a
431 // final cover pass over the curves by drawing their convex hulls. This will fill in any
432 // remaining samples and reset the stencil buffer.
Chris Dalton4328e922020-01-29 13:16:14 -0700433 pipeline.setUserStencil(&kTestAndResetStencil);
Chris Dalton04f9cda2020-04-23 10:04:25 -0600434 GrFillCubicHullShader fillCubicHullShader(fViewMatrix, fColor);
435 GrPathShader::ProgramInfo programInfo(state->writeView(), &pipeline,
436 &fillCubicHullShader);
Chris Daltonaa0e45c2020-03-16 10:05:11 -0600437 state->bindPipelineAndScissorClip(programInfo, this->bounds());
Chris Dalton04f9cda2020-04-23 10:04:25 -0600438 state->bindTextures(fillCubicHullShader, nullptr, pipeline);
439
440 // Here we treat fCubicBuffer as an instance buffer. It should have been prepared with
441 // the base vertex on an instance boundary in order to accommodate this.
442 SkASSERT((fCubicVertexCount % 4) == 0);
443 SkASSERT((fBaseCubicVertex % 4) == 0);
444 state->bindBuffers(nullptr, fCubicBuffer.get(), nullptr);
445 state->drawInstanced(fCubicVertexCount >> 2, fBaseCubicVertex >> 2, 4, 0);
Chris Dalton4328e922020-01-29 13:16:14 -0700446 }
Chris Dalton42915c22020-04-22 16:24:43 -0600447 return;
Chris Dalton4328e922020-01-29 13:16:14 -0700448 }
Chris Dalton42915c22020-04-22 16:24:43 -0600449
Chris Dalton04f9cda2020-04-23 10:04:25 -0600450 // There are no triangles to fill. Just draw a bounding box.
Chris Dalton42915c22020-04-22 16:24:43 -0600451 pipeline.setUserStencil(&kTestAndResetStencil);
Chris Dalton04f9cda2020-04-23 10:04:25 -0600452 GrFillBoundingBoxShader fillBoundingBoxShader(fViewMatrix, fColor, fPath.getBounds());
453 GrPathShader::ProgramInfo programInfo(state->writeView(), &pipeline, &fillBoundingBoxShader);
Chris Dalton42915c22020-04-22 16:24:43 -0600454 state->bindPipelineAndScissorClip(programInfo, this->bounds());
Chris Dalton04f9cda2020-04-23 10:04:25 -0600455 state->bindTextures(fillBoundingBoxShader, nullptr, pipeline);
Chris Dalton42915c22020-04-22 16:24:43 -0600456 state->bindBuffers(nullptr, nullptr, nullptr);
457 state->draw(4, 0);
Chris Daltonb832ce62020-01-06 19:49:37 -0700458}