1 /*
2 * Copyright 2016 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
8 #include "GrMSAAPathRenderer.h"
9 #include "GrAuditTrail.h"
10 #include "GrClip.h"
11 #include "GrDefaultGeoProcFactory.h"
12 #include "GrFixedClip.h"
13 #include "GrMesh.h"
14 #include "GrOpFlushState.h"
15 #include "GrPathStencilSettings.h"
16 #include "GrPathUtils.h"
17 #include "GrSimpleMeshDrawOpHelper.h"
18 #include "SkAutoMalloc.h"
19 #include "SkGeometry.h"
20 #include "SkTraceEvent.h"
21 #include "gl/GrGLVaryingHandler.h"
22 #include "glsl/GrGLSLFragmentShaderBuilder.h"
23 #include "glsl/GrGLSLGeometryProcessor.h"
24 #include "glsl/GrGLSLProgramDataManager.h"
25 #include "glsl/GrGLSLUtil.h"
26 #include "glsl/GrGLSLVertexGeoBuilder.h"
27 #include "ops/GrMeshDrawOp.h"
28 #include "ops/GrRectOpFactory.h"
29
30 static const float kTolerance = 0.5f;
31
32 ////////////////////////////////////////////////////////////////////////////////
33 // Helpers for drawPath
34
single_pass_shape(const GrShape & shape)35 static inline bool single_pass_shape(const GrShape& shape) {
36 if (!shape.inverseFilled()) {
37 return shape.knownToBeConvex();
38 }
39 return false;
40 }
41
onGetStencilSupport(const GrShape & shape) const42 GrPathRenderer::StencilSupport GrMSAAPathRenderer::onGetStencilSupport(const GrShape& shape) const {
43 if (single_pass_shape(shape)) {
44 return GrPathRenderer::kNoRestriction_StencilSupport;
45 } else {
46 return GrPathRenderer::kStencilOnly_StencilSupport;
47 }
48 }
49
50 struct MSAALineVertices {
51 struct Vertex {
52 SkPoint fPosition;
53 SkColor fColor;
54 };
55 Vertex* vertices;
56 Vertex* nextVertex;
57 #ifdef SK_DEBUG
58 Vertex* verticesEnd;
59 #endif
60 uint16_t* indices;
61 uint16_t* nextIndex;
62 };
63
64 struct MSAAQuadVertices {
65 struct Vertex {
66 SkPoint fPosition;
67 SkPoint fUV;
68 SkColor fColor;
69 };
70 Vertex* vertices;
71 Vertex* nextVertex;
72 #ifdef SK_DEBUG
73 Vertex* verticesEnd;
74 #endif
75 uint16_t* indices;
76 uint16_t* nextIndex;
77 };
78
append_contour_edge_indices(uint16_t fanCenterIdx,uint16_t edgeV0Idx,MSAALineVertices & lines)79 static inline void append_contour_edge_indices(uint16_t fanCenterIdx,
80 uint16_t edgeV0Idx,
81 MSAALineVertices& lines) {
82 *(lines.nextIndex++) = fanCenterIdx;
83 *(lines.nextIndex++) = edgeV0Idx;
84 *(lines.nextIndex++) = edgeV0Idx + 1;
85 }
86
add_quad(MSAALineVertices & lines,MSAAQuadVertices & quads,const SkPoint pts[],SkColor color,bool indexed,uint16_t subpathLineIdxStart)87 static inline void add_quad(MSAALineVertices& lines, MSAAQuadVertices& quads, const SkPoint pts[],
88 SkColor color, bool indexed, uint16_t subpathLineIdxStart) {
89 SkASSERT(lines.nextVertex < lines.verticesEnd);
90 *lines.nextVertex = { pts[2], color };
91 if (indexed) {
92 int prevIdx = (uint16_t) (lines.nextVertex - lines.vertices - 1);
93 if (prevIdx > subpathLineIdxStart) {
94 append_contour_edge_indices(subpathLineIdxStart, prevIdx, lines);
95 }
96 }
97 lines.nextVertex++;
98
99 SkASSERT(quads.nextVertex + 2 < quads.verticesEnd);
100 // the texture coordinates are drawn from the Loop-Blinn rendering algorithm
101 *(quads.nextVertex++) = { pts[0], SkPoint::Make(0.0, 0.0), color };
102 *(quads.nextVertex++) = { pts[1], SkPoint::Make(0.5, 0.0), color };
103 *(quads.nextVertex++) = { pts[2], SkPoint::Make(1.0, 1.0), color };
104 if (indexed) {
105 uint16_t offset = (uint16_t) (quads.nextVertex - quads.vertices) - 3;
106 *(quads.nextIndex++) = offset++;
107 *(quads.nextIndex++) = offset++;
108 *(quads.nextIndex++) = offset++;
109 }
110 }
111
112 namespace {
113
114 class MSAAQuadProcessor : public GrGeometryProcessor {
115 public:
Create(const SkMatrix & viewMatrix)116 static GrGeometryProcessor* Create(const SkMatrix& viewMatrix) {
117 return new MSAAQuadProcessor(viewMatrix);
118 }
119
~MSAAQuadProcessor()120 ~MSAAQuadProcessor() override {}
121
name() const122 const char* name() const override { return "MSAAQuadProcessor"; }
123
inPosition() const124 const Attribute* inPosition() const { return fInPosition; }
inUV() const125 const Attribute* inUV() const { return fInUV; }
inColor() const126 const Attribute* inColor() const { return fInColor; }
viewMatrix() const127 const SkMatrix& viewMatrix() const { return fViewMatrix; }
128
129 class GLSLProcessor : public GrGLSLGeometryProcessor {
130 public:
GLSLProcessor(const GrGeometryProcessor & qpr)131 GLSLProcessor(const GrGeometryProcessor& qpr) {}
132
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)133 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
134 const MSAAQuadProcessor& qp = args.fGP.cast<MSAAQuadProcessor>();
135 GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
136 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
137 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
138
139 // emit attributes
140 varyingHandler->emitAttributes(qp);
141 varyingHandler->addPassThroughAttribute(qp.inColor(), args.fOutputColor);
142
143 GrGLSLVarying uv(kFloat2_GrSLType);
144 varyingHandler->addVarying("uv", &uv);
145 vsBuilder->codeAppendf("%s = %s;", uv.vsOut(), qp.inUV()->fName);
146
147 // Setup position
148 this->writeOutputPosition(vsBuilder, uniformHandler, gpArgs, qp.inPosition()->fName,
149 qp.viewMatrix(), &fViewMatrixUniform);
150
151 // emit transforms
152 this->emitTransforms(vsBuilder, varyingHandler, uniformHandler,
153 qp.inPosition()->asShaderVar(), SkMatrix::I(),
154 args.fFPCoordTransformHandler);
155
156 GrGLSLFPFragmentBuilder* fsBuilder = args.fFragBuilder;
157 fsBuilder->codeAppendf("if (%s.x * %s.x >= %s.y) discard;", uv.fsIn(), uv.fsIn(),
158 uv.fsIn());
159 fsBuilder->codeAppendf("%s = half4(1.0);", args.fOutputCoverage);
160 }
161
GenKey(const GrGeometryProcessor & gp,const GrShaderCaps &,GrProcessorKeyBuilder * b)162 static inline void GenKey(const GrGeometryProcessor& gp,
163 const GrShaderCaps&,
164 GrProcessorKeyBuilder* b) {
165 const MSAAQuadProcessor& qp = gp.cast<MSAAQuadProcessor>();
166 uint32_t key = 0;
167 key |= qp.viewMatrix().hasPerspective() ? 0x1 : 0x0;
168 key |= qp.viewMatrix().isIdentity() ? 0x2: 0x0;
169 b->add32(key);
170 }
171
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & gp,FPCoordTransformIter && transformIter)172 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp,
173 FPCoordTransformIter&& transformIter) override {
174 const MSAAQuadProcessor& qp = gp.cast<MSAAQuadProcessor>();
175 if (!qp.viewMatrix().isIdentity()) {
176 float viewMatrix[3 * 3];
177 GrGLSLGetMatrix<3>(viewMatrix, qp.viewMatrix());
178 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
179 }
180 this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
181 }
182
183 private:
184 typedef GrGLSLGeometryProcessor INHERITED;
185
186 UniformHandle fViewMatrixUniform;
187 };
188
getGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const189 virtual void getGLSLProcessorKey(const GrShaderCaps& caps,
190 GrProcessorKeyBuilder* b) const override {
191 GLSLProcessor::GenKey(*this, caps, b);
192 }
193
createGLSLInstance(const GrShaderCaps &) const194 virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
195 return new GLSLProcessor(*this);
196 }
197
198 private:
MSAAQuadProcessor(const SkMatrix & viewMatrix)199 MSAAQuadProcessor(const SkMatrix& viewMatrix)
200 : INHERITED(kMSAAQuadProcessor_ClassID)
201 , fViewMatrix(viewMatrix) {
202 fInPosition = &this->addVertexAttrib("inPosition", kFloat2_GrVertexAttribType);
203 fInUV = &this->addVertexAttrib("inUV", kFloat2_GrVertexAttribType);
204 fInColor = &this->addVertexAttrib("inColor", kUByte4_norm_GrVertexAttribType);
205 this->setSampleShading(1.0f);
206 }
207
208 const Attribute* fInPosition;
209 const Attribute* fInUV;
210 const Attribute* fInColor;
211 SkMatrix fViewMatrix;
212
213 GR_DECLARE_GEOMETRY_PROCESSOR_TEST
214
215 typedef GrGeometryProcessor INHERITED;
216 };
217
218 class MSAAPathOp final : public GrMeshDrawOp {
219 private:
220 using Helper = GrSimpleMeshDrawOpHelperWithStencil;
221
222 public:
223 DEFINE_OP_CLASS_ID
224
Make(GrPaint && paint,const SkPath & path,GrAAType aaType,const SkMatrix & viewMatrix,const SkRect & devBounds,const GrUserStencilSettings * stencilSettings)225 static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkPath& path, GrAAType aaType,
226 const SkMatrix& viewMatrix, const SkRect& devBounds,
227 const GrUserStencilSettings* stencilSettings) {
228 int contourCount;
229 int maxLineVertices;
230 int maxQuadVertices;
231 ComputeWorstCasePointCount(path, viewMatrix, &contourCount, &maxLineVertices,
232 &maxQuadVertices);
233 bool isIndexed = contourCount > 1;
234 if (isIndexed &&
235 (maxLineVertices > kMaxIndexedVertexCnt || maxQuadVertices > kMaxIndexedVertexCnt)) {
236 return nullptr;
237 }
238
239 return Helper::FactoryHelper<MSAAPathOp>(std::move(paint), path, aaType, viewMatrix,
240 devBounds, maxLineVertices, maxQuadVertices,
241 isIndexed, stencilSettings);
242 }
243
name() const244 const char* name() const override { return "MSAAPathOp"; }
245
visitProxies(const VisitProxyFunc & func) const246 void visitProxies(const VisitProxyFunc& func) const override {
247 fHelper.visitProxies(func);
248 }
249
dumpInfo() const250 SkString dumpInfo() const override {
251 SkString string;
252 string.appendf("Indexed: %d\n", fIsIndexed);
253 for (const auto& path : fPaths) {
254 string.appendf("Color: 0x%08x\n", path.fColor);
255 }
256 string += fHelper.dumpInfo();
257 string += INHERITED::dumpInfo();
258 return string;
259 }
260
MSAAPathOp(const Helper::MakeArgs & helperArgs,GrColor color,const SkPath & path,GrAAType aaType,const SkMatrix & viewMatrix,const SkRect & devBounds,int maxLineVertices,int maxQuadVertices,bool isIndexed,const GrUserStencilSettings * stencilSettings)261 MSAAPathOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkPath& path,
262 GrAAType aaType, const SkMatrix& viewMatrix, const SkRect& devBounds,
263 int maxLineVertices, int maxQuadVertices, bool isIndexed,
264 const GrUserStencilSettings* stencilSettings)
265 : INHERITED(ClassID())
266 , fHelper(helperArgs, aaType, stencilSettings)
267 , fViewMatrix(viewMatrix)
268 , fMaxLineVertices(maxLineVertices)
269 , fMaxQuadVertices(maxQuadVertices)
270 , fIsIndexed(isIndexed) {
271 fPaths.emplace_back(PathInfo{color, path});
272 this->setBounds(devBounds, HasAABloat::kNo, IsZeroArea::kNo);
273 }
274
fixedFunctionFlags() const275 FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
276
finalize(const GrCaps & caps,const GrAppliedClip * clip,GrPixelConfigIsClamped dstIsClamped)277 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip,
278 GrPixelConfigIsClamped dstIsClamped) override {
279 return fHelper.xpRequiresDstTexture(caps, clip, dstIsClamped,
280 GrProcessorAnalysisCoverage::kNone,
281 &fPaths.front().fColor);
282 }
283
284 private:
ComputeWorstCasePointCount(const SkPath & path,const SkMatrix & m,int * subpaths,int * outLinePointCount,int * outQuadPointCount)285 static void ComputeWorstCasePointCount(const SkPath& path, const SkMatrix& m, int* subpaths,
286 int* outLinePointCount, int* outQuadPointCount) {
287 SkScalar tolerance = GrPathUtils::scaleToleranceToSrc(kTolerance, m, path.getBounds());
288 int linePointCount = 0;
289 int quadPointCount = 0;
290 *subpaths = 1;
291
292 bool first = true;
293
294 SkPath::Iter iter(path, true);
295 SkPath::Verb verb;
296
297 SkPoint pts[4];
298 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
299 switch (verb) {
300 case SkPath::kLine_Verb:
301 linePointCount += 1;
302 break;
303 case SkPath::kConic_Verb: {
304 SkScalar weight = iter.conicWeight();
305 SkAutoConicToQuads converter;
306 converter.computeQuads(pts, weight, tolerance);
307 int quadPts = converter.countQuads();
308 linePointCount += quadPts;
309 quadPointCount += 3 * quadPts;
310 }
311 case SkPath::kQuad_Verb:
312 linePointCount += 1;
313 quadPointCount += 3;
314 break;
315 case SkPath::kCubic_Verb: {
316 SkSTArray<15, SkPoint, true> quadPts;
317 GrPathUtils::convertCubicToQuads(pts, tolerance, &quadPts);
318 int count = quadPts.count();
319 linePointCount += count / 3;
320 quadPointCount += count;
321 break;
322 }
323 case SkPath::kMove_Verb:
324 linePointCount += 1;
325 if (!first) {
326 ++(*subpaths);
327 }
328 break;
329 default:
330 break;
331 }
332 first = false;
333 }
334 *outLinePointCount = linePointCount;
335 *outQuadPointCount = quadPointCount;
336 }
337
onPrepareDraws(Target * target)338 void onPrepareDraws(Target* target) override {
339 if (fMaxLineVertices == 0) {
340 SkASSERT(fMaxQuadVertices == 0);
341 return;
342 }
343
344 GrPrimitiveType primitiveType = fIsIndexed ? GrPrimitiveType::kTriangles
345 : GrPrimitiveType::kTriangleFan;
346
347 // allocate vertex / index buffers
348 const GrBuffer* lineVertexBuffer;
349 int firstLineVertex;
350 MSAALineVertices lines;
351 int lineVertexStride = sizeof(MSAALineVertices::Vertex);
352 lines.vertices = (MSAALineVertices::Vertex*) target->makeVertexSpace(lineVertexStride,
353 fMaxLineVertices,
354 &lineVertexBuffer,
355 &firstLineVertex);
356 if (!lines.vertices) {
357 SkDebugf("Could not allocate vertices\n");
358 return;
359 }
360 lines.nextVertex = lines.vertices;
361 SkDEBUGCODE(lines.verticesEnd = lines.vertices + fMaxLineVertices;)
362
363 MSAAQuadVertices quads;
364 int quadVertexStride = sizeof(MSAAQuadVertices::Vertex);
365 SkAutoMalloc quadVertexPtr(fMaxQuadVertices * quadVertexStride);
366 quads.vertices = (MSAAQuadVertices::Vertex*) quadVertexPtr.get();
367 quads.nextVertex = quads.vertices;
368 SkDEBUGCODE(quads.verticesEnd = quads.vertices + fMaxQuadVertices;)
369
370 const GrBuffer* lineIndexBuffer = nullptr;
371 int firstLineIndex = 0;
372 if (fIsIndexed) {
373 lines.indices =
374 target->makeIndexSpace(3 * fMaxLineVertices, &lineIndexBuffer, &firstLineIndex);
375 if (!lines.indices) {
376 SkDebugf("Could not allocate indices\n");
377 return;
378 }
379 lines.nextIndex = lines.indices;
380 } else {
381 lines.indices = nullptr;
382 lines.nextIndex = nullptr;
383 }
384
385 SkAutoFree quadIndexPtr;
386 if (fIsIndexed) {
387 quads.indices = (uint16_t*)sk_malloc_throw(3 * fMaxQuadVertices * sizeof(uint16_t));
388 quadIndexPtr.reset(quads.indices);
389 quads.nextIndex = quads.indices;
390 } else {
391 quads.indices = nullptr;
392 quads.nextIndex = nullptr;
393 }
394 // fill buffers
395 for (int i = 0; i < fPaths.count(); i++) {
396 const PathInfo& pathInfo = fPaths[i];
397 if (!this->createGeom(lines,
398 quads,
399 pathInfo.fPath,
400 fViewMatrix,
401 pathInfo.fColor,
402 fIsIndexed)) {
403 return;
404 }
405 }
406 int lineVertexOffset = (int) (lines.nextVertex - lines.vertices);
407 int lineIndexOffset = (int) (lines.nextIndex - lines.indices);
408 SkASSERT(lineVertexOffset <= fMaxLineVertices && lineIndexOffset <= 3 * fMaxLineVertices);
409 int quadVertexOffset = (int) (quads.nextVertex - quads.vertices);
410 int quadIndexOffset = (int) (quads.nextIndex - quads.indices);
411 SkASSERT(quadVertexOffset <= fMaxQuadVertices && quadIndexOffset <= 3 * fMaxQuadVertices);
412
413 const GrPipeline* pipeline = fHelper.makePipeline(target);
414
415 if (lineVertexOffset) {
416 sk_sp<GrGeometryProcessor> lineGP;
417 {
418 using namespace GrDefaultGeoProcFactory;
419 lineGP = GrDefaultGeoProcFactory::Make(Color(Color::kPremulGrColorAttribute_Type),
420 Coverage::kSolid_Type,
421 LocalCoords(LocalCoords::kUnused_Type),
422 fViewMatrix);
423 }
424 SkASSERT(lineVertexStride == lineGP->getVertexStride());
425
426 GrMesh lineMeshes(primitiveType);
427 if (!fIsIndexed) {
428 lineMeshes.setNonIndexedNonInstanced(lineVertexOffset);
429 } else {
430 lineMeshes.setIndexed(lineIndexBuffer, lineIndexOffset, firstLineIndex,
431 0, lineVertexOffset - 1);
432 }
433 lineMeshes.setVertexData(lineVertexBuffer, firstLineVertex);
434
435 // We can get line vertices from path moveTos with no actual segments and thus no index
436 // count. We assert that indexed draws contain a positive index count, so bail here in
437 // that case.
438 if (!fIsIndexed || lineIndexOffset) {
439 target->draw(lineGP.get(), pipeline, lineMeshes);
440 }
441 }
442
443 if (quadVertexOffset) {
444 sk_sp<const GrGeometryProcessor> quadGP(MSAAQuadProcessor::Create(fViewMatrix));
445 SkASSERT(quadVertexStride == quadGP->getVertexStride());
446
447 const GrBuffer* quadVertexBuffer;
448 int firstQuadVertex;
449 MSAAQuadVertices::Vertex* quadVertices = (MSAAQuadVertices::Vertex*)
450 target->makeVertexSpace(quadVertexStride, quadVertexOffset, &quadVertexBuffer,
451 &firstQuadVertex);
452 memcpy(quadVertices, quads.vertices, quadVertexStride * quadVertexOffset);
453 GrMesh quadMeshes(GrPrimitiveType::kTriangles);
454 if (!fIsIndexed) {
455 quadMeshes.setNonIndexedNonInstanced(quadVertexOffset);
456 } else {
457 const GrBuffer* quadIndexBuffer;
458 int firstQuadIndex;
459 uint16_t* quadIndices = (uint16_t*) target->makeIndexSpace(quadIndexOffset,
460 &quadIndexBuffer,
461 &firstQuadIndex);
462 memcpy(quadIndices, quads.indices, sizeof(uint16_t) * quadIndexOffset);
463 quadMeshes.setIndexed(quadIndexBuffer, quadIndexOffset, firstQuadIndex,
464 0, quadVertexOffset - 1);
465 }
466 quadMeshes.setVertexData(quadVertexBuffer, firstQuadVertex);
467 target->draw(quadGP.get(), pipeline, quadMeshes);
468 }
469 }
470
onCombineIfPossible(GrOp * t,const GrCaps & caps)471 bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
472 MSAAPathOp* that = t->cast<MSAAPathOp>();
473 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
474 return false;
475 }
476
477 if (this->bounds().intersects(that->bounds())) {
478 return false;
479 }
480
481 if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
482 return false;
483 }
484
485 // If we grow to include 2+ paths we will be indexed.
486 if (((fMaxLineVertices + that->fMaxLineVertices) > kMaxIndexedVertexCnt) ||
487 ((fMaxQuadVertices + that->fMaxQuadVertices) > kMaxIndexedVertexCnt)) {
488 return false;
489 }
490
491 fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
492 this->joinBounds(*that);
493 fIsIndexed = true;
494 fMaxLineVertices += that->fMaxLineVertices;
495 fMaxQuadVertices += that->fMaxQuadVertices;
496 return true;
497 }
498
createGeom(MSAALineVertices & lines,MSAAQuadVertices & quads,const SkPath & path,const SkMatrix & m,SkColor color,bool isIndexed) const499 bool createGeom(MSAALineVertices& lines,
500 MSAAQuadVertices& quads,
501 const SkPath& path,
502 const SkMatrix& m,
503 SkColor color,
504 bool isIndexed) const {
505 {
506 const SkScalar tolerance = GrPathUtils::scaleToleranceToSrc(kTolerance, m,
507 path.getBounds());
508 uint16_t subpathIdxStart = (uint16_t) (lines.nextVertex - lines.vertices);
509
510 SkPoint pts[4];
511
512 bool first = true;
513 SkPath::Iter iter(path, true);
514
515 bool done = false;
516 while (!done) {
517 SkPath::Verb verb = iter.next(pts);
518 switch (verb) {
519 case SkPath::kMove_Verb:
520 if (!first) {
521 uint16_t currIdx = (uint16_t) (lines.nextVertex - lines.vertices);
522 subpathIdxStart = currIdx;
523 }
524 SkASSERT(lines.nextVertex < lines.verticesEnd);
525 *(lines.nextVertex++) = { pts[0], color };
526 break;
527 case SkPath::kLine_Verb:
528 if (isIndexed) {
529 uint16_t prevIdx = (uint16_t) (lines.nextVertex - lines.vertices - 1);
530 if (prevIdx > subpathIdxStart) {
531 append_contour_edge_indices(subpathIdxStart, prevIdx, lines);
532 }
533 }
534 SkASSERT(lines.nextVertex < lines.verticesEnd);
535 *(lines.nextVertex++) = { pts[1], color };
536 break;
537 case SkPath::kConic_Verb: {
538 SkScalar weight = iter.conicWeight();
539 SkAutoConicToQuads converter;
540 const SkPoint* quadPts = converter.computeQuads(pts, weight, tolerance);
541 for (int i = 0; i < converter.countQuads(); ++i) {
542 add_quad(lines, quads, quadPts + i * 2, color, isIndexed,
543 subpathIdxStart);
544 }
545 break;
546 }
547 case SkPath::kQuad_Verb: {
548 add_quad(lines, quads, pts, color, isIndexed, subpathIdxStart);
549 break;
550 }
551 case SkPath::kCubic_Verb: {
552 SkSTArray<15, SkPoint, true> quadPts;
553 GrPathUtils::convertCubicToQuads(pts, tolerance, &quadPts);
554 int count = quadPts.count();
555 for (int i = 0; i < count; i += 3) {
556 add_quad(lines, quads, &quadPts[i], color, isIndexed, subpathIdxStart);
557 }
558 break;
559 }
560 case SkPath::kClose_Verb:
561 break;
562 case SkPath::kDone_Verb:
563 done = true;
564 }
565 first = false;
566 }
567 }
568 return true;
569 }
570
571 // Lines and quads may render with an index buffer. However, we don't have any support for
572 // overflowing the max index.
573 static constexpr int kMaxIndexedVertexCnt = SK_MaxU16 / 3;
574 struct PathInfo {
575 GrColor fColor;
576 SkPath fPath;
577 };
578
579 Helper fHelper;
580 SkSTArray<1, PathInfo, true> fPaths;
581 SkMatrix fViewMatrix;
582 int fMaxLineVertices;
583 int fMaxQuadVertices;
584 bool fIsIndexed;
585
586 typedef GrMeshDrawOp INHERITED;
587 };
588
589 } // anonymous namespace
590
internalDrawPath(GrRenderTargetContext * renderTargetContext,GrPaint && paint,GrAAType aaType,const GrUserStencilSettings & userStencilSettings,const GrClip & clip,const SkMatrix & viewMatrix,const GrShape & shape,bool stencilOnly)591 bool GrMSAAPathRenderer::internalDrawPath(GrRenderTargetContext* renderTargetContext,
592 GrPaint&& paint,
593 GrAAType aaType,
594 const GrUserStencilSettings& userStencilSettings,
595 const GrClip& clip,
596 const SkMatrix& viewMatrix,
597 const GrShape& shape,
598 bool stencilOnly) {
599 SkASSERT(shape.style().isSimpleFill());
600 SkPath path;
601 shape.asPath(&path);
602
603 const GrUserStencilSettings* passes[2] = {nullptr, nullptr};
604 bool reverse = false;
605
606 if (single_pass_shape(shape)) {
607 if (stencilOnly) {
608 passes[0] = &gDirectToStencil;
609 } else {
610 passes[0] = &userStencilSettings;
611 }
612 } else {
613 switch (path.getFillType()) {
614 case SkPath::kInverseEvenOdd_FillType:
615 reverse = true;
616 // fallthrough
617 case SkPath::kEvenOdd_FillType:
618 passes[0] = &gEOStencilPass;
619 if (!stencilOnly) {
620 passes[1] = reverse ? &gInvEOColorPass : &gEOColorPass;
621 }
622 break;
623
624 case SkPath::kInverseWinding_FillType:
625 reverse = true;
626 // fallthrough
627 case SkPath::kWinding_FillType:
628 passes[0] = &gWindStencilPass;
629 if (!stencilOnly) {
630 passes[1] = reverse ? &gInvWindColorPass : &gWindColorPass;
631 }
632 break;
633 default:
634 SkDEBUGFAIL("Unknown path fFill!");
635 return false;
636 }
637 }
638
639 SkRect devBounds;
640 GetPathDevBounds(path,
641 renderTargetContext->asRenderTargetProxy()->worstCaseWidth(),
642 renderTargetContext->asRenderTargetProxy()->worstCaseHeight(),
643 viewMatrix, &devBounds);
644
645 SkASSERT(passes[0]);
646 { // First pass
647 bool firstPassIsStencil = stencilOnly || passes[1];
648 // If we have a cover pass then we ignore the paint in the first pass and apply it in the
649 // second.
650 std::unique_ptr<GrDrawOp> op;
651 if (firstPassIsStencil) {
652 GrPaint stencilPaint;
653 stencilPaint.setXPFactory(GrDisableColorXPFactory::Get());
654 op = MSAAPathOp::Make(std::move(stencilPaint), path, aaType, viewMatrix, devBounds,
655 passes[0]);
656 } else {
657 op = MSAAPathOp::Make(std::move(paint), path, aaType, viewMatrix, devBounds, passes[0]);
658 }
659 if (!op) {
660 return false;
661 }
662 renderTargetContext->addDrawOp(clip, std::move(op));
663 }
664
665 if (passes[1]) {
666 SkRect bounds;
667 SkMatrix localMatrix = SkMatrix::I();
668 if (reverse) {
669 // draw over the dev bounds (which will be the whole dst surface for inv fill).
670 bounds = devBounds;
671 SkMatrix vmi;
672 // mapRect through persp matrix may not be correct
673 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
674 vmi.mapRect(&bounds);
675 } else {
676 if (!viewMatrix.invert(&localMatrix)) {
677 return false;
678 }
679 }
680 } else {
681 bounds = path.getBounds();
682 }
683 const SkMatrix& viewM =
684 (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() : viewMatrix;
685 renderTargetContext->addDrawOp(
686 clip,
687 GrRectOpFactory::MakeNonAAFillWithLocalMatrix(std::move(paint), viewM, localMatrix,
688 bounds, aaType, passes[1]));
689 }
690 return true;
691 }
692
onCanDrawPath(const CanDrawPathArgs & args) const693 GrPathRenderer::CanDrawPath GrMSAAPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
694 // If we aren't a single_pass_shape, we require stencil buffers.
695 if (!single_pass_shape(*args.fShape) && args.fCaps->avoidStencilBuffers()) {
696 return CanDrawPath::kNo;
697 }
698 // This path renderer only fills and relies on MSAA for antialiasing. Stroked shapes are
699 // handled by passing on the original shape and letting the caller compute the stroked shape
700 // which will have a fill style.
701 if (!args.fShape->style().isSimpleFill() || GrAAType::kCoverage == args.fAAType) {
702 return CanDrawPath::kNo;
703 }
704 return CanDrawPath::kYes;
705 }
706
onDrawPath(const DrawPathArgs & args)707 bool GrMSAAPathRenderer::onDrawPath(const DrawPathArgs& args) {
708 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
709 "GrMSAAPathRenderer::onDrawPath");
710 SkTLazy<GrShape> tmpShape;
711 const GrShape* shape = args.fShape;
712 if (shape->style().applies()) {
713 SkScalar styleScale = GrStyle::MatrixToScaleFactor(*args.fViewMatrix);
714 tmpShape.init(args.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale));
715 shape = tmpShape.get();
716 }
717 return this->internalDrawPath(args.fRenderTargetContext,
718 std::move(args.fPaint),
719 args.fAAType,
720 *args.fUserStencilSettings,
721 *args.fClip,
722 *args.fViewMatrix,
723 *shape,
724 false);
725 }
726
onStencilPath(const StencilPathArgs & args)727 void GrMSAAPathRenderer::onStencilPath(const StencilPathArgs& args) {
728 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
729 "GrMSAAPathRenderer::onStencilPath");
730 SkASSERT(args.fShape->style().isSimpleFill());
731 SkASSERT(!args.fShape->mayBeInverseFilledAfterStyling());
732
733 GrPaint paint;
734 paint.setXPFactory(GrDisableColorXPFactory::Get());
735
736 this->internalDrawPath(args.fRenderTargetContext, std::move(paint), args.fAAType,
737 GrUserStencilSettings::kUnused, *args.fClip, *args.fViewMatrix,
738 *args.fShape, true);
739 }
740
741 ///////////////////////////////////////////////////////////////////////////////////////////////////
742