blob: fbd845a65d76aa2de5e8534095e173b83044554a [file] [log] [blame]
bsalomon@google.com30085192011-08-19 15:42:31 +00001/*
2 * Copyright 2011 Google Inc.
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/gpu/ops/GrDefaultPathRenderer.h"
Robert Phillipsbe9aff22019-02-15 11:33:22 -05009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkString.h"
11#include "include/core/SkStrokeRec.h"
12#include "src/core/SkGeometry.h"
Michael Ludwigfbe28592020-06-26 16:02:15 -040013#include "src/core/SkMatrixPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/core/SkTLazy.h"
15#include "src/core/SkTraceEvent.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040016#include "src/gpu/GrAuditTrail.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/gpu/GrCaps.h"
Michael Ludwig58f569b2020-05-21 17:03:08 -040018#include "src/gpu/GrClip.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/gpu/GrDefaultGeoProcFactory.h"
20#include "src/gpu/GrDrawOpTest.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "src/gpu/GrOpFlushState.h"
Robert Phillips9028bac2020-03-10 16:19:27 -040022#include "src/gpu/GrProgramInfo.h"
Michael Ludwigaa1b6b32019-05-29 14:43:13 -040023#include "src/gpu/GrRenderTargetContextPriv.h"
Chris Daltoneb694b72020-03-16 09:25:50 -060024#include "src/gpu/GrSimpleMesh.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/gpu/GrStyle.h"
26#include "src/gpu/GrSurfaceContextPriv.h"
Michael Ludwig663afe52019-06-03 16:46:19 -040027#include "src/gpu/geometry/GrPathUtils.h"
Michael Ludwig2686d692020-04-17 20:21:37 +000028#include "src/gpu/geometry/GrStyledShape.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050029#include "src/gpu/ops/GrMeshDrawOp.h"
Robert Phillips55f681f2020-02-28 08:58:15 -050030#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
joshualitt74417822015-08-07 11:42:16 -070031
Brian Salomon15b25092017-05-08 11:10:53 -040032GrDefaultPathRenderer::GrDefaultPathRenderer() {
bsalomon@google.com289533a2011-10-27 12:34:25 +000033}
34
bsalomon@google.com30085192011-08-19 15:42:31 +000035////////////////////////////////////////////////////////////////////////////////
36// Helpers for drawPath
37
bsalomon@google.com30085192011-08-19 15:42:31 +000038#define STENCIL_OFF 0 // Always disable stencil (even when needed)
39
Michael Ludwig2686d692020-04-17 20:21:37 +000040static inline bool single_pass_shape(const GrStyledShape& shape) {
bsalomon@google.com30085192011-08-19 15:42:31 +000041#if STENCIL_OFF
42 return true;
43#else
bsalomonee432412016-06-27 07:18:18 -070044 // Inverse fill is always two pass.
45 if (shape.inverseFilled()) {
46 return false;
47 }
48 // This path renderer only accepts simple fill paths or stroke paths that are either hairline
49 // or have a stroke width small enough to treat as hairline. Hairline paths are always single
50 // pass. Filled paths are single pass if they're convex.
51 if (shape.style().isSimpleFill()) {
bsalomon8acedde2016-06-24 10:42:16 -070052 return shape.knownToBeConvex();
bsalomon@google.com30085192011-08-19 15:42:31 +000053 }
bsalomonee432412016-06-27 07:18:18 -070054 return true;
bsalomon@google.com30085192011-08-19 15:42:31 +000055#endif
56}
57
joshualitt9853cce2014-11-17 14:22:48 -080058GrPathRenderer::StencilSupport
Michael Ludwig2686d692020-04-17 20:21:37 +000059GrDefaultPathRenderer::onGetStencilSupport(const GrStyledShape& shape) const {
bsalomon8acedde2016-06-24 10:42:16 -070060 if (single_pass_shape(shape)) {
bsalomon@google.com45a15f52012-12-10 19:10:17 +000061 return GrPathRenderer::kNoRestriction_StencilSupport;
62 } else {
63 return GrPathRenderer::kStencilOnly_StencilSupport;
64 }
bsalomon@google.com30085192011-08-19 15:42:31 +000065}
66
Brian Salomonee3e0ba2017-07-13 16:40:46 -040067namespace {
68
Brian Osman49b7b6f2017-06-20 14:43:58 -040069class PathGeoBuilder {
70public:
Robert Phillips9028bac2020-03-10 16:19:27 -040071 PathGeoBuilder(GrPrimitiveType primitiveType,
72 GrMeshDrawOp::Target* target,
Chris Daltoneb694b72020-03-16 09:25:50 -060073 SkTDArray<GrSimpleMesh*>* meshes)
Brian Salomon7eae3e02018-08-07 14:02:38 +000074 : fPrimitiveType(primitiveType)
Brian Osman49b7b6f2017-06-20 14:43:58 -040075 , fTarget(target)
76 , fVertexStride(sizeof(SkPoint))
Brian Osman49b7b6f2017-06-20 14:43:58 -040077 , fFirstIndex(0)
78 , fIndicesInChunk(0)
Robert Phillips9028bac2020-03-10 16:19:27 -040079 , fIndices(nullptr)
80 , fMeshes(meshes) {
Brian Osman49b7b6f2017-06-20 14:43:58 -040081 this->allocNewBuffers();
Brian Osmaneb86b702017-06-07 11:38:31 -040082 }
83
Brian Osman49b7b6f2017-06-20 14:43:58 -040084 ~PathGeoBuilder() {
Robert Phillips9028bac2020-03-10 16:19:27 -040085 this->createMeshAndPutBackReserve();
Brian Osman49b7b6f2017-06-20 14:43:58 -040086 }
87
88 /**
89 * Path verbs
90 */
91 void moveTo(const SkPoint& p) {
92 needSpace(1);
93
94 fSubpathIndexStart = this->currentIndex();
95 *(fCurVert++) = p;
96 }
97
98 void addLine(const SkPoint& p) {
99 needSpace(1, this->indexScale());
100
Brian Salomon763abf02018-05-01 18:49:38 +0000101 if (this->isIndexed()) {
Brian Osman49b7b6f2017-06-20 14:43:58 -0400102 uint16_t prevIdx = this->currentIndex() - 1;
103 appendCountourEdgeIndices(prevIdx);
104 }
105 *(fCurVert++) = p;
106 }
107
108 void addQuad(const SkPoint pts[], SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol) {
109 this->needSpace(GrPathUtils::kMaxPointsPerCurve,
110 GrPathUtils::kMaxPointsPerCurve * this->indexScale());
111
112 // First pt of quad is the pt we ended on in previous step
113 uint16_t firstQPtIdx = this->currentIndex() - 1;
114 uint16_t numPts = (uint16_t)GrPathUtils::generateQuadraticPoints(
115 pts[0], pts[1], pts[2], srcSpaceTolSqd, &fCurVert,
116 GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
Brian Salomon763abf02018-05-01 18:49:38 +0000117 if (this->isIndexed()) {
Brian Osman49b7b6f2017-06-20 14:43:58 -0400118 for (uint16_t i = 0; i < numPts; ++i) {
119 appendCountourEdgeIndices(firstQPtIdx + i);
120 }
egdanielaf18a092015-01-05 10:22:28 -0800121 }
122 }
Brian Osman49b7b6f2017-06-20 14:43:58 -0400123
124 void addConic(SkScalar weight, const SkPoint pts[], SkScalar srcSpaceTolSqd,
125 SkScalar srcSpaceTol) {
126 SkAutoConicToQuads converter;
127 const SkPoint* quadPts = converter.computeQuads(pts, weight, srcSpaceTol);
128 for (int i = 0; i < converter.countQuads(); ++i) {
129 this->addQuad(quadPts + i * 2, srcSpaceTolSqd, srcSpaceTol);
130 }
131 }
132
133 void addCubic(const SkPoint pts[], SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol) {
134 this->needSpace(GrPathUtils::kMaxPointsPerCurve,
135 GrPathUtils::kMaxPointsPerCurve * this->indexScale());
136
137 // First pt of cubic is the pt we ended on in previous step
138 uint16_t firstCPtIdx = this->currentIndex() - 1;
139 uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
140 pts[0], pts[1], pts[2], pts[3], srcSpaceTolSqd, &fCurVert,
141 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
Brian Salomon763abf02018-05-01 18:49:38 +0000142 if (this->isIndexed()) {
Brian Osman49b7b6f2017-06-20 14:43:58 -0400143 for (uint16_t i = 0; i < numPts; ++i) {
144 appendCountourEdgeIndices(firstCPtIdx + i);
145 }
146 }
147 }
148
149 void addPath(const SkPath& path, SkScalar srcSpaceTol) {
150 SkScalar srcSpaceTolSqd = srcSpaceTol * srcSpaceTol;
151
152 SkPath::Iter iter(path, false);
153 SkPoint pts[4];
154
155 bool done = false;
156 while (!done) {
Mike Reedba7e9a62019-08-16 13:30:34 -0400157 SkPath::Verb verb = iter.next(pts);
Brian Osman49b7b6f2017-06-20 14:43:58 -0400158 switch (verb) {
159 case SkPath::kMove_Verb:
160 this->moveTo(pts[0]);
161 break;
162 case SkPath::kLine_Verb:
163 this->addLine(pts[1]);
164 break;
165 case SkPath::kConic_Verb:
166 this->addConic(iter.conicWeight(), pts, srcSpaceTolSqd, srcSpaceTol);
167 break;
168 case SkPath::kQuad_Verb:
169 this->addQuad(pts, srcSpaceTolSqd, srcSpaceTol);
170 break;
171 case SkPath::kCubic_Verb:
172 this->addCubic(pts, srcSpaceTolSqd, srcSpaceTol);
173 break;
174 case SkPath::kClose_Verb:
175 break;
176 case SkPath::kDone_Verb:
177 done = true;
178 }
179 }
180 }
181
182 static bool PathHasMultipleSubpaths(const SkPath& path) {
183 bool first = true;
184
185 SkPath::Iter iter(path, false);
186 SkPath::Verb verb;
187
188 SkPoint pts[4];
Mike Reedba7e9a62019-08-16 13:30:34 -0400189 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
Brian Osman49b7b6f2017-06-20 14:43:58 -0400190 if (SkPath::kMove_Verb == verb && !first) {
191 return true;
192 }
193 first = false;
194 }
195 return false;
196 }
197
198private:
199 /**
200 * Derived properties
201 * TODO: Cache some of these for better performance, rather than re-computing?
202 */
Brian Salomon763abf02018-05-01 18:49:38 +0000203 bool isIndexed() const {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000204 return GrPrimitiveType::kLines == fPrimitiveType ||
205 GrPrimitiveType::kTriangles == fPrimitiveType;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400206 }
207 bool isHairline() const {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000208 return GrPrimitiveType::kLines == fPrimitiveType ||
209 GrPrimitiveType::kLineStrip == fPrimitiveType;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400210 }
211 int indexScale() const {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000212 switch (fPrimitiveType) {
Brian Osman49b7b6f2017-06-20 14:43:58 -0400213 case GrPrimitiveType::kLines:
214 return 2;
215 case GrPrimitiveType::kTriangles:
216 return 3;
217 default:
218 return 0;
219 }
220 }
221
222 uint16_t currentIndex() const { return fCurVert - fVertices; }
223
Brian Osman49b7b6f2017-06-20 14:43:58 -0400224 // Allocate vertex and (possibly) index buffers
225 void allocNewBuffers() {
226 // Ensure that we always get enough verts for a worst-case quad/cubic, plus leftover points
227 // from previous mesh piece (up to two verts to continue fanning). If we can't get that
228 // many, ask for a much larger number. This needs to be fairly big to handle quads/cubics,
229 // which have a worst-case of 1k points.
230 static const int kMinVerticesPerChunk = GrPathUtils::kMaxPointsPerCurve + 2;
231 static const int kFallbackVerticesPerChunk = 16384;
232
233 fVertices = static_cast<SkPoint*>(fTarget->makeVertexSpaceAtLeast(fVertexStride,
234 kMinVerticesPerChunk,
235 kFallbackVerticesPerChunk,
236 &fVertexBuffer,
237 &fFirstVertex,
238 &fVerticesInChunk));
239
Brian Salomon763abf02018-05-01 18:49:38 +0000240 if (this->isIndexed()) {
Brian Osman49b7b6f2017-06-20 14:43:58 -0400241 // Similar to above: Ensure we get enough indices for one worst-case quad/cubic.
242 // No extra indices are needed for stitching, though. If we can't get that many, ask
243 // for enough to match our large vertex request.
244 const int kMinIndicesPerChunk = GrPathUtils::kMaxPointsPerCurve * this->indexScale();
245 const int kFallbackIndicesPerChunk = kFallbackVerticesPerChunk * this->indexScale();
246
247 fIndices = fTarget->makeIndexSpaceAtLeast(kMinIndicesPerChunk, kFallbackIndicesPerChunk,
248 &fIndexBuffer, &fFirstIndex,
249 &fIndicesInChunk);
250 }
Brian Osman3902d402017-06-20 15:36:31 -0400251
252 fCurVert = fVertices;
253 fCurIdx = fIndices;
254 fSubpathIndexStart = 0;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400255 }
256
257 void appendCountourEdgeIndices(uint16_t edgeV0Idx) {
258 // When drawing lines we're appending line segments along the countour. When applying the
259 // other fill rules we're drawing triangle fans around the start of the current (sub)path.
260 if (!this->isHairline()) {
261 *(fCurIdx++) = fSubpathIndexStart;
262 }
263 *(fCurIdx++) = edgeV0Idx;
264 *(fCurIdx++) = edgeV0Idx + 1;
265 }
266
267 // Emits a single draw with all accumulated vertex/index data
Robert Phillips9028bac2020-03-10 16:19:27 -0400268 void createMeshAndPutBackReserve() {
Brian Osman3902d402017-06-20 15:36:31 -0400269 int vertexCount = fCurVert - fVertices;
270 int indexCount = fCurIdx - fIndices;
271 SkASSERT(vertexCount <= fVerticesInChunk);
272 SkASSERT(indexCount <= fIndicesInChunk);
273
Chris Daltoneb694b72020-03-16 09:25:50 -0600274 GrSimpleMesh* mesh = nullptr;
Brian Salomon763abf02018-05-01 18:49:38 +0000275 if (this->isIndexed() ? SkToBool(indexCount) : SkToBool(vertexCount)) {
Robert Phillips9028bac2020-03-10 16:19:27 -0400276 mesh = fTarget->allocMesh();
Brian Salomon763abf02018-05-01 18:49:38 +0000277 if (!this->isIndexed()) {
Chris Dalton37c7bdd2020-03-13 09:21:12 -0600278 mesh->set(std::move(fVertexBuffer), vertexCount, fFirstVertex);
Brian Salomon763abf02018-05-01 18:49:38 +0000279 } else {
Brian Salomon12d22642019-01-29 14:38:50 -0500280 mesh->setIndexed(std::move(fIndexBuffer), indexCount, fFirstIndex, 0,
Chris Dalton37c7bdd2020-03-13 09:21:12 -0600281 vertexCount - 1, GrPrimitiveRestart::kNo, std::move(fVertexBuffer),
282 fFirstVertex);
Brian Osman49b7b6f2017-06-20 14:43:58 -0400283 }
Brian Osman49b7b6f2017-06-20 14:43:58 -0400284 }
Brian Osman3902d402017-06-20 15:36:31 -0400285
286 fTarget->putBackIndices((size_t)(fIndicesInChunk - indexCount));
287 fTarget->putBackVertices((size_t)(fVerticesInChunk - vertexCount), fVertexStride);
Robert Phillips9028bac2020-03-10 16:19:27 -0400288
289 if (mesh) {
290 fMeshes->push_back(mesh);
291 }
Brian Osman49b7b6f2017-06-20 14:43:58 -0400292 }
293
294 void needSpace(int vertsNeeded, int indicesNeeded = 0) {
295 if (fCurVert + vertsNeeded > fVertices + fVerticesInChunk ||
296 fCurIdx + indicesNeeded > fIndices + fIndicesInChunk) {
297 // We are about to run out of space (possibly)
298
299 // To maintain continuity, we need to remember one or two points from the current mesh.
300 // Lines only need the last point, fills need the first point from the current contour.
301 // We always grab both here, and append the ones we need at the end of this process.
302 SkPoint lastPt = *(fCurVert - 1);
Brian Osman3902d402017-06-20 15:36:31 -0400303 SkASSERT(fSubpathIndexStart < fVerticesInChunk);
304 SkPoint subpathStartPt = fVertices[fSubpathIndexStart];
Brian Osman49b7b6f2017-06-20 14:43:58 -0400305
Brian Osman3902d402017-06-20 15:36:31 -0400306 // Draw the mesh we've accumulated, and put back any unused space
Robert Phillips9028bac2020-03-10 16:19:27 -0400307 this->createMeshAndPutBackReserve();
Brian Osman49b7b6f2017-06-20 14:43:58 -0400308
Brian Osman3902d402017-06-20 15:36:31 -0400309 // Get new buffers
Brian Osman49b7b6f2017-06-20 14:43:58 -0400310 this->allocNewBuffers();
311
Brian Osman49b7b6f2017-06-20 14:43:58 -0400312 // Append copies of the points we saved so the two meshes will weld properly
313 if (!this->isHairline()) {
314 *(fCurVert++) = subpathStartPt;
315 }
316 *(fCurVert++) = lastPt;
317 }
318 }
319
Brian Salomon7eae3e02018-08-07 14:02:38 +0000320 GrPrimitiveType fPrimitiveType;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400321 GrMeshDrawOp::Target* fTarget;
322 size_t fVertexStride;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400323
Brian Salomon12d22642019-01-29 14:38:50 -0500324 sk_sp<const GrBuffer> fVertexBuffer;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400325 int fFirstVertex;
326 int fVerticesInChunk;
327 SkPoint* fVertices;
328 SkPoint* fCurVert;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400329
Brian Salomon12d22642019-01-29 14:38:50 -0500330 sk_sp<const GrBuffer> fIndexBuffer;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400331 int fFirstIndex;
332 int fIndicesInChunk;
333 uint16_t* fIndices;
334 uint16_t* fCurIdx;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400335 uint16_t fSubpathIndexStart;
Robert Phillips9028bac2020-03-10 16:19:27 -0400336
Chris Daltoneb694b72020-03-16 09:25:50 -0600337 SkTDArray<GrSimpleMesh*>* fMeshes;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400338};
egdanielaf18a092015-01-05 10:22:28 -0800339
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400340class DefaultPathOp final : public GrMeshDrawOp {
341private:
342 using Helper = GrSimpleMeshDrawOpHelperWithStencil;
343
joshualitt332c7292015-02-23 08:44:31 -0800344public:
Brian Salomon25a88092016-12-01 09:36:50 -0500345 DEFINE_OP_CLASS_ID
reed1b55a962015-09-17 20:16:13 -0700346
Herb Derbyc76d4092020-10-07 16:46:15 -0400347 static GrOp::Owner Make(GrRecordingContext* context,
348 GrPaint&& paint,
349 const SkPath& path,
350 SkScalar tolerance,
351 uint8_t coverage,
352 const SkMatrix& viewMatrix,
353 bool isHairline,
354 GrAAType aaType,
355 const SkRect& devBounds,
356 const GrUserStencilSettings* stencilSettings) {
Robert Phillips7c525e62018-06-12 10:11:12 -0400357 return Helper::FactoryHelper<DefaultPathOp>(context, std::move(paint), path, tolerance,
358 coverage, viewMatrix, isHairline, aaType,
359 devBounds, stencilSettings);
bsalomon@google.com30085192011-08-19 15:42:31 +0000360 }
361
Brian Salomon780dad12016-12-15 18:08:40 -0500362 const char* name() const override { return "DefaultPathOp"; }
bsalomon@google.com30085192011-08-19 15:42:31 +0000363
Chris Dalton1706cbf2019-05-21 19:35:29 -0600364 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillips9028bac2020-03-10 16:19:27 -0400365 if (fProgramInfo) {
Chris Daltonbe457422020-03-16 18:05:03 -0600366 fProgramInfo->visitFPProxies(func);
Robert Phillips9028bac2020-03-10 16:19:27 -0400367 } else {
368 fHelper.visitProxies(func);
369 }
Robert Phillipsb493eeb2017-09-13 13:10:52 -0400370 }
371
Herb Derbyc76d4092020-10-07 16:46:15 -0400372 DefaultPathOp(GrProcessorSet* processorSet, const SkPMColor4f& color, const SkPath& path,
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400373 SkScalar tolerance, uint8_t coverage, const SkMatrix& viewMatrix, bool isHairline,
374 GrAAType aaType, const SkRect& devBounds,
375 const GrUserStencilSettings* stencilSettings)
Brian Salomon780dad12016-12-15 18:08:40 -0500376 : INHERITED(ClassID())
Herb Derbyc76d4092020-10-07 16:46:15 -0400377 , fHelper(processorSet, aaType, stencilSettings)
Brian Salomon780dad12016-12-15 18:08:40 -0500378 , fColor(color)
379 , fCoverage(coverage)
380 , fViewMatrix(viewMatrix)
381 , fIsHairline(isHairline) {
382 fPaths.emplace_back(PathData{path, tolerance});
joshualitt332c7292015-02-23 08:44:31 -0800383
Greg Daniel5faf4742019-10-01 15:14:44 -0400384 HasAABloat aaBloat = (aaType == GrAAType::kNone) ? HasAABloat ::kNo : HasAABloat::kYes;
385 this->setBounds(devBounds, aaBloat,
386 isHairline ? IsHairline::kYes : IsHairline::kNo);
Brian Salomon780dad12016-12-15 18:08:40 -0500387 }
388
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400389 FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
390
Chris Dalton6ce447a2019-06-23 18:07:38 -0600391 GrProcessorSet::Analysis finalize(
392 const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
393 GrClampType clampType) override {
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400394 GrProcessorAnalysisCoverage gpCoverage =
395 this->coverage() == 0xFF ? GrProcessorAnalysisCoverage::kNone
396 : GrProcessorAnalysisCoverage::kSingleChannel;
Brian Osman8fa7ab42019-03-18 10:22:42 -0400397 // This Op uses uniform (not vertex) color, so doesn't need to track wide color.
398 return fHelper.finalizeProcessors(
Chris Dalton6ce447a2019-06-23 18:07:38 -0600399 caps, clip, hasMixedSampledCoverage, clampType, gpCoverage, &fColor, nullptr);
Brian Salomon92aee3d2016-12-21 09:20:25 -0500400 }
401
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400402private:
Robert Phillips9028bac2020-03-10 16:19:27 -0400403 GrPrimitiveType primType() const {
404 if (this->isHairline()) {
405 int instanceCount = fPaths.count();
406
407 // We avoid indices when we have a single hairline contour.
408 bool isIndexed = instanceCount > 1 ||
409 PathGeoBuilder::PathHasMultipleSubpaths(fPaths[0].fPath);
410
411 return isIndexed ? GrPrimitiveType::kLines : GrPrimitiveType::kLineStrip;
412 }
413
414 return GrPrimitiveType::kTriangles;
415 }
416
Robert Phillips2669a7b2020-03-12 12:07:19 -0400417 GrProgramInfo* programInfo() override { return fProgramInfo; }
418
Robert Phillips4133dc42020-03-11 15:55:55 -0400419 void onCreateProgramInfo(const GrCaps* caps,
420 SkArenaAlloc* arena,
Adlai Hollere2296f72020-11-19 13:41:26 -0500421 const GrSurfaceProxyView& writeView,
Robert Phillips4133dc42020-03-11 15:55:55 -0400422 GrAppliedClip&& appliedClip,
Greg Danield358cbe2020-09-11 09:33:54 -0400423 const GrXferProcessor::DstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500424 GrXferBarrierFlags renderPassXferBarriers,
425 GrLoadOp colorLoadOp) override {
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500426 GrGeometryProcessor* gp;
joshualittdf0c5572015-08-03 11:35:28 -0700427 {
428 using namespace GrDefaultGeoProcFactory;
429 Color color(this->color());
430 Coverage coverage(this->coverage());
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400431 LocalCoords localCoords(fHelper.usesLocalCoords() ? LocalCoords::kUsePosition_Type
432 : LocalCoords::kUnused_Type);
Robert Phillips9028bac2020-03-10 16:19:27 -0400433 gp = GrDefaultGeoProcFactory::Make(arena,
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400434 color,
435 coverage,
436 localCoords,
437 this->viewMatrix());
joshualittdf0c5572015-08-03 11:35:28 -0700438 }
joshualitt332c7292015-02-23 08:44:31 -0800439
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500440 SkASSERT(gp->vertexStride() == sizeof(SkPoint));
joshualitt332c7292015-02-23 08:44:31 -0800441
Brian Salomon8afde5f2020-04-01 16:22:00 -0400442 fProgramInfo = fHelper.createProgramInfoWithStencil(caps, arena, writeView,
Robert Phillips4133dc42020-03-11 15:55:55 -0400443 std::move(appliedClip),
Greg Danield358cbe2020-09-11 09:33:54 -0400444 dstProxyView, gp, this->primType(),
Greg Daniel42dbca52020-11-20 10:22:43 -0500445 renderPassXferBarriers, colorLoadOp);
Brian Salomon763abf02018-05-01 18:49:38 +0000446
Robert Phillips9028bac2020-03-10 16:19:27 -0400447 }
Brian Osman7f95dfc2017-06-09 14:43:49 +0000448
Robert Phillips9028bac2020-03-10 16:19:27 -0400449 void onPrepareDraws(Target* target) override {
450 PathGeoBuilder pathGeoBuilder(this->primType(), target, &fMeshes);
Brian Osman7f95dfc2017-06-09 14:43:49 +0000451
452 // fill buffers
Robert Phillips9028bac2020-03-10 16:19:27 -0400453 for (int i = 0; i < fPaths.count(); i++) {
Brian Salomon763abf02018-05-01 18:49:38 +0000454 const PathData& args = fPaths[i];
455 pathGeoBuilder.addPath(args.fPath, args.fTolerance);
Brian Osman7f95dfc2017-06-09 14:43:49 +0000456 }
joshualitt332c7292015-02-23 08:44:31 -0800457 }
458
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700459 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
Robert Phillips9028bac2020-03-10 16:19:27 -0400460 if (!fProgramInfo) {
Robert Phillips4133dc42020-03-11 15:55:55 -0400461 this->createProgramInfo(flushState);
Robert Phillips9028bac2020-03-10 16:19:27 -0400462 }
Robert Phillips3968fcb2019-12-05 16:40:31 -0500463
Robert Phillips9028bac2020-03-10 16:19:27 -0400464 if (!fProgramInfo || !fMeshes.count()) {
465 return;
466 }
467
Chris Dalton765ed362020-03-16 17:34:44 -0600468 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
469 flushState->bindTextures(fProgramInfo->primProc(), nullptr, fProgramInfo->pipeline());
Robert Phillips9028bac2020-03-10 16:19:27 -0400470 for (int i = 0; i < fMeshes.count(); ++i) {
Chris Dalton765ed362020-03-16 17:34:44 -0600471 flushState->drawMesh(*fMeshes[i]);
Robert Phillips9028bac2020-03-10 16:19:27 -0400472 }
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700473 }
474
Herb Derbye25c3002020-10-27 15:57:27 -0400475 CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override {
Brian Salomon780dad12016-12-15 18:08:40 -0500476 DefaultPathOp* that = t->cast<DefaultPathOp>();
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400477 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000478 return CombineResult::kCannotCombine;
joshualitt8cab9a72015-07-16 09:13:50 -0700479 }
480
joshualitt332c7292015-02-23 08:44:31 -0800481 if (this->color() != that->color()) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000482 return CombineResult::kCannotCombine;
joshualitt332c7292015-02-23 08:44:31 -0800483 }
484
485 if (this->coverage() != that->coverage()) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000486 return CombineResult::kCannotCombine;
joshualitt332c7292015-02-23 08:44:31 -0800487 }
488
Mike Reed2c383152019-12-18 16:47:47 -0500489 if (!SkMatrixPriv::CheapEqual(this->viewMatrix(), that->viewMatrix())) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000490 return CombineResult::kCannotCombine;
joshualitt332c7292015-02-23 08:44:31 -0800491 }
492
493 if (this->isHairline() != that->isHairline()) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000494 return CombineResult::kCannotCombine;
joshualitt332c7292015-02-23 08:44:31 -0800495 }
496
Brian Salomon780dad12016-12-15 18:08:40 -0500497 fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
Brian Salomon7eae3e02018-08-07 14:02:38 +0000498 return CombineResult::kMerged;
joshualitt332c7292015-02-23 08:44:31 -0800499 }
500
John Stilesaf366522020-08-13 09:57:34 -0400501#if GR_TEST_UTILS
502 SkString onDumpInfo() const override {
503 SkString string = SkStringPrintf("Color: 0x%08x Count: %d\n",
504 fColor.toBytes_RGBA(), fPaths.count());
505 for (const auto& path : fPaths) {
506 string.appendf("Tolerance: %.2f\n", path.fTolerance);
507 }
508 string += fHelper.dumpInfo();
509 return string;
510 }
511#endif
512
Brian Osmancf860852018-10-31 14:04:39 -0400513 const SkPMColor4f& color() const { return fColor; }
Brian Salomon780dad12016-12-15 18:08:40 -0500514 uint8_t coverage() const { return fCoverage; }
Brian Salomon780dad12016-12-15 18:08:40 -0500515 const SkMatrix& viewMatrix() const { return fViewMatrix; }
516 bool isHairline() const { return fIsHairline; }
bsalomon@google.com30085192011-08-19 15:42:31 +0000517
Brian Salomon780dad12016-12-15 18:08:40 -0500518 struct PathData {
bsalomon0432dd62016-06-30 07:19:27 -0700519 SkPath fPath;
520 SkScalar fTolerance;
521 };
522
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400523 SkSTArray<1, PathData, true> fPaths;
524 Helper fHelper;
Brian Osmancf860852018-10-31 14:04:39 -0400525 SkPMColor4f fColor;
Brian Salomon780dad12016-12-15 18:08:40 -0500526 uint8_t fCoverage;
527 SkMatrix fViewMatrix;
Brian Salomon780dad12016-12-15 18:08:40 -0500528 bool fIsHairline;
reed1b55a962015-09-17 20:16:13 -0700529
Chris Daltoneb694b72020-03-16 09:25:50 -0600530 SkTDArray<GrSimpleMesh*> fMeshes;
531 GrProgramInfo* fProgramInfo = nullptr;
Robert Phillips9028bac2020-03-10 16:19:27 -0400532
John Stiles7571f9e2020-09-02 22:42:33 -0400533 using INHERITED = GrMeshDrawOp;
joshualitt332c7292015-02-23 08:44:31 -0800534};
bsalomon@google.com30085192011-08-19 15:42:31 +0000535
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400536} // anonymous namespace
537
Brian Osman11052242016-10-27 14:47:55 -0400538bool GrDefaultPathRenderer::internalDrawPath(GrRenderTargetContext* renderTargetContext,
Brian Salomon82f44312017-01-11 13:42:54 -0500539 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500540 GrAAType aaType,
robertphillipsd2b6d642016-07-21 08:55:08 -0700541 const GrUserStencilSettings& userStencilSettings,
Michael Ludwig7c12e282020-05-29 09:54:07 -0400542 const GrClip* clip,
joshualitt8059eb92014-12-29 15:10:07 -0800543 const SkMatrix& viewMatrix,
Michael Ludwig2686d692020-04-17 20:21:37 +0000544 const GrStyledShape& shape,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000545 bool stencilOnly) {
Robert Phillipsb97da532019-02-12 15:24:12 -0500546 auto context = renderTargetContext->surfPriv().getContext();
Robert Phillips7c525e62018-06-12 10:11:12 -0400547
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500548 SkASSERT(GrAAType::kCoverage != aaType);
bsalomon8acedde2016-06-24 10:42:16 -0700549 SkPath path;
550 shape.asPath(&path);
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000551
552 SkScalar hairlineCoverage;
joshualitt2e3b3e32014-12-09 13:31:14 -0800553 uint8_t newCoverage = 0xff;
bsalomon6663acf2016-05-10 09:14:17 -0700554 bool isHairline = false;
bsalomon8acedde2016-06-24 10:42:16 -0700555 if (IsStrokeHairlineOrEquivalent(shape.style(), viewMatrix, &hairlineCoverage)) {
joshualitt2e3b3e32014-12-09 13:31:14 -0800556 newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
bsalomon6663acf2016-05-10 09:14:17 -0700557 isHairline = true;
558 } else {
bsalomon8acedde2016-06-24 10:42:16 -0700559 SkASSERT(shape.style().isSimpleFill());
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000560 }
561
cdalton93a379b2016-05-11 13:58:08 -0700562 int passCount = 0;
Brian Salomonf0861672017-05-08 11:10:10 -0400563 const GrUserStencilSettings* passes[2];
cdalton93a379b2016-05-11 13:58:08 -0700564 bool reverse = false;
565 bool lastPassIsBounds;
bsalomon@google.com30085192011-08-19 15:42:31 +0000566
joshualitt332c7292015-02-23 08:44:31 -0800567 if (isHairline) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000568 passCount = 1;
569 if (stencilOnly) {
570 passes[0] = &gDirectToStencil;
571 } else {
robertphillipsd2b6d642016-07-21 08:55:08 -0700572 passes[0] = &userStencilSettings;
bsalomon@google.com30085192011-08-19 15:42:31 +0000573 }
574 lastPassIsBounds = false;
bsalomon@google.com30085192011-08-19 15:42:31 +0000575 } else {
bsalomon8acedde2016-06-24 10:42:16 -0700576 if (single_pass_shape(shape)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000577 passCount = 1;
578 if (stencilOnly) {
579 passes[0] = &gDirectToStencil;
580 } else {
robertphillipsd2b6d642016-07-21 08:55:08 -0700581 passes[0] = &userStencilSettings;
bsalomon@google.com30085192011-08-19 15:42:31 +0000582 }
bsalomon@google.com30085192011-08-19 15:42:31 +0000583 lastPassIsBounds = false;
584 } else {
Mike Reedcf0e3c62019-12-03 16:26:15 -0500585 switch (path.getFillType()) {
Mike Reed7d34dc72019-11-26 12:17:17 -0500586 case SkPathFillType::kInverseEvenOdd:
bsalomon@google.com30085192011-08-19 15:42:31 +0000587 reverse = true;
John Stiles30212b72020-06-11 17:55:07 -0400588 [[fallthrough]];
Mike Reed7d34dc72019-11-26 12:17:17 -0500589 case SkPathFillType::kEvenOdd:
bsalomon@google.com30085192011-08-19 15:42:31 +0000590 passes[0] = &gEOStencilPass;
591 if (stencilOnly) {
592 passCount = 1;
593 lastPassIsBounds = false;
594 } else {
595 passCount = 2;
596 lastPassIsBounds = true;
597 if (reverse) {
598 passes[1] = &gInvEOColorPass;
599 } else {
600 passes[1] = &gEOColorPass;
601 }
602 }
bsalomon@google.com30085192011-08-19 15:42:31 +0000603 break;
604
Mike Reed7d34dc72019-11-26 12:17:17 -0500605 case SkPathFillType::kInverseWinding:
bsalomon@google.com30085192011-08-19 15:42:31 +0000606 reverse = true;
John Stiles30212b72020-06-11 17:55:07 -0400607 [[fallthrough]];
Mike Reed7d34dc72019-11-26 12:17:17 -0500608 case SkPathFillType::kWinding:
Brian Salomon15b25092017-05-08 11:10:53 -0400609 passes[0] = &gWindStencilPass;
Brian Salomonf0861672017-05-08 11:10:10 -0400610 passCount = 2;
bsalomon@google.com30085192011-08-19 15:42:31 +0000611 if (stencilOnly) {
612 lastPassIsBounds = false;
613 --passCount;
614 } else {
615 lastPassIsBounds = true;
bsalomon@google.com30085192011-08-19 15:42:31 +0000616 if (reverse) {
617 passes[passCount-1] = &gInvWindColorPass;
618 } else {
619 passes[passCount-1] = &gWindColorPass;
620 }
621 }
622 break;
623 default:
mtklein@google.com330313a2013-08-22 15:37:26 +0000624 SkDEBUGFAIL("Unknown path fFill!");
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000625 return false;
bsalomon@google.com30085192011-08-19 15:42:31 +0000626 }
627 }
628 }
629
senorblanco2b4bb072015-04-22 13:45:18 -0700630 SkScalar tol = GrPathUtils::kDefaultTolerance;
joshualitt332c7292015-02-23 08:44:31 -0800631 SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds());
632
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000633 SkRect devBounds;
Robert Phillipse9462dd2019-10-23 12:41:29 -0400634 GetPathDevBounds(path, renderTargetContext->asRenderTargetProxy()->backingStoreDimensions(),
Robert Phillipsec325342017-10-30 18:02:48 +0000635 viewMatrix, &devBounds);
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000636
bsalomon@google.com30085192011-08-19 15:42:31 +0000637 for (int p = 0; p < passCount; ++p) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000638 if (lastPassIsBounds && (p == passCount-1)) {
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000639 SkRect bounds;
joshualittd27f73e2014-12-29 07:43:36 -0800640 SkMatrix localMatrix = SkMatrix::I();
bsalomon@google.com30085192011-08-19 15:42:31 +0000641 if (reverse) {
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000642 // draw over the dev bounds (which will be the whole dst surface for inv fill).
643 bounds = devBounds;
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000644 SkMatrix vmi;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000645 // mapRect through persp matrix may not be correct
joshualitt8059eb92014-12-29 15:10:07 -0800646 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000647 vmi.mapRect(&bounds);
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000648 } else {
joshualittd27f73e2014-12-29 07:43:36 -0800649 if (!viewMatrix.invert(&localMatrix)) {
650 return false;
651 }
bsalomon@google.com30085192011-08-19 15:42:31 +0000652 }
653 } else {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000654 bounds = path.getBounds();
bsalomon@google.com30085192011-08-19 15:42:31 +0000655 }
joshualitt8059eb92014-12-29 15:10:07 -0800656 const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
657 viewMatrix;
Michael Ludwig72ab3462018-12-10 12:43:36 -0500658 // This is a non-coverage aa rect op since we assert aaType != kCoverage at the start
Mike Klein16885072018-12-11 09:54:31 -0500659 assert_alive(paint);
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400660 renderTargetContext->priv().stencilRect(clip, passes[p], std::move(paint),
661 GrAA(aaType == GrAAType::kMSAA), viewM, bounds, &localMatrix);
robertphillips976f5f02016-06-03 10:59:20 -0700662 } else {
Brian Salomond4652ca2017-01-13 12:11:36 -0500663 bool stencilPass = stencilOnly || passCount > 1;
Herb Derbyc76d4092020-10-07 16:46:15 -0400664 GrOp::Owner op;
Brian Salomond4652ca2017-01-13 12:11:36 -0500665 if (stencilPass) {
Brian Salomonb74ef032017-08-10 12:46:01 -0400666 GrPaint stencilPaint;
667 stencilPaint.setXPFactory(GrDisableColorXPFactory::Get());
Robert Phillips7c525e62018-06-12 10:11:12 -0400668 op = DefaultPathOp::Make(context, std::move(stencilPaint), path, srcSpaceTol,
669 newCoverage, viewMatrix, isHairline, aaType, devBounds,
670 passes[p]);
Brian Salomonb74ef032017-08-10 12:46:01 -0400671 } else {
Mike Klein16885072018-12-11 09:54:31 -0500672 assert_alive(paint);
Robert Phillips7c525e62018-06-12 10:11:12 -0400673 op = DefaultPathOp::Make(context, std::move(paint), path, srcSpaceTol, newCoverage,
Brian Salomonb74ef032017-08-10 12:46:01 -0400674 viewMatrix, isHairline, aaType, devBounds, passes[p]);
Brian Salomond4652ca2017-01-13 12:11:36 -0500675 }
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400676 renderTargetContext->addDrawOp(clip, std::move(op));
bsalomon@google.com30085192011-08-19 15:42:31 +0000677 }
678 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000679 return true;
bsalomon@google.com30085192011-08-19 15:42:31 +0000680}
681
Chris Dalton5ed44232017-09-07 13:22:46 -0600682GrPathRenderer::CanDrawPath
683GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
Chris Dalton09e56892019-03-13 00:22:01 -0600684 bool isHairline = IsStrokeHairlineOrEquivalent(
685 args.fShape->style(), *args.fViewMatrix, nullptr);
Eric Karl5c779752017-05-08 12:02:07 -0700686 // If we aren't a single_pass_shape or hairline, we require stencil buffers.
Greg Danielbe7fc462019-01-03 16:40:42 -0500687 if (!(single_pass_shape(*args.fShape) || isHairline) &&
688 (args.fCaps->avoidStencilBuffers() || args.fTargetIsWrappedVkSecondaryCB)) {
Chris Dalton5ed44232017-09-07 13:22:46 -0600689 return CanDrawPath::kNo;
Eric Karl5c779752017-05-08 12:02:07 -0700690 }
Chris Dalton09e56892019-03-13 00:22:01 -0600691 // If antialiasing is required, we only support MSAA.
Chris Dalton6ce447a2019-06-23 18:07:38 -0600692 if (GrAAType::kNone != args.fAAType && GrAAType::kMSAA != args.fAAType) {
Chris Dalton09e56892019-03-13 00:22:01 -0600693 return CanDrawPath::kNo;
694 }
695 // This can draw any path with any simple fill style.
696 if (!args.fShape->style().isSimpleFill() && !isHairline) {
Chris Dalton5ed44232017-09-07 13:22:46 -0600697 return CanDrawPath::kNo;
698 }
699 // This is the fallback renderer for when a path is too complicated for the others to draw.
700 return CanDrawPath::kAsBackup;
bsalomon@google.com30085192011-08-19 15:42:31 +0000701}
702
bsalomon0aff2fa2015-07-31 06:48:27 -0700703bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
Brian Osman11052242016-10-27 14:47:55 -0400704 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
robertphillips976f5f02016-06-03 10:59:20 -0700705 "GrDefaultPathRenderer::onDrawPath");
Chris Dalton6ce447a2019-06-23 18:07:38 -0600706 GrAAType aaType = (GrAAType::kNone != args.fAAType) ? GrAAType::kMSAA : GrAAType::kNone;
Chris Dalton09e56892019-03-13 00:22:01 -0600707
708 return this->internalDrawPath(
709 args.fRenderTargetContext, std::move(args.fPaint), aaType, *args.fUserStencilSettings,
Michael Ludwig7c12e282020-05-29 09:54:07 -0400710 args.fClip, *args.fViewMatrix, *args.fShape, false);
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000711}
712
bsalomon0aff2fa2015-07-31 06:48:27 -0700713void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
Brian Osman11052242016-10-27 14:47:55 -0400714 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
robertphillips976f5f02016-06-03 10:59:20 -0700715 "GrDefaultPathRenderer::onStencilPath");
bsalomon8acedde2016-06-24 10:42:16 -0700716 SkASSERT(!args.fShape->inverseFilled());
robertphillips976f5f02016-06-03 10:59:20 -0700717
718 GrPaint paint;
Brian Salomona1633922017-01-09 11:46:10 -0500719 paint.setXPFactory(GrDisableColorXPFactory::Get());
robertphillips976f5f02016-06-03 10:59:20 -0700720
Chris Dalton09e56892019-03-13 00:22:01 -0600721 auto aaType = (GrAA::kYes == args.fDoStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone;
722
723 this->internalDrawPath(
724 args.fRenderTargetContext, std::move(paint), aaType, GrUserStencilSettings::kUnused,
Michael Ludwig7c12e282020-05-29 09:54:07 -0400725 args.fClip, *args.fViewMatrix, *args.fShape, true);
bsalomon@google.com30085192011-08-19 15:42:31 +0000726}
joshualitt622d3ad2015-05-07 08:13:11 -0700727
728///////////////////////////////////////////////////////////////////////////////////////////////////
729
Hal Canary6f6961e2017-01-31 13:50:44 -0500730#if GR_TEST_UTILS
joshualitt622d3ad2015-05-07 08:13:11 -0700731
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400732GR_DRAW_OP_TEST_DEFINE(DefaultPathOp) {
joshualitt622d3ad2015-05-07 08:13:11 -0700733 SkMatrix viewMatrix = GrTest::TestMatrix(random);
734
Brian Salomon53e4c3c2016-12-21 11:38:53 -0500735 // For now just hairlines because the other types of draws require two ops.
736 // TODO we should figure out a way to combine the stencil and cover steps into one op.
bsalomon6663acf2016-05-10 09:14:17 -0700737 GrStyle style(SkStrokeRec::kHairline_InitStyle);
John Stiles31954bf2020-08-07 17:35:54 -0400738 const SkPath& path = GrTest::TestPath(random);
joshualitt622d3ad2015-05-07 08:13:11 -0700739
740 // Compute srcSpaceTol
741 SkRect bounds = path.getBounds();
742 SkScalar tol = GrPathUtils::kDefaultTolerance;
743 SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, bounds);
744
joshualitt622d3ad2015-05-07 08:13:11 -0700745 viewMatrix.mapRect(&bounds);
746 uint8_t coverage = GrRandomCoverage(random);
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400747 GrAAType aaType = GrAAType::kNone;
Chris Dalton6ce447a2019-06-23 18:07:38 -0600748 if (numSamples > 1 && random->nextBool()) {
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400749 aaType = GrAAType::kMSAA;
750 }
Robert Phillips7c525e62018-06-12 10:11:12 -0400751 return DefaultPathOp::Make(context, std::move(paint), path, srcSpaceTol, coverage, viewMatrix,
752 true, aaType, bounds, GrGetRandomStencil(random, context));
joshualitt622d3ad2015-05-07 08:13:11 -0700753}
754
755#endif