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 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 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 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 : 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 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 void visitProxies(const VisitProxyFunc& func) const override { 247 fHelper.visitProxies(func); 248 } 249 250 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 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 275 FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); } 276 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: 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 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 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 499 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 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 693 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 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 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