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/GrGLSLVertexShaderBuilder.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 35 static inline bool single_pass_shape(const GrShape& shape) { 36 if (!shape.inverseFilled()) { 37 return shape.knownToBeConvex(); 38 } 39 return false; 40 } 41 42 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 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 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: 116 static GrGeometryProcessor* Create(const SkMatrix& viewMatrix) { 117 return new MSAAQuadProcessor(viewMatrix); 118 } 119 120 ~MSAAQuadProcessor() override {} 121 122 const char* name() const override { return "MSAAQuadProcessor"; } 123 124 const Attribute* inPosition() const { return fInPosition; } 125 const Attribute* inUV() const { return fInUV; } 126 const Attribute* inColor() const { return fInColor; } 127 const SkMatrix& viewMatrix() const { return fViewMatrix; } 128 129 class GLSLProcessor : public GrGLSLGeometryProcessor { 130 public: 131 GLSLProcessor(const GrGeometryProcessor& qpr) {} 132 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 GrGLSLVertToFrag uv(kVec2f_GrSLType); 144 varyingHandler->addVarying("uv", &uv, kHigh_GrSLPrecision); 145 vsBuilder->codeAppendf("%s = %s;", uv.vsOut(), qp.inUV()->fName); 146 147 // Setup position 148 this->setupPosition(vsBuilder, uniformHandler, gpArgs, qp.inPosition()->fName, 149 qp.viewMatrix(), &fViewMatrixUniform); 150 151 // emit transforms 152 this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, 153 qp.inPosition()->fName, SkMatrix::I(), 154 args.fFPCoordTransformHandler); 155 156 GrGLSLPPFragmentBuilder* 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 = vec4(1.0);", args.fOutputCoverage); 160 } 161 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 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 189 virtual void getGLSLProcessorKey(const GrShaderCaps& caps, 190 GrProcessorKeyBuilder* b) const override { 191 GLSLProcessor::GenKey(*this, caps, b); 192 } 193 194 virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override { 195 return new GLSLProcessor(*this); 196 } 197 198 private: 199 MSAAQuadProcessor(const SkMatrix& viewMatrix) 200 : fViewMatrix(viewMatrix) { 201 this->initClassID<MSAAQuadProcessor>(); 202 fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType, 203 kHigh_GrSLPrecision); 204 fInUV = &this->addVertexAttrib("inUV", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision); 205 fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType); 206 this->setSampleShading(1.0f); 207 } 208 209 const Attribute* fInPosition; 210 const Attribute* fInUV; 211 const Attribute* fInColor; 212 SkMatrix fViewMatrix; 213 214 GR_DECLARE_GEOMETRY_PROCESSOR_TEST 215 216 typedef GrGeometryProcessor INHERITED; 217 }; 218 219 class MSAAPathOp final : public GrMeshDrawOp { 220 private: 221 using Helper = GrSimpleMeshDrawOpHelperWithStencil; 222 223 public: 224 DEFINE_OP_CLASS_ID 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 244 const char* name() const override { return "MSAAPathOp"; } 245 246 SkString dumpInfo() const override { 247 SkString string; 248 string.appendf("Indexed: %d\n", fIsIndexed); 249 for (const auto& path : fPaths) { 250 string.appendf("Color: 0x%08x\n", path.fColor); 251 } 252 string += fHelper.dumpInfo(); 253 string += INHERITED::dumpInfo(); 254 return string; 255 } 256 257 MSAAPathOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkPath& path, 258 GrAAType aaType, const SkMatrix& viewMatrix, const SkRect& devBounds, 259 int maxLineVertices, int maxQuadVertices, bool isIndexed, 260 const GrUserStencilSettings* stencilSettings) 261 : INHERITED(ClassID()) 262 , fHelper(helperArgs, aaType, stencilSettings) 263 , fViewMatrix(viewMatrix) 264 , fMaxLineVertices(maxLineVertices) 265 , fMaxQuadVertices(maxQuadVertices) 266 , fIsIndexed(isIndexed) { 267 fPaths.emplace_back(PathInfo{color, path}); 268 this->setBounds(devBounds, HasAABloat::kNo, IsZeroArea::kNo); 269 } 270 271 FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); } 272 273 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override { 274 return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, 275 &fPaths.front().fColor); 276 } 277 278 private: 279 static void ComputeWorstCasePointCount(const SkPath& path, const SkMatrix& m, int* subpaths, 280 int* outLinePointCount, int* outQuadPointCount) { 281 SkScalar tolerance = GrPathUtils::scaleToleranceToSrc(kTolerance, m, path.getBounds()); 282 int linePointCount = 0; 283 int quadPointCount = 0; 284 *subpaths = 1; 285 286 bool first = true; 287 288 SkPath::Iter iter(path, true); 289 SkPath::Verb verb; 290 291 SkPoint pts[4]; 292 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 293 switch (verb) { 294 case SkPath::kLine_Verb: 295 linePointCount += 1; 296 break; 297 case SkPath::kConic_Verb: { 298 SkScalar weight = iter.conicWeight(); 299 SkAutoConicToQuads converter; 300 converter.computeQuads(pts, weight, tolerance); 301 int quadPts = converter.countQuads(); 302 linePointCount += quadPts; 303 quadPointCount += 3 * quadPts; 304 } 305 case SkPath::kQuad_Verb: 306 linePointCount += 1; 307 quadPointCount += 3; 308 break; 309 case SkPath::kCubic_Verb: { 310 SkSTArray<15, SkPoint, true> quadPts; 311 GrPathUtils::convertCubicToQuads(pts, tolerance, &quadPts); 312 int count = quadPts.count(); 313 linePointCount += count / 3; 314 quadPointCount += count; 315 break; 316 } 317 case SkPath::kMove_Verb: 318 linePointCount += 1; 319 if (!first) { 320 ++(*subpaths); 321 } 322 break; 323 default: 324 break; 325 } 326 first = false; 327 } 328 *outLinePointCount = linePointCount; 329 *outQuadPointCount = quadPointCount; 330 } 331 332 void onPrepareDraws(Target* target) const override { 333 if (fMaxLineVertices == 0) { 334 SkASSERT(fMaxQuadVertices == 0); 335 return; 336 } 337 338 GrPrimitiveType primitiveType = fIsIndexed ? GrPrimitiveType::kTriangles 339 : GrPrimitiveType::kTriangleFan; 340 341 // allocate vertex / index buffers 342 const GrBuffer* lineVertexBuffer; 343 int firstLineVertex; 344 MSAALineVertices lines; 345 int lineVertexStride = sizeof(MSAALineVertices::Vertex); 346 lines.vertices = (MSAALineVertices::Vertex*) target->makeVertexSpace(lineVertexStride, 347 fMaxLineVertices, 348 &lineVertexBuffer, 349 &firstLineVertex); 350 if (!lines.vertices) { 351 SkDebugf("Could not allocate vertices\n"); 352 return; 353 } 354 lines.nextVertex = lines.vertices; 355 SkDEBUGCODE(lines.verticesEnd = lines.vertices + fMaxLineVertices;) 356 357 MSAAQuadVertices quads; 358 int quadVertexStride = sizeof(MSAAQuadVertices::Vertex); 359 SkAutoMalloc quadVertexPtr(fMaxQuadVertices * quadVertexStride); 360 quads.vertices = (MSAAQuadVertices::Vertex*) quadVertexPtr.get(); 361 quads.nextVertex = quads.vertices; 362 SkDEBUGCODE(quads.verticesEnd = quads.vertices + fMaxQuadVertices;) 363 364 const GrBuffer* lineIndexBuffer = nullptr; 365 int firstLineIndex; 366 if (fIsIndexed) { 367 lines.indices = 368 target->makeIndexSpace(3 * fMaxLineVertices, &lineIndexBuffer, &firstLineIndex); 369 if (!lines.indices) { 370 SkDebugf("Could not allocate indices\n"); 371 return; 372 } 373 lines.nextIndex = lines.indices; 374 } else { 375 lines.indices = nullptr; 376 lines.nextIndex = nullptr; 377 } 378 379 SkAutoFree quadIndexPtr; 380 if (fIsIndexed) { 381 quads.indices = (uint16_t*)sk_malloc_throw(3 * fMaxQuadVertices * sizeof(uint16_t)); 382 quadIndexPtr.reset(quads.indices); 383 quads.nextIndex = quads.indices; 384 } else { 385 quads.indices = nullptr; 386 quads.nextIndex = nullptr; 387 } 388 // fill buffers 389 for (int i = 0; i < fPaths.count(); i++) { 390 const PathInfo& pathInfo = fPaths[i]; 391 if (!this->createGeom(lines, 392 quads, 393 pathInfo.fPath, 394 fViewMatrix, 395 pathInfo.fColor, 396 fIsIndexed)) { 397 return; 398 } 399 } 400 int lineVertexOffset = (int) (lines.nextVertex - lines.vertices); 401 int lineIndexOffset = (int) (lines.nextIndex - lines.indices); 402 SkASSERT(lineVertexOffset <= fMaxLineVertices && lineIndexOffset <= 3 * fMaxLineVertices); 403 int quadVertexOffset = (int) (quads.nextVertex - quads.vertices); 404 int quadIndexOffset = (int) (quads.nextIndex - quads.indices); 405 SkASSERT(quadVertexOffset <= fMaxQuadVertices && quadIndexOffset <= 3 * fMaxQuadVertices); 406 407 const GrPipeline* pipeline = fHelper.makePipeline(target); 408 409 if (lineVertexOffset) { 410 sk_sp<GrGeometryProcessor> lineGP; 411 { 412 using namespace GrDefaultGeoProcFactory; 413 lineGP = GrDefaultGeoProcFactory::Make(Color(Color::kPremulGrColorAttribute_Type), 414 Coverage::kSolid_Type, 415 LocalCoords(LocalCoords::kUnused_Type), 416 fViewMatrix); 417 } 418 SkASSERT(lineVertexStride == lineGP->getVertexStride()); 419 420 GrMesh lineMeshes(primitiveType); 421 if (!fIsIndexed) { 422 lineMeshes.setNonIndexedNonInstanced(lineVertexOffset); 423 } else { 424 lineMeshes.setIndexed(lineIndexBuffer, lineIndexOffset, firstLineIndex, 425 0, lineVertexOffset - 1); 426 } 427 lineMeshes.setVertexData(lineVertexBuffer, firstLineVertex); 428 429 // We can get line vertices from path moveTos with no actual segments and thus no index 430 // count. We assert that indexed draws contain a positive index count, so bail here in 431 // that case. 432 if (!fIsIndexed || lineIndexOffset) { 433 target->draw(lineGP.get(), pipeline, lineMeshes); 434 } 435 } 436 437 if (quadVertexOffset) { 438 sk_sp<const GrGeometryProcessor> quadGP(MSAAQuadProcessor::Create(fViewMatrix)); 439 SkASSERT(quadVertexStride == quadGP->getVertexStride()); 440 441 const GrBuffer* quadVertexBuffer; 442 int firstQuadVertex; 443 MSAAQuadVertices::Vertex* quadVertices = (MSAAQuadVertices::Vertex*) 444 target->makeVertexSpace(quadVertexStride, quadVertexOffset, &quadVertexBuffer, 445 &firstQuadVertex); 446 memcpy(quadVertices, quads.vertices, quadVertexStride * quadVertexOffset); 447 GrMesh quadMeshes(GrPrimitiveType::kTriangles); 448 if (!fIsIndexed) { 449 quadMeshes.setNonIndexedNonInstanced(quadVertexOffset); 450 } else { 451 const GrBuffer* quadIndexBuffer; 452 int firstQuadIndex; 453 uint16_t* quadIndices = (uint16_t*) target->makeIndexSpace(quadIndexOffset, 454 &quadIndexBuffer, 455 &firstQuadIndex); 456 memcpy(quadIndices, quads.indices, sizeof(uint16_t) * quadIndexOffset); 457 quadMeshes.setIndexed(quadIndexBuffer, quadIndexOffset, firstQuadIndex, 458 0, quadVertexOffset - 1); 459 } 460 quadMeshes.setVertexData(quadVertexBuffer, firstQuadVertex); 461 target->draw(quadGP.get(), pipeline, quadMeshes); 462 } 463 } 464 465 bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { 466 MSAAPathOp* that = t->cast<MSAAPathOp>(); 467 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) { 468 return false; 469 } 470 471 if (this->bounds().intersects(that->bounds())) { 472 return false; 473 } 474 475 if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) { 476 return false; 477 } 478 479 // If we grow to include 2+ paths we will be indexed. 480 if (((fMaxLineVertices + that->fMaxLineVertices) > kMaxIndexedVertexCnt) || 481 ((fMaxQuadVertices + that->fMaxQuadVertices) > kMaxIndexedVertexCnt)) { 482 return false; 483 } 484 485 fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin()); 486 this->joinBounds(*that); 487 fIsIndexed = true; 488 fMaxLineVertices += that->fMaxLineVertices; 489 fMaxQuadVertices += that->fMaxQuadVertices; 490 return true; 491 } 492 493 bool createGeom(MSAALineVertices& lines, 494 MSAAQuadVertices& quads, 495 const SkPath& path, 496 const SkMatrix& m, 497 SkColor color, 498 bool isIndexed) const { 499 { 500 const SkScalar tolerance = GrPathUtils::scaleToleranceToSrc(kTolerance, m, 501 path.getBounds()); 502 uint16_t subpathIdxStart = (uint16_t) (lines.nextVertex - lines.vertices); 503 504 SkPoint pts[4]; 505 506 bool first = true; 507 SkPath::Iter iter(path, true); 508 509 bool done = false; 510 while (!done) { 511 SkPath::Verb verb = iter.next(pts); 512 switch (verb) { 513 case SkPath::kMove_Verb: 514 if (!first) { 515 uint16_t currIdx = (uint16_t) (lines.nextVertex - lines.vertices); 516 subpathIdxStart = currIdx; 517 } 518 SkASSERT(lines.nextVertex < lines.verticesEnd); 519 *(lines.nextVertex++) = { pts[0], color }; 520 break; 521 case SkPath::kLine_Verb: 522 if (isIndexed) { 523 uint16_t prevIdx = (uint16_t) (lines.nextVertex - lines.vertices - 1); 524 if (prevIdx > subpathIdxStart) { 525 append_contour_edge_indices(subpathIdxStart, prevIdx, lines); 526 } 527 } 528 SkASSERT(lines.nextVertex < lines.verticesEnd); 529 *(lines.nextVertex++) = { pts[1], color }; 530 break; 531 case SkPath::kConic_Verb: { 532 SkScalar weight = iter.conicWeight(); 533 SkAutoConicToQuads converter; 534 const SkPoint* quadPts = converter.computeQuads(pts, weight, tolerance); 535 for (int i = 0; i < converter.countQuads(); ++i) { 536 add_quad(lines, quads, quadPts + i * 2, color, isIndexed, 537 subpathIdxStart); 538 } 539 break; 540 } 541 case SkPath::kQuad_Verb: { 542 add_quad(lines, quads, pts, color, isIndexed, subpathIdxStart); 543 break; 544 } 545 case SkPath::kCubic_Verb: { 546 SkSTArray<15, SkPoint, true> quadPts; 547 GrPathUtils::convertCubicToQuads(pts, tolerance, &quadPts); 548 int count = quadPts.count(); 549 for (int i = 0; i < count; i += 3) { 550 add_quad(lines, quads, &quadPts[i], color, isIndexed, subpathIdxStart); 551 } 552 break; 553 } 554 case SkPath::kClose_Verb: 555 break; 556 case SkPath::kDone_Verb: 557 done = true; 558 } 559 first = false; 560 } 561 } 562 return true; 563 } 564 565 // Lines and quads may render with an index buffer. However, we don't have any support for 566 // overflowing the max index. 567 static constexpr int kMaxIndexedVertexCnt = SK_MaxU16 / 3; 568 struct PathInfo { 569 GrColor fColor; 570 SkPath fPath; 571 }; 572 573 Helper fHelper; 574 SkSTArray<1, PathInfo, true> fPaths; 575 SkMatrix fViewMatrix; 576 int fMaxLineVertices; 577 int fMaxQuadVertices; 578 bool fIsIndexed; 579 580 typedef GrMeshDrawOp INHERITED; 581 }; 582 583 } // anonymous namespace 584 585 bool GrMSAAPathRenderer::internalDrawPath(GrRenderTargetContext* renderTargetContext, 586 GrPaint&& paint, 587 GrAAType aaType, 588 const GrUserStencilSettings& userStencilSettings, 589 const GrClip& clip, 590 const SkMatrix& viewMatrix, 591 const GrShape& shape, 592 bool stencilOnly) { 593 SkASSERT(shape.style().isSimpleFill()); 594 SkPath path; 595 shape.asPath(&path); 596 597 const GrUserStencilSettings* passes[2] = {nullptr, nullptr}; 598 bool reverse = false; 599 600 if (single_pass_shape(shape)) { 601 if (stencilOnly) { 602 passes[0] = &gDirectToStencil; 603 } else { 604 passes[0] = &userStencilSettings; 605 } 606 } else { 607 switch (path.getFillType()) { 608 case SkPath::kInverseEvenOdd_FillType: 609 reverse = true; 610 // fallthrough 611 case SkPath::kEvenOdd_FillType: 612 passes[0] = &gEOStencilPass; 613 if (!stencilOnly) { 614 passes[1] = reverse ? &gInvEOColorPass : &gEOColorPass; 615 } 616 break; 617 618 case SkPath::kInverseWinding_FillType: 619 reverse = true; 620 // fallthrough 621 case SkPath::kWinding_FillType: 622 passes[0] = &gWindStencilPass; 623 if (!stencilOnly) { 624 passes[1] = reverse ? &gInvWindColorPass : &gWindColorPass; 625 } 626 break; 627 default: 628 SkDEBUGFAIL("Unknown path fFill!"); 629 return false; 630 } 631 } 632 633 SkRect devBounds; 634 GetPathDevBounds(path, renderTargetContext->width(), renderTargetContext->height(), viewMatrix, 635 &devBounds); 636 637 SkASSERT(passes[0]); 638 { // First pass 639 bool firstPassIsStencil = stencilOnly || passes[1]; 640 // If we have a cover pass then we ignore the paint in the first pass and apply it in the 641 // second. 642 GrPaint::MoveOrNew firstPassPaint(paint, firstPassIsStencil); 643 if (firstPassIsStencil) { 644 firstPassPaint.paint().setXPFactory(GrDisableColorXPFactory::Get()); 645 } 646 std::unique_ptr<GrDrawOp> op = MSAAPathOp::Make(std::move(firstPassPaint), path, aaType, 647 viewMatrix, devBounds, passes[0]); 648 if (!op) { 649 return false; 650 } 651 renderTargetContext->addDrawOp(clip, std::move(op)); 652 } 653 654 if (passes[1]) { 655 SkRect bounds; 656 SkMatrix localMatrix = SkMatrix::I(); 657 if (reverse) { 658 // draw over the dev bounds (which will be the whole dst surface for inv fill). 659 bounds = devBounds; 660 SkMatrix vmi; 661 // mapRect through persp matrix may not be correct 662 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) { 663 vmi.mapRect(&bounds); 664 } else { 665 if (!viewMatrix.invert(&localMatrix)) { 666 return false; 667 } 668 } 669 } else { 670 bounds = path.getBounds(); 671 } 672 const SkMatrix& viewM = 673 (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() : viewMatrix; 674 renderTargetContext->addDrawOp( 675 clip, 676 GrRectOpFactory::MakeNonAAFillWithLocalMatrix(std::move(paint), viewM, localMatrix, 677 bounds, aaType, passes[1])); 678 } 679 return true; 680 } 681 682 bool GrMSAAPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { 683 // If we aren't a single_pass_shape, we require stencil buffers. 684 if (!single_pass_shape(*args.fShape) && args.fCaps->avoidStencilBuffers()) { 685 return false; 686 } 687 // This path renderer only fills and relies on MSAA for antialiasing. Stroked shapes are 688 // handled by passing on the original shape and letting the caller compute the stroked shape 689 // which will have a fill style. 690 return args.fShape->style().isSimpleFill() && (GrAAType::kCoverage != args.fAAType); 691 } 692 693 bool GrMSAAPathRenderer::onDrawPath(const DrawPathArgs& args) { 694 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), 695 "GrMSAAPathRenderer::onDrawPath"); 696 SkTLazy<GrShape> tmpShape; 697 const GrShape* shape = args.fShape; 698 if (shape->style().applies()) { 699 SkScalar styleScale = GrStyle::MatrixToScaleFactor(*args.fViewMatrix); 700 tmpShape.init(args.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale)); 701 shape = tmpShape.get(); 702 } 703 return this->internalDrawPath(args.fRenderTargetContext, 704 std::move(args.fPaint), 705 args.fAAType, 706 *args.fUserStencilSettings, 707 *args.fClip, 708 *args.fViewMatrix, 709 *shape, 710 false); 711 } 712 713 void GrMSAAPathRenderer::onStencilPath(const StencilPathArgs& args) { 714 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), 715 "GrMSAAPathRenderer::onStencilPath"); 716 SkASSERT(args.fShape->style().isSimpleFill()); 717 SkASSERT(!args.fShape->mayBeInverseFilledAfterStyling()); 718 719 GrPaint paint; 720 paint.setXPFactory(GrDisableColorXPFactory::Get()); 721 722 this->internalDrawPath(args.fRenderTargetContext, std::move(paint), args.fAAType, 723 GrUserStencilSettings::kUnused, *args.fClip, *args.fViewMatrix, 724 *args.fShape, true); 725 } 726 727 /////////////////////////////////////////////////////////////////////////////////////////////////// 728