blob: 2f69421a9fd2fb137629bb8253c10089855dd7f9 [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
Robert Phillips461c5392021-08-17 16:42:51 -04008#include "src/gpu/ops/DefaultPathRenderer.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"
Chris Daltoneb694b72020-03-16 09:25:50 -060023#include "src/gpu/GrSimpleMesh.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/gpu/GrStyle.h"
Robert Phillips62214f72021-06-15 10:12:51 -040025#include "src/gpu/GrUtil.h"
Robert Phillips550de7f2021-07-06 16:28:52 -040026#include "src/gpu/effects/GrDisableColorXP.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"
Robert Phillips4dca8312021-07-28 15:13:20 -040031#include "src/gpu/v1/SurfaceDrawContext_v1.h"
joshualitt74417822015-08-07 11:42:16 -070032
bsalomon@google.com30085192011-08-19 15:42:31 +000033////////////////////////////////////////////////////////////////////////////////
34// Helpers for drawPath
35
Robert Phillips461c5392021-08-17 16:42:51 -040036namespace {
37
bsalomon@google.com30085192011-08-19 15:42:31 +000038#define STENCIL_OFF 0 // Always disable stencil (even when needed)
39
Robert Phillips461c5392021-08-17 16:42:51 -040040inline 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
Brian Osman49b7b6f2017-06-20 14:43:58 -040058class PathGeoBuilder {
59public:
Robert Phillips9028bac2020-03-10 16:19:27 -040060 PathGeoBuilder(GrPrimitiveType primitiveType,
Robert Phillips71143952021-06-17 14:55:07 -040061 GrMeshDrawTarget* target,
Chris Daltoneb694b72020-03-16 09:25:50 -060062 SkTDArray<GrSimpleMesh*>* meshes)
Brian Salomon7eae3e02018-08-07 14:02:38 +000063 : fPrimitiveType(primitiveType)
Brian Osman49b7b6f2017-06-20 14:43:58 -040064 , fTarget(target)
65 , fVertexStride(sizeof(SkPoint))
Brian Osman49b7b6f2017-06-20 14:43:58 -040066 , fFirstIndex(0)
67 , fIndicesInChunk(0)
Robert Phillips9028bac2020-03-10 16:19:27 -040068 , fIndices(nullptr)
69 , fMeshes(meshes) {
Brian Osman49b7b6f2017-06-20 14:43:58 -040070 this->allocNewBuffers();
Brian Osmaneb86b702017-06-07 11:38:31 -040071 }
72
Brian Osman49b7b6f2017-06-20 14:43:58 -040073 ~PathGeoBuilder() {
Robert Phillips9028bac2020-03-10 16:19:27 -040074 this->createMeshAndPutBackReserve();
Brian Osman49b7b6f2017-06-20 14:43:58 -040075 }
76
77 /**
78 * Path verbs
79 */
80 void moveTo(const SkPoint& p) {
Robert Phillipsd1285c62021-06-29 07:29:58 -040081 if (!this->ensureSpace(1)) {
82 return;
83 }
Brian Osman49b7b6f2017-06-20 14:43:58 -040084
Greg Daniel733ab112021-02-03 12:16:32 -050085 if (!this->isHairline()) {
86 fSubpathIndexStart = this->currentIndex();
87 fSubpathStartPoint = p;
Brian Osman49b7b6f2017-06-20 14:43:58 -040088 }
Greg Daniel30b355a2021-02-03 16:22:49 +000089 *(fCurVert++) = p;
Brian Osman49b7b6f2017-06-20 14:43:58 -040090 }
91
Greg Daniel733ab112021-02-03 12:16:32 -050092 void addLine(const SkPoint pts[]) {
Robert Phillipsd1285c62021-06-29 07:29:58 -040093 if (!this->ensureSpace(1, this->indexScale(), &pts[0])) {
94 return;
95 }
Greg Daniel733ab112021-02-03 12:16:32 -050096
97 if (this->isIndexed()) {
98 uint16_t prevIdx = this->currentIndex() - 1;
99 this->appendCountourEdgeIndices(prevIdx);
100 }
101 *(fCurVert++) = pts[1];
102 }
103
Brian Osman49b7b6f2017-06-20 14:43:58 -0400104 void addQuad(const SkPoint pts[], SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol) {
Robert Phillipsd1285c62021-06-29 07:29:58 -0400105 if (!this->ensureSpace(GrPathUtils::kMaxPointsPerCurve,
106 GrPathUtils::kMaxPointsPerCurve * this->indexScale(),
107 &pts[0])) {
108 return;
109 }
Brian Osman49b7b6f2017-06-20 14:43:58 -0400110
111 // First pt of quad is the pt we ended on in previous step
112 uint16_t firstQPtIdx = this->currentIndex() - 1;
113 uint16_t numPts = (uint16_t)GrPathUtils::generateQuadraticPoints(
114 pts[0], pts[1], pts[2], srcSpaceTolSqd, &fCurVert,
115 GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
Brian Salomon763abf02018-05-01 18:49:38 +0000116 if (this->isIndexed()) {
Brian Osman49b7b6f2017-06-20 14:43:58 -0400117 for (uint16_t i = 0; i < numPts; ++i) {
Greg Daniel733ab112021-02-03 12:16:32 -0500118 this->appendCountourEdgeIndices(firstQPtIdx + i);
Brian Osman49b7b6f2017-06-20 14:43:58 -0400119 }
egdanielaf18a092015-01-05 10:22:28 -0800120 }
121 }
Brian Osman49b7b6f2017-06-20 14:43:58 -0400122
123 void addConic(SkScalar weight, const SkPoint pts[], SkScalar srcSpaceTolSqd,
124 SkScalar srcSpaceTol) {
125 SkAutoConicToQuads converter;
126 const SkPoint* quadPts = converter.computeQuads(pts, weight, srcSpaceTol);
127 for (int i = 0; i < converter.countQuads(); ++i) {
128 this->addQuad(quadPts + i * 2, srcSpaceTolSqd, srcSpaceTol);
129 }
130 }
131
132 void addCubic(const SkPoint pts[], SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol) {
Robert Phillipsd1285c62021-06-29 07:29:58 -0400133 if (!this->ensureSpace(GrPathUtils::kMaxPointsPerCurve,
134 GrPathUtils::kMaxPointsPerCurve * this->indexScale(),
135 &pts[0])) {
136 return;
137 }
Brian Osman49b7b6f2017-06-20 14:43:58 -0400138
139 // First pt of cubic is the pt we ended on in previous step
140 uint16_t firstCPtIdx = this->currentIndex() - 1;
141 uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
142 pts[0], pts[1], pts[2], pts[3], srcSpaceTolSqd, &fCurVert,
143 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
Brian Salomon763abf02018-05-01 18:49:38 +0000144 if (this->isIndexed()) {
Brian Osman49b7b6f2017-06-20 14:43:58 -0400145 for (uint16_t i = 0; i < numPts; ++i) {
Greg Daniel733ab112021-02-03 12:16:32 -0500146 this->appendCountourEdgeIndices(firstCPtIdx + i);
Brian Osman49b7b6f2017-06-20 14:43:58 -0400147 }
148 }
149 }
150
151 void addPath(const SkPath& path, SkScalar srcSpaceTol) {
152 SkScalar srcSpaceTolSqd = srcSpaceTol * srcSpaceTol;
153
154 SkPath::Iter iter(path, false);
155 SkPoint pts[4];
156
157 bool done = false;
158 while (!done) {
Mike Reedba7e9a62019-08-16 13:30:34 -0400159 SkPath::Verb verb = iter.next(pts);
Brian Osman49b7b6f2017-06-20 14:43:58 -0400160 switch (verb) {
161 case SkPath::kMove_Verb:
162 this->moveTo(pts[0]);
163 break;
164 case SkPath::kLine_Verb:
Greg Daniel733ab112021-02-03 12:16:32 -0500165 this->addLine(pts);
Brian Osman49b7b6f2017-06-20 14:43:58 -0400166 break;
167 case SkPath::kConic_Verb:
168 this->addConic(iter.conicWeight(), pts, srcSpaceTolSqd, srcSpaceTol);
169 break;
170 case SkPath::kQuad_Verb:
171 this->addQuad(pts, srcSpaceTolSqd, srcSpaceTol);
172 break;
173 case SkPath::kCubic_Verb:
174 this->addCubic(pts, srcSpaceTolSqd, srcSpaceTol);
175 break;
176 case SkPath::kClose_Verb:
177 break;
178 case SkPath::kDone_Verb:
179 done = true;
180 }
181 }
182 }
183
184 static bool PathHasMultipleSubpaths(const SkPath& path) {
185 bool first = true;
186
187 SkPath::Iter iter(path, false);
188 SkPath::Verb verb;
189
190 SkPoint pts[4];
Mike Reedba7e9a62019-08-16 13:30:34 -0400191 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
Brian Osman49b7b6f2017-06-20 14:43:58 -0400192 if (SkPath::kMove_Verb == verb && !first) {
193 return true;
194 }
195 first = false;
196 }
197 return false;
198 }
199
200private:
201 /**
202 * Derived properties
203 * TODO: Cache some of these for better performance, rather than re-computing?
204 */
Brian Salomon763abf02018-05-01 18:49:38 +0000205 bool isIndexed() const {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000206 return GrPrimitiveType::kLines == fPrimitiveType ||
207 GrPrimitiveType::kTriangles == fPrimitiveType;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400208 }
209 bool isHairline() const {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000210 return GrPrimitiveType::kLines == fPrimitiveType ||
211 GrPrimitiveType::kLineStrip == fPrimitiveType;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400212 }
213 int indexScale() const {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000214 switch (fPrimitiveType) {
Brian Osman49b7b6f2017-06-20 14:43:58 -0400215 case GrPrimitiveType::kLines:
216 return 2;
217 case GrPrimitiveType::kTriangles:
218 return 3;
219 default:
220 return 0;
221 }
222 }
223
224 uint16_t currentIndex() const { return fCurVert - fVertices; }
225
Brian Osman49b7b6f2017-06-20 14:43:58 -0400226 // Allocate vertex and (possibly) index buffers
227 void allocNewBuffers() {
Robert Phillipsd1285c62021-06-29 07:29:58 -0400228 SkASSERT(fValid);
229
Brian Osman49b7b6f2017-06-20 14:43:58 -0400230 // Ensure that we always get enough verts for a worst-case quad/cubic, plus leftover points
231 // from previous mesh piece (up to two verts to continue fanning). If we can't get that
232 // many, ask for a much larger number. This needs to be fairly big to handle quads/cubics,
233 // which have a worst-case of 1k points.
234 static const int kMinVerticesPerChunk = GrPathUtils::kMaxPointsPerCurve + 2;
235 static const int kFallbackVerticesPerChunk = 16384;
236
237 fVertices = static_cast<SkPoint*>(fTarget->makeVertexSpaceAtLeast(fVertexStride,
238 kMinVerticesPerChunk,
239 kFallbackVerticesPerChunk,
240 &fVertexBuffer,
241 &fFirstVertex,
242 &fVerticesInChunk));
Robert Phillipsd1285c62021-06-29 07:29:58 -0400243 if (!fVertices) {
Robert Phillips461c5392021-08-17 16:42:51 -0400244 SkDebugf("WARNING: Failed to allocate vertex buffer for DefaultPathRenderer.\n");
Robert Phillipsd1285c62021-06-29 07:29:58 -0400245 fCurVert = nullptr;
246 fCurIdx = fIndices = nullptr;
247 fSubpathIndexStart = 0;
248 fValid = false;
249 return;
250 }
Brian Osman49b7b6f2017-06-20 14:43:58 -0400251
Brian Salomon763abf02018-05-01 18:49:38 +0000252 if (this->isIndexed()) {
Brian Osman49b7b6f2017-06-20 14:43:58 -0400253 // Similar to above: Ensure we get enough indices for one worst-case quad/cubic.
254 // No extra indices are needed for stitching, though. If we can't get that many, ask
255 // for enough to match our large vertex request.
256 const int kMinIndicesPerChunk = GrPathUtils::kMaxPointsPerCurve * this->indexScale();
257 const int kFallbackIndicesPerChunk = kFallbackVerticesPerChunk * this->indexScale();
258
259 fIndices = fTarget->makeIndexSpaceAtLeast(kMinIndicesPerChunk, kFallbackIndicesPerChunk,
260 &fIndexBuffer, &fFirstIndex,
261 &fIndicesInChunk);
Robert Phillipsd1285c62021-06-29 07:29:58 -0400262 if (!fIndices) {
Robert Phillips461c5392021-08-17 16:42:51 -0400263 SkDebugf("WARNING: Failed to allocate index buffer for DefaultPathRenderer.\n");
Robert Phillipsd1285c62021-06-29 07:29:58 -0400264 fVertices = nullptr;
265 fValid = false;
266 }
Brian Osman49b7b6f2017-06-20 14:43:58 -0400267 }
Brian Osman3902d402017-06-20 15:36:31 -0400268
269 fCurVert = fVertices;
270 fCurIdx = fIndices;
271 fSubpathIndexStart = 0;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400272 }
273
274 void appendCountourEdgeIndices(uint16_t edgeV0Idx) {
Robert Phillipsd1285c62021-06-29 07:29:58 -0400275 SkASSERT(fCurIdx);
276
Brian Osman49b7b6f2017-06-20 14:43:58 -0400277 // When drawing lines we're appending line segments along the countour. When applying the
278 // other fill rules we're drawing triangle fans around the start of the current (sub)path.
279 if (!this->isHairline()) {
280 *(fCurIdx++) = fSubpathIndexStart;
281 }
282 *(fCurIdx++) = edgeV0Idx;
283 *(fCurIdx++) = edgeV0Idx + 1;
284 }
285
286 // Emits a single draw with all accumulated vertex/index data
Robert Phillips9028bac2020-03-10 16:19:27 -0400287 void createMeshAndPutBackReserve() {
Robert Phillipsd1285c62021-06-29 07:29:58 -0400288 if (!fValid) {
289 return;
290 }
291
Brian Osman3902d402017-06-20 15:36:31 -0400292 int vertexCount = fCurVert - fVertices;
293 int indexCount = fCurIdx - fIndices;
294 SkASSERT(vertexCount <= fVerticesInChunk);
295 SkASSERT(indexCount <= fIndicesInChunk);
296
Chris Daltoneb694b72020-03-16 09:25:50 -0600297 GrSimpleMesh* mesh = nullptr;
Brian Salomon763abf02018-05-01 18:49:38 +0000298 if (this->isIndexed() ? SkToBool(indexCount) : SkToBool(vertexCount)) {
Robert Phillips9028bac2020-03-10 16:19:27 -0400299 mesh = fTarget->allocMesh();
Brian Salomon763abf02018-05-01 18:49:38 +0000300 if (!this->isIndexed()) {
Chris Dalton37c7bdd2020-03-13 09:21:12 -0600301 mesh->set(std::move(fVertexBuffer), vertexCount, fFirstVertex);
Brian Salomon763abf02018-05-01 18:49:38 +0000302 } else {
Brian Salomon12d22642019-01-29 14:38:50 -0500303 mesh->setIndexed(std::move(fIndexBuffer), indexCount, fFirstIndex, 0,
Chris Dalton37c7bdd2020-03-13 09:21:12 -0600304 vertexCount - 1, GrPrimitiveRestart::kNo, std::move(fVertexBuffer),
305 fFirstVertex);
Brian Osman49b7b6f2017-06-20 14:43:58 -0400306 }
Brian Osman49b7b6f2017-06-20 14:43:58 -0400307 }
Brian Osman3902d402017-06-20 15:36:31 -0400308
309 fTarget->putBackIndices((size_t)(fIndicesInChunk - indexCount));
310 fTarget->putBackVertices((size_t)(fVerticesInChunk - vertexCount), fVertexStride);
Robert Phillips9028bac2020-03-10 16:19:27 -0400311
312 if (mesh) {
313 fMeshes->push_back(mesh);
314 }
Brian Osman49b7b6f2017-06-20 14:43:58 -0400315 }
316
Robert Phillipsd1285c62021-06-29 07:29:58 -0400317 bool ensureSpace(int vertsNeeded, int indicesNeeded = 0, const SkPoint* lastPoint = nullptr) {
318 if (!fValid) {
319 return false;
320 }
321
Brian Osman49b7b6f2017-06-20 14:43:58 -0400322 if (fCurVert + vertsNeeded > fVertices + fVerticesInChunk ||
323 fCurIdx + indicesNeeded > fIndices + fIndicesInChunk) {
324 // We are about to run out of space (possibly)
325
Greg Daniel733ab112021-02-03 12:16:32 -0500326#ifdef SK_DEBUG
Brian Osman49b7b6f2017-06-20 14:43:58 -0400327 // To maintain continuity, we need to remember one or two points from the current mesh.
328 // Lines only need the last point, fills need the first point from the current contour.
329 // We always grab both here, and append the ones we need at the end of this process.
Brian Osman3902d402017-06-20 15:36:31 -0400330 SkASSERT(fSubpathIndexStart < fVerticesInChunk);
Greg Daniel733ab112021-02-03 12:16:32 -0500331 // This assert is reading from the gpu buffer fVertices and will be slow, but for debug
332 // that is okay.
333 if (!this->isHairline()) {
334 SkASSERT(fSubpathStartPoint == fVertices[fSubpathIndexStart]);
335 }
336 if (lastPoint) {
337 SkASSERT(*(fCurVert - 1) == *lastPoint);
338 }
339#endif
Brian Osman49b7b6f2017-06-20 14:43:58 -0400340
Brian Osman3902d402017-06-20 15:36:31 -0400341 // Draw the mesh we've accumulated, and put back any unused space
Robert Phillips9028bac2020-03-10 16:19:27 -0400342 this->createMeshAndPutBackReserve();
Brian Osman49b7b6f2017-06-20 14:43:58 -0400343
Brian Osman3902d402017-06-20 15:36:31 -0400344 // Get new buffers
Brian Osman49b7b6f2017-06-20 14:43:58 -0400345 this->allocNewBuffers();
Robert Phillipsd1285c62021-06-29 07:29:58 -0400346 if (!fValid) {
347 return false;
348 }
Brian Osman49b7b6f2017-06-20 14:43:58 -0400349
Greg Daniel733ab112021-02-03 12:16:32 -0500350 // On moves we don't need to copy over any points to the new buffer and we pass in a
351 // null lastPoint.
352 if (lastPoint) {
353 // Append copies of the points we saved so the two meshes will weld properly
354 if (!this->isHairline()) {
355 *(fCurVert++) = fSubpathStartPoint;
356 }
357 *(fCurVert++) = *lastPoint;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400358 }
Brian Osman49b7b6f2017-06-20 14:43:58 -0400359 }
Robert Phillipsd1285c62021-06-29 07:29:58 -0400360
361 return true;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400362 }
363
Brian Salomon7eae3e02018-08-07 14:02:38 +0000364 GrPrimitiveType fPrimitiveType;
Robert Phillips71143952021-06-17 14:55:07 -0400365 GrMeshDrawTarget* fTarget;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400366 size_t fVertexStride;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400367
Brian Salomon12d22642019-01-29 14:38:50 -0500368 sk_sp<const GrBuffer> fVertexBuffer;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400369 int fFirstVertex;
370 int fVerticesInChunk;
371 SkPoint* fVertices;
372 SkPoint* fCurVert;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400373
Brian Salomon12d22642019-01-29 14:38:50 -0500374 sk_sp<const GrBuffer> fIndexBuffer;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400375 int fFirstIndex;
376 int fIndicesInChunk;
377 uint16_t* fIndices;
378 uint16_t* fCurIdx;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400379 uint16_t fSubpathIndexStart;
Greg Daniel733ab112021-02-03 12:16:32 -0500380 SkPoint fSubpathStartPoint;
Robert Phillips9028bac2020-03-10 16:19:27 -0400381
Robert Phillipsd1285c62021-06-29 07:29:58 -0400382 bool fValid = true;
Chris Daltoneb694b72020-03-16 09:25:50 -0600383 SkTDArray<GrSimpleMesh*>* fMeshes;
Brian Osman49b7b6f2017-06-20 14:43:58 -0400384};
egdanielaf18a092015-01-05 10:22:28 -0800385
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400386class DefaultPathOp final : public GrMeshDrawOp {
387private:
388 using Helper = GrSimpleMeshDrawOpHelperWithStencil;
389
joshualitt332c7292015-02-23 08:44:31 -0800390public:
Brian Salomon25a88092016-12-01 09:36:50 -0500391 DEFINE_OP_CLASS_ID
reed1b55a962015-09-17 20:16:13 -0700392
Herb Derbyc76d4092020-10-07 16:46:15 -0400393 static GrOp::Owner Make(GrRecordingContext* context,
394 GrPaint&& paint,
395 const SkPath& path,
396 SkScalar tolerance,
397 uint8_t coverage,
398 const SkMatrix& viewMatrix,
399 bool isHairline,
400 GrAAType aaType,
401 const SkRect& devBounds,
402 const GrUserStencilSettings* stencilSettings) {
Robert Phillips7c525e62018-06-12 10:11:12 -0400403 return Helper::FactoryHelper<DefaultPathOp>(context, std::move(paint), path, tolerance,
404 coverage, viewMatrix, isHairline, aaType,
405 devBounds, stencilSettings);
bsalomon@google.com30085192011-08-19 15:42:31 +0000406 }
407
Brian Salomon780dad12016-12-15 18:08:40 -0500408 const char* name() const override { return "DefaultPathOp"; }
bsalomon@google.com30085192011-08-19 15:42:31 +0000409
Robert Phillips294723d2021-06-17 09:23:58 -0400410 void visitProxies(const GrVisitProxyFunc& func) const override {
Robert Phillips9028bac2020-03-10 16:19:27 -0400411 if (fProgramInfo) {
Chris Daltonbe457422020-03-16 18:05:03 -0600412 fProgramInfo->visitFPProxies(func);
Robert Phillips9028bac2020-03-10 16:19:27 -0400413 } else {
414 fHelper.visitProxies(func);
415 }
Robert Phillipsb493eeb2017-09-13 13:10:52 -0400416 }
417
Herb Derbyc76d4092020-10-07 16:46:15 -0400418 DefaultPathOp(GrProcessorSet* processorSet, const SkPMColor4f& color, const SkPath& path,
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400419 SkScalar tolerance, uint8_t coverage, const SkMatrix& viewMatrix, bool isHairline,
420 GrAAType aaType, const SkRect& devBounds,
421 const GrUserStencilSettings* stencilSettings)
Brian Salomon780dad12016-12-15 18:08:40 -0500422 : INHERITED(ClassID())
Herb Derbyc76d4092020-10-07 16:46:15 -0400423 , fHelper(processorSet, aaType, stencilSettings)
Brian Salomon780dad12016-12-15 18:08:40 -0500424 , fColor(color)
425 , fCoverage(coverage)
426 , fViewMatrix(viewMatrix)
427 , fIsHairline(isHairline) {
428 fPaths.emplace_back(PathData{path, tolerance});
joshualitt332c7292015-02-23 08:44:31 -0800429
Greg Daniel5faf4742019-10-01 15:14:44 -0400430 HasAABloat aaBloat = (aaType == GrAAType::kNone) ? HasAABloat ::kNo : HasAABloat::kYes;
431 this->setBounds(devBounds, aaBloat,
432 isHairline ? IsHairline::kYes : IsHairline::kNo);
Brian Salomon780dad12016-12-15 18:08:40 -0500433 }
434
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400435 FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
436
Chris Dalton57ab06c2021-04-22 12:57:28 -0600437 GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
438 GrClampType clampType) override {
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400439 GrProcessorAnalysisCoverage gpCoverage =
440 this->coverage() == 0xFF ? GrProcessorAnalysisCoverage::kNone
441 : GrProcessorAnalysisCoverage::kSingleChannel;
Brian Osman8fa7ab42019-03-18 10:22:42 -0400442 // This Op uses uniform (not vertex) color, so doesn't need to track wide color.
Chris Dalton57ab06c2021-04-22 12:57:28 -0600443 return fHelper.finalizeProcessors(caps, clip, clampType, gpCoverage, &fColor, nullptr);
Brian Salomon92aee3d2016-12-21 09:20:25 -0500444 }
445
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400446private:
Robert Phillips9028bac2020-03-10 16:19:27 -0400447 GrPrimitiveType primType() const {
448 if (this->isHairline()) {
449 int instanceCount = fPaths.count();
450
451 // We avoid indices when we have a single hairline contour.
452 bool isIndexed = instanceCount > 1 ||
453 PathGeoBuilder::PathHasMultipleSubpaths(fPaths[0].fPath);
454
455 return isIndexed ? GrPrimitiveType::kLines : GrPrimitiveType::kLineStrip;
456 }
457
458 return GrPrimitiveType::kTriangles;
459 }
460
Robert Phillips2669a7b2020-03-12 12:07:19 -0400461 GrProgramInfo* programInfo() override { return fProgramInfo; }
462
Robert Phillips4133dc42020-03-11 15:55:55 -0400463 void onCreateProgramInfo(const GrCaps* caps,
464 SkArenaAlloc* arena,
Adlai Hollere2296f72020-11-19 13:41:26 -0500465 const GrSurfaceProxyView& writeView,
Chris Dalton6aaf00f2021-07-13 13:26:39 -0600466 bool usesMSAASurface,
Robert Phillips4133dc42020-03-11 15:55:55 -0400467 GrAppliedClip&& appliedClip,
John Stiles52cb1d02021-06-02 11:58:05 -0400468 const GrDstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500469 GrXferBarrierFlags renderPassXferBarriers,
470 GrLoadOp colorLoadOp) override {
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500471 GrGeometryProcessor* gp;
joshualittdf0c5572015-08-03 11:35:28 -0700472 {
473 using namespace GrDefaultGeoProcFactory;
474 Color color(this->color());
475 Coverage coverage(this->coverage());
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400476 LocalCoords localCoords(fHelper.usesLocalCoords() ? LocalCoords::kUsePosition_Type
477 : LocalCoords::kUnused_Type);
Robert Phillips9028bac2020-03-10 16:19:27 -0400478 gp = GrDefaultGeoProcFactory::Make(arena,
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400479 color,
480 coverage,
481 localCoords,
482 this->viewMatrix());
joshualittdf0c5572015-08-03 11:35:28 -0700483 }
joshualitt332c7292015-02-23 08:44:31 -0800484
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500485 SkASSERT(gp->vertexStride() == sizeof(SkPoint));
joshualitt332c7292015-02-23 08:44:31 -0800486
Brian Salomon8afde5f2020-04-01 16:22:00 -0400487 fProgramInfo = fHelper.createProgramInfoWithStencil(caps, arena, writeView,
Robert Phillips4133dc42020-03-11 15:55:55 -0400488 std::move(appliedClip),
Greg Danield358cbe2020-09-11 09:33:54 -0400489 dstProxyView, gp, this->primType(),
Greg Daniel42dbca52020-11-20 10:22:43 -0500490 renderPassXferBarriers, colorLoadOp);
Brian Salomon763abf02018-05-01 18:49:38 +0000491
Robert Phillips9028bac2020-03-10 16:19:27 -0400492 }
Brian Osman7f95dfc2017-06-09 14:43:49 +0000493
Robert Phillips71143952021-06-17 14:55:07 -0400494 void onPrepareDraws(GrMeshDrawTarget* target) override {
Robert Phillips9028bac2020-03-10 16:19:27 -0400495 PathGeoBuilder pathGeoBuilder(this->primType(), target, &fMeshes);
Brian Osman7f95dfc2017-06-09 14:43:49 +0000496
497 // fill buffers
Robert Phillips9028bac2020-03-10 16:19:27 -0400498 for (int i = 0; i < fPaths.count(); i++) {
Brian Salomon763abf02018-05-01 18:49:38 +0000499 const PathData& args = fPaths[i];
500 pathGeoBuilder.addPath(args.fPath, args.fTolerance);
Brian Osman7f95dfc2017-06-09 14:43:49 +0000501 }
joshualitt332c7292015-02-23 08:44:31 -0800502 }
503
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700504 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
Robert Phillips9028bac2020-03-10 16:19:27 -0400505 if (!fProgramInfo) {
Robert Phillips4133dc42020-03-11 15:55:55 -0400506 this->createProgramInfo(flushState);
Robert Phillips9028bac2020-03-10 16:19:27 -0400507 }
Robert Phillips3968fcb2019-12-05 16:40:31 -0500508
Robert Phillips9028bac2020-03-10 16:19:27 -0400509 if (!fProgramInfo || !fMeshes.count()) {
510 return;
511 }
512
Chris Dalton765ed362020-03-16 17:34:44 -0600513 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
Robert Phillips787fd9d2021-03-22 14:48:09 -0400514 flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
Robert Phillips9028bac2020-03-10 16:19:27 -0400515 for (int i = 0; i < fMeshes.count(); ++i) {
Chris Dalton765ed362020-03-16 17:34:44 -0600516 flushState->drawMesh(*fMeshes[i]);
Robert Phillips9028bac2020-03-10 16:19:27 -0400517 }
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700518 }
519
Herb Derbye25c3002020-10-27 15:57:27 -0400520 CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override {
Brian Salomon780dad12016-12-15 18:08:40 -0500521 DefaultPathOp* that = t->cast<DefaultPathOp>();
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400522 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000523 return CombineResult::kCannotCombine;
joshualitt8cab9a72015-07-16 09:13:50 -0700524 }
525
joshualitt332c7292015-02-23 08:44:31 -0800526 if (this->color() != that->color()) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000527 return CombineResult::kCannotCombine;
joshualitt332c7292015-02-23 08:44:31 -0800528 }
529
530 if (this->coverage() != that->coverage()) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000531 return CombineResult::kCannotCombine;
joshualitt332c7292015-02-23 08:44:31 -0800532 }
533
Mike Reed2c383152019-12-18 16:47:47 -0500534 if (!SkMatrixPriv::CheapEqual(this->viewMatrix(), that->viewMatrix())) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000535 return CombineResult::kCannotCombine;
joshualitt332c7292015-02-23 08:44:31 -0800536 }
537
538 if (this->isHairline() != that->isHairline()) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000539 return CombineResult::kCannotCombine;
joshualitt332c7292015-02-23 08:44:31 -0800540 }
541
Brian Salomon780dad12016-12-15 18:08:40 -0500542 fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
Brian Salomon7eae3e02018-08-07 14:02:38 +0000543 return CombineResult::kMerged;
joshualitt332c7292015-02-23 08:44:31 -0800544 }
545
John Stilesaf366522020-08-13 09:57:34 -0400546#if GR_TEST_UTILS
547 SkString onDumpInfo() const override {
548 SkString string = SkStringPrintf("Color: 0x%08x Count: %d\n",
549 fColor.toBytes_RGBA(), fPaths.count());
550 for (const auto& path : fPaths) {
551 string.appendf("Tolerance: %.2f\n", path.fTolerance);
552 }
553 string += fHelper.dumpInfo();
554 return string;
555 }
556#endif
557
Brian Osmancf860852018-10-31 14:04:39 -0400558 const SkPMColor4f& color() const { return fColor; }
Brian Salomon780dad12016-12-15 18:08:40 -0500559 uint8_t coverage() const { return fCoverage; }
Brian Salomon780dad12016-12-15 18:08:40 -0500560 const SkMatrix& viewMatrix() const { return fViewMatrix; }
561 bool isHairline() const { return fIsHairline; }
bsalomon@google.com30085192011-08-19 15:42:31 +0000562
Brian Salomon780dad12016-12-15 18:08:40 -0500563 struct PathData {
bsalomon0432dd62016-06-30 07:19:27 -0700564 SkPath fPath;
565 SkScalar fTolerance;
566 };
567
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400568 SkSTArray<1, PathData, true> fPaths;
569 Helper fHelper;
Brian Osmancf860852018-10-31 14:04:39 -0400570 SkPMColor4f fColor;
Brian Salomon780dad12016-12-15 18:08:40 -0500571 uint8_t fCoverage;
572 SkMatrix fViewMatrix;
Brian Salomon780dad12016-12-15 18:08:40 -0500573 bool fIsHairline;
reed1b55a962015-09-17 20:16:13 -0700574
Chris Daltoneb694b72020-03-16 09:25:50 -0600575 SkTDArray<GrSimpleMesh*> fMeshes;
576 GrProgramInfo* fProgramInfo = nullptr;
Robert Phillips9028bac2020-03-10 16:19:27 -0400577
John Stiles7571f9e2020-09-02 22:42:33 -0400578 using INHERITED = GrMeshDrawOp;
joshualitt332c7292015-02-23 08:44:31 -0800579};
bsalomon@google.com30085192011-08-19 15:42:31 +0000580
Brian Salomonee3e0ba2017-07-13 16:40:46 -0400581} // anonymous namespace
582
Robert Phillips461c5392021-08-17 16:42:51 -0400583///////////////////////////////////////////////////////////////////////////////////////////////////
584
585#if GR_TEST_UTILS
586
587GR_DRAW_OP_TEST_DEFINE(DefaultPathOp) {
588 SkMatrix viewMatrix = GrTest::TestMatrix(random);
589
590 // For now just hairlines because the other types of draws require two ops.
591 // TODO we should figure out a way to combine the stencil and cover steps into one op.
592 GrStyle style(SkStrokeRec::kHairline_InitStyle);
593 const SkPath& path = GrTest::TestPath(random);
594
595 // Compute srcSpaceTol
596 SkRect bounds = path.getBounds();
597 SkScalar tol = GrPathUtils::kDefaultTolerance;
598 SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, bounds);
599
600 viewMatrix.mapRect(&bounds);
John Stiles9af527b2021-08-18 12:34:05 -0400601 uint8_t coverage = GrTest::RandomCoverage(random);
Robert Phillips461c5392021-08-17 16:42:51 -0400602 GrAAType aaType = GrAAType::kNone;
603 if (numSamples > 1 && random->nextBool()) {
604 aaType = GrAAType::kMSAA;
605 }
606 return DefaultPathOp::Make(context, std::move(paint), path, srcSpaceTol, coverage, viewMatrix,
607 true, aaType, bounds, GrGetRandomStencil(random, context));
608}
609
610#endif
611
612///////////////////////////////////////////////////////////////////////////////////////////////////
613
614namespace skgpu::v1 {
615
616bool DefaultPathRenderer::internalDrawPath(skgpu::v1::SurfaceDrawContext* sdc,
617 GrPaint&& paint,
618 GrAAType aaType,
619 const GrUserStencilSettings& userStencilSettings,
620 const GrClip* clip,
621 const SkMatrix& viewMatrix,
622 const GrStyledShape& shape,
623 bool stencilOnly) {
Robert Phillips4dca8312021-07-28 15:13:20 -0400624 auto context = sdc->recordingContext();
Robert Phillips7c525e62018-06-12 10:11:12 -0400625
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500626 SkASSERT(GrAAType::kCoverage != aaType);
bsalomon8acedde2016-06-24 10:42:16 -0700627 SkPath path;
628 shape.asPath(&path);
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000629
630 SkScalar hairlineCoverage;
joshualitt2e3b3e32014-12-09 13:31:14 -0800631 uint8_t newCoverage = 0xff;
bsalomon6663acf2016-05-10 09:14:17 -0700632 bool isHairline = false;
Robert Phillips62214f72021-06-15 10:12:51 -0400633 if (GrIsStrokeHairlineOrEquivalent(shape.style(), viewMatrix, &hairlineCoverage)) {
joshualitt2e3b3e32014-12-09 13:31:14 -0800634 newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
bsalomon6663acf2016-05-10 09:14:17 -0700635 isHairline = true;
636 } else {
bsalomon8acedde2016-06-24 10:42:16 -0700637 SkASSERT(shape.style().isSimpleFill());
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000638 }
639
cdalton93a379b2016-05-11 13:58:08 -0700640 int passCount = 0;
Brian Salomonf0861672017-05-08 11:10:10 -0400641 const GrUserStencilSettings* passes[2];
cdalton93a379b2016-05-11 13:58:08 -0700642 bool reverse = false;
643 bool lastPassIsBounds;
bsalomon@google.com30085192011-08-19 15:42:31 +0000644
joshualitt332c7292015-02-23 08:44:31 -0800645 if (isHairline) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000646 passCount = 1;
647 if (stencilOnly) {
648 passes[0] = &gDirectToStencil;
649 } else {
robertphillipsd2b6d642016-07-21 08:55:08 -0700650 passes[0] = &userStencilSettings;
bsalomon@google.com30085192011-08-19 15:42:31 +0000651 }
652 lastPassIsBounds = false;
bsalomon@google.com30085192011-08-19 15:42:31 +0000653 } else {
bsalomon8acedde2016-06-24 10:42:16 -0700654 if (single_pass_shape(shape)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000655 passCount = 1;
656 if (stencilOnly) {
657 passes[0] = &gDirectToStencil;
658 } else {
robertphillipsd2b6d642016-07-21 08:55:08 -0700659 passes[0] = &userStencilSettings;
bsalomon@google.com30085192011-08-19 15:42:31 +0000660 }
bsalomon@google.com30085192011-08-19 15:42:31 +0000661 lastPassIsBounds = false;
662 } else {
Mike Reedcf0e3c62019-12-03 16:26:15 -0500663 switch (path.getFillType()) {
Mike Reed7d34dc72019-11-26 12:17:17 -0500664 case SkPathFillType::kInverseEvenOdd:
bsalomon@google.com30085192011-08-19 15:42:31 +0000665 reverse = true;
John Stiles30212b72020-06-11 17:55:07 -0400666 [[fallthrough]];
Mike Reed7d34dc72019-11-26 12:17:17 -0500667 case SkPathFillType::kEvenOdd:
bsalomon@google.com30085192011-08-19 15:42:31 +0000668 passes[0] = &gEOStencilPass;
669 if (stencilOnly) {
670 passCount = 1;
671 lastPassIsBounds = false;
672 } else {
673 passCount = 2;
674 lastPassIsBounds = true;
675 if (reverse) {
676 passes[1] = &gInvEOColorPass;
677 } else {
678 passes[1] = &gEOColorPass;
679 }
680 }
bsalomon@google.com30085192011-08-19 15:42:31 +0000681 break;
682
Mike Reed7d34dc72019-11-26 12:17:17 -0500683 case SkPathFillType::kInverseWinding:
bsalomon@google.com30085192011-08-19 15:42:31 +0000684 reverse = true;
John Stiles30212b72020-06-11 17:55:07 -0400685 [[fallthrough]];
Mike Reed7d34dc72019-11-26 12:17:17 -0500686 case SkPathFillType::kWinding:
Brian Salomon15b25092017-05-08 11:10:53 -0400687 passes[0] = &gWindStencilPass;
Brian Salomonf0861672017-05-08 11:10:10 -0400688 passCount = 2;
bsalomon@google.com30085192011-08-19 15:42:31 +0000689 if (stencilOnly) {
690 lastPassIsBounds = false;
691 --passCount;
692 } else {
693 lastPassIsBounds = true;
bsalomon@google.com30085192011-08-19 15:42:31 +0000694 if (reverse) {
695 passes[passCount-1] = &gInvWindColorPass;
696 } else {
697 passes[passCount-1] = &gWindColorPass;
698 }
699 }
700 break;
701 default:
mtklein@google.com330313a2013-08-22 15:37:26 +0000702 SkDEBUGFAIL("Unknown path fFill!");
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000703 return false;
bsalomon@google.com30085192011-08-19 15:42:31 +0000704 }
705 }
706 }
707
senorblanco2b4bb072015-04-22 13:45:18 -0700708 SkScalar tol = GrPathUtils::kDefaultTolerance;
joshualitt332c7292015-02-23 08:44:31 -0800709 SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds());
710
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000711 SkRect devBounds;
Robert Phillips4dca8312021-07-28 15:13:20 -0400712 GetPathDevBounds(path, sdc->asRenderTargetProxy()->backingStoreDimensions(),
Robert Phillipsec325342017-10-30 18:02:48 +0000713 viewMatrix, &devBounds);
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000714
bsalomon@google.com30085192011-08-19 15:42:31 +0000715 for (int p = 0; p < passCount; ++p) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000716 if (lastPassIsBounds && (p == passCount-1)) {
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000717 SkRect bounds;
joshualittd27f73e2014-12-29 07:43:36 -0800718 SkMatrix localMatrix = SkMatrix::I();
bsalomon@google.com30085192011-08-19 15:42:31 +0000719 if (reverse) {
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000720 // draw over the dev bounds (which will be the whole dst surface for inv fill).
721 bounds = devBounds;
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000722 SkMatrix vmi;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000723 // mapRect through persp matrix may not be correct
joshualitt8059eb92014-12-29 15:10:07 -0800724 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000725 vmi.mapRect(&bounds);
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000726 } else {
joshualittd27f73e2014-12-29 07:43:36 -0800727 if (!viewMatrix.invert(&localMatrix)) {
728 return false;
729 }
bsalomon@google.com30085192011-08-19 15:42:31 +0000730 }
731 } else {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000732 bounds = path.getBounds();
bsalomon@google.com30085192011-08-19 15:42:31 +0000733 }
joshualitt8059eb92014-12-29 15:10:07 -0800734 const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
735 viewMatrix;
Michael Ludwig72ab3462018-12-10 12:43:36 -0500736 // This is a non-coverage aa rect op since we assert aaType != kCoverage at the start
Mike Klein16885072018-12-11 09:54:31 -0500737 assert_alive(paint);
Robert Phillips4dca8312021-07-28 15:13:20 -0400738 sdc->stencilRect(clip, passes[p], std::move(paint),
739 GrAA(aaType == GrAAType::kMSAA), viewM, bounds,
740 &localMatrix);
robertphillips976f5f02016-06-03 10:59:20 -0700741 } else {
Brian Salomond4652ca2017-01-13 12:11:36 -0500742 bool stencilPass = stencilOnly || passCount > 1;
Herb Derbyc76d4092020-10-07 16:46:15 -0400743 GrOp::Owner op;
Brian Salomond4652ca2017-01-13 12:11:36 -0500744 if (stencilPass) {
Brian Salomonb74ef032017-08-10 12:46:01 -0400745 GrPaint stencilPaint;
746 stencilPaint.setXPFactory(GrDisableColorXPFactory::Get());
Robert Phillips7c525e62018-06-12 10:11:12 -0400747 op = DefaultPathOp::Make(context, std::move(stencilPaint), path, srcSpaceTol,
748 newCoverage, viewMatrix, isHairline, aaType, devBounds,
749 passes[p]);
Brian Salomonb74ef032017-08-10 12:46:01 -0400750 } else {
Mike Klein16885072018-12-11 09:54:31 -0500751 assert_alive(paint);
Robert Phillips7c525e62018-06-12 10:11:12 -0400752 op = DefaultPathOp::Make(context, std::move(paint), path, srcSpaceTol, newCoverage,
Brian Salomonb74ef032017-08-10 12:46:01 -0400753 viewMatrix, isHairline, aaType, devBounds, passes[p]);
Brian Salomond4652ca2017-01-13 12:11:36 -0500754 }
Robert Phillips4dca8312021-07-28 15:13:20 -0400755 sdc->addDrawOp(clip, std::move(op));
bsalomon@google.com30085192011-08-19 15:42:31 +0000756 }
757 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000758 return true;
bsalomon@google.com30085192011-08-19 15:42:31 +0000759}
760
Robert Phillips461c5392021-08-17 16:42:51 -0400761
762GrPathRenderer::StencilSupport
763DefaultPathRenderer::onGetStencilSupport(const GrStyledShape& shape) const {
764 if (single_pass_shape(shape)) {
765 return GrPathRenderer::kNoRestriction_StencilSupport;
766 } else {
767 return GrPathRenderer::kStencilOnly_StencilSupport;
768 }
769}
770
771GrPathRenderer::CanDrawPath DefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
Robert Phillips62214f72021-06-15 10:12:51 -0400772 bool isHairline = GrIsStrokeHairlineOrEquivalent(
Chris Dalton09e56892019-03-13 00:22:01 -0600773 args.fShape->style(), *args.fViewMatrix, nullptr);
Eric Karl5c779752017-05-08 12:02:07 -0700774 // If we aren't a single_pass_shape or hairline, we require stencil buffers.
Greg Danielbe7fc462019-01-03 16:40:42 -0500775 if (!(single_pass_shape(*args.fShape) || isHairline) &&
Chris Dalton537293bf2021-05-03 15:54:24 -0600776 !args.fProxy->canUseStencil(*args.fCaps)) {
Chris Dalton5ed44232017-09-07 13:22:46 -0600777 return CanDrawPath::kNo;
Eric Karl5c779752017-05-08 12:02:07 -0700778 }
Chris Dalton09e56892019-03-13 00:22:01 -0600779 // If antialiasing is required, we only support MSAA.
Chris Dalton6ce447a2019-06-23 18:07:38 -0600780 if (GrAAType::kNone != args.fAAType && GrAAType::kMSAA != args.fAAType) {
Chris Dalton09e56892019-03-13 00:22:01 -0600781 return CanDrawPath::kNo;
782 }
783 // This can draw any path with any simple fill style.
784 if (!args.fShape->style().isSimpleFill() && !isHairline) {
Chris Dalton5ed44232017-09-07 13:22:46 -0600785 return CanDrawPath::kNo;
786 }
787 // This is the fallback renderer for when a path is too complicated for the others to draw.
788 return CanDrawPath::kAsBackup;
bsalomon@google.com30085192011-08-19 15:42:31 +0000789}
790
Robert Phillips461c5392021-08-17 16:42:51 -0400791bool DefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
Robert Phillipsa92913e2021-07-12 16:31:52 -0400792 GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
Robert Phillips461c5392021-08-17 16:42:51 -0400793 "DefaultPathRenderer::onDrawPath");
Chris Dalton6ce447a2019-06-23 18:07:38 -0600794 GrAAType aaType = (GrAAType::kNone != args.fAAType) ? GrAAType::kMSAA : GrAAType::kNone;
Chris Dalton09e56892019-03-13 00:22:01 -0600795
796 return this->internalDrawPath(
John Stiles0fbc6a32021-06-04 14:40:57 -0400797 args.fSurfaceDrawContext, std::move(args.fPaint), aaType, *args.fUserStencilSettings,
Michael Ludwig7c12e282020-05-29 09:54:07 -0400798 args.fClip, *args.fViewMatrix, *args.fShape, false);
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000799}
800
Robert Phillips461c5392021-08-17 16:42:51 -0400801void DefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
Robert Phillipsa92913e2021-07-12 16:31:52 -0400802 GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
Robert Phillips461c5392021-08-17 16:42:51 -0400803 "DefaultPathRenderer::onStencilPath");
bsalomon8acedde2016-06-24 10:42:16 -0700804 SkASSERT(!args.fShape->inverseFilled());
robertphillips976f5f02016-06-03 10:59:20 -0700805
806 GrPaint paint;
Brian Salomona1633922017-01-09 11:46:10 -0500807 paint.setXPFactory(GrDisableColorXPFactory::Get());
robertphillips976f5f02016-06-03 10:59:20 -0700808
Chris Dalton09e56892019-03-13 00:22:01 -0600809 auto aaType = (GrAA::kYes == args.fDoStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone;
810
811 this->internalDrawPath(
John Stiles0fbc6a32021-06-04 14:40:57 -0400812 args.fSurfaceDrawContext, std::move(paint), aaType, GrUserStencilSettings::kUnused,
Michael Ludwig7c12e282020-05-29 09:54:07 -0400813 args.fClip, *args.fViewMatrix, *args.fShape, true);
bsalomon@google.com30085192011-08-19 15:42:31 +0000814}
joshualitt622d3ad2015-05-07 08:13:11 -0700815
Robert Phillips461c5392021-08-17 16:42:51 -0400816} // namespace skgpu::v1