1 /* 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 8 #include "GrDefaultPathRenderer.h" 9 10 #include "GrBatchFlushState.h" 11 #include "GrBatchTest.h" 12 #include "GrContext.h" 13 #include "GrDefaultGeoProcFactory.h" 14 #include "GrPathUtils.h" 15 #include "GrPipelineBuilder.h" 16 #include "GrVertices.h" 17 #include "SkGeometry.h" 18 #include "SkString.h" 19 #include "SkStrokeRec.h" 20 #include "SkTLazy.h" 21 #include "SkTraceEvent.h" 22 23 #include "batches/GrRectBatchFactory.h" 24 #include "batches/GrVertexBatch.h" 25 26 GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport, 27 bool stencilWrapOpsSupport) 28 : fSeparateStencil(separateStencilSupport) 29 , fStencilWrapOps(stencilWrapOpsSupport) { 30 } 31 32 33 //////////////////////////////////////////////////////////////////////////////// 34 // Stencil rules for paths 35 36 ////// Even/Odd 37 38 GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass, 39 kInvert_StencilOp, 40 kKeep_StencilOp, 41 kAlwaysIfInClip_StencilFunc, 42 0xffff, 43 0xffff, 44 0xffff); 45 46 // ok not to check clip b/c stencil pass only wrote inside clip 47 GR_STATIC_CONST_SAME_STENCIL(gEOColorPass, 48 kZero_StencilOp, 49 kZero_StencilOp, 50 kNotEqual_StencilFunc, 51 0xffff, 52 0x0000, 53 0xffff); 54 55 // have to check clip b/c outside clip will always be zero. 56 GR_STATIC_CONST_SAME_STENCIL(gInvEOColorPass, 57 kZero_StencilOp, 58 kZero_StencilOp, 59 kEqualIfInClip_StencilFunc, 60 0xffff, 61 0x0000, 62 0xffff); 63 64 ////// Winding 65 66 // when we have separate stencil we increment front faces / decrement back faces 67 // when we don't have wrap incr and decr we use the stencil test to simulate 68 // them. 69 70 GR_STATIC_CONST_STENCIL(gWindStencilSeparateWithWrap, 71 kIncWrap_StencilOp, kDecWrap_StencilOp, 72 kKeep_StencilOp, kKeep_StencilOp, 73 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc, 74 0xffff, 0xffff, 75 0xffff, 0xffff, 76 0xffff, 0xffff); 77 78 // if inc'ing the max value, invert to make 0 79 // if dec'ing zero invert to make all ones. 80 // we can't avoid touching the stencil on both passing and 81 // failing, so we can't resctrict ourselves to the clip. 82 GR_STATIC_CONST_STENCIL(gWindStencilSeparateNoWrap, 83 kInvert_StencilOp, kInvert_StencilOp, 84 kIncClamp_StencilOp, kDecClamp_StencilOp, 85 kEqual_StencilFunc, kEqual_StencilFunc, 86 0xffff, 0xffff, 87 0xffff, 0x0000, 88 0xffff, 0xffff); 89 90 // When there are no separate faces we do two passes to setup the winding rule 91 // stencil. First we draw the front faces and inc, then we draw the back faces 92 // and dec. These are same as the above two split into the incrementing and 93 // decrementing passes. 94 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc, 95 kIncWrap_StencilOp, 96 kKeep_StencilOp, 97 kAlwaysIfInClip_StencilFunc, 98 0xffff, 99 0xffff, 100 0xffff); 101 102 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec, 103 kDecWrap_StencilOp, 104 kKeep_StencilOp, 105 kAlwaysIfInClip_StencilFunc, 106 0xffff, 107 0xffff, 108 0xffff); 109 110 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc, 111 kInvert_StencilOp, 112 kIncClamp_StencilOp, 113 kEqual_StencilFunc, 114 0xffff, 115 0xffff, 116 0xffff); 117 118 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec, 119 kInvert_StencilOp, 120 kDecClamp_StencilOp, 121 kEqual_StencilFunc, 122 0xffff, 123 0x0000, 124 0xffff); 125 126 // Color passes are the same whether we use the two-sided stencil or two passes 127 128 GR_STATIC_CONST_SAME_STENCIL(gWindColorPass, 129 kZero_StencilOp, 130 kZero_StencilOp, 131 kNonZeroIfInClip_StencilFunc, 132 0xffff, 133 0x0000, 134 0xffff); 135 136 GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass, 137 kZero_StencilOp, 138 kZero_StencilOp, 139 kEqualIfInClip_StencilFunc, 140 0xffff, 141 0x0000, 142 0xffff); 143 144 ////// Normal render to stencil 145 146 // Sometimes the default path renderer can draw a path directly to the stencil 147 // buffer without having to first resolve the interior / exterior. 148 GR_STATIC_CONST_SAME_STENCIL(gDirectToStencil, 149 kZero_StencilOp, 150 kIncClamp_StencilOp, 151 kAlwaysIfInClip_StencilFunc, 152 0xffff, 153 0x0000, 154 0xffff); 155 156 //////////////////////////////////////////////////////////////////////////////// 157 // Helpers for drawPath 158 159 #define STENCIL_OFF 0 // Always disable stencil (even when needed) 160 161 static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& stroke) { 162 #if STENCIL_OFF 163 return true; 164 #else 165 if (!stroke.isHairlineStyle() && !path.isInverseFillType()) { 166 return path.isConvex(); 167 } 168 return false; 169 #endif 170 } 171 172 GrPathRenderer::StencilSupport 173 GrDefaultPathRenderer::onGetStencilSupport(const SkPath& path, const GrStrokeInfo& stroke) const { 174 if (single_pass_path(path, stroke)) { 175 return GrPathRenderer::kNoRestriction_StencilSupport; 176 } else { 177 return GrPathRenderer::kStencilOnly_StencilSupport; 178 } 179 } 180 181 static inline void append_countour_edge_indices(bool hairLine, 182 uint16_t fanCenterIdx, 183 uint16_t edgeV0Idx, 184 uint16_t** indices) { 185 // when drawing lines we're appending line segments along 186 // the contour. When applying the other fill rules we're 187 // drawing triangle fans around fanCenterIdx. 188 if (!hairLine) { 189 *((*indices)++) = fanCenterIdx; 190 } 191 *((*indices)++) = edgeV0Idx; 192 *((*indices)++) = edgeV0Idx + 1; 193 } 194 195 static inline void add_quad(SkPoint** vert, const SkPoint* base, const SkPoint pts[], 196 SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol, bool indexed, 197 bool isHairline, uint16_t subpathIdxStart, int offset, uint16_t** idx) { 198 // first pt of quad is the pt we ended on in previous step 199 uint16_t firstQPtIdx = (uint16_t)(*vert - base) - 1 + offset; 200 uint16_t numPts = (uint16_t) 201 GrPathUtils::generateQuadraticPoints( 202 pts[0], pts[1], pts[2], 203 srcSpaceTolSqd, vert, 204 GrPathUtils::quadraticPointCount(pts, srcSpaceTol)); 205 if (indexed) { 206 for (uint16_t i = 0; i < numPts; ++i) { 207 append_countour_edge_indices(isHairline, subpathIdxStart, 208 firstQPtIdx + i, idx); 209 } 210 } 211 } 212 213 class DefaultPathBatch : public GrVertexBatch { 214 public: 215 DEFINE_BATCH_CLASS_ID 216 217 struct Geometry { 218 GrColor fColor; 219 SkPath fPath; 220 SkScalar fTolerance; 221 }; 222 223 static GrDrawBatch* Create(const Geometry& geometry, uint8_t coverage, 224 const SkMatrix& viewMatrix, bool isHairline, 225 const SkRect& devBounds) { 226 return new DefaultPathBatch(geometry, coverage, viewMatrix, isHairline, devBounds); 227 } 228 229 const char* name() const override { return "DefaultPathBatch"; } 230 231 void computePipelineOptimizations(GrInitInvariantOutput* color, 232 GrInitInvariantOutput* coverage, 233 GrBatchToXPOverrides* overrides) const override { 234 // When this is called on a batch, there is only one geometry bundle 235 color->setKnownFourComponents(fGeoData[0].fColor); 236 coverage->setKnownSingleComponent(this->coverage()); 237 } 238 239 private: 240 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { 241 // Handle any color overrides 242 if (!overrides.readsColor()) { 243 fGeoData[0].fColor = GrColor_ILLEGAL; 244 } 245 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); 246 247 // setup batch properties 248 fBatch.fColorIgnored = !overrides.readsColor(); 249 fBatch.fColor = fGeoData[0].fColor; 250 fBatch.fUsesLocalCoords = overrides.readsLocalCoords(); 251 fBatch.fCoverageIgnored = !overrides.readsCoverage(); 252 } 253 254 void onPrepareDraws(Target* target) const override { 255 SkAutoTUnref<const GrGeometryProcessor> gp; 256 { 257 using namespace GrDefaultGeoProcFactory; 258 Color color(this->color()); 259 Coverage coverage(this->coverage()); 260 if (this->coverageIgnored()) { 261 coverage.fType = Coverage::kNone_Type; 262 } 263 LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUsePosition_Type : 264 LocalCoords::kUnused_Type); 265 gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoords, 266 this->viewMatrix())); 267 } 268 269 size_t vertexStride = gp->getVertexStride(); 270 SkASSERT(vertexStride == sizeof(SkPoint)); 271 272 target->initDraw(gp, this->pipeline()); 273 274 int instanceCount = fGeoData.count(); 275 276 // compute number of vertices 277 int maxVertices = 0; 278 279 // We will use index buffers if we have multiple paths or one path with multiple contours 280 bool isIndexed = instanceCount > 1; 281 for (int i = 0; i < instanceCount; i++) { 282 const Geometry& args = fGeoData[i]; 283 284 int contourCount; 285 maxVertices += GrPathUtils::worstCasePointCount(args.fPath, &contourCount, 286 args.fTolerance); 287 288 isIndexed = isIndexed || contourCount > 1; 289 } 290 291 if (maxVertices == 0 || maxVertices > ((int)SK_MaxU16 + 1)) { 292 //SkDebugf("Cannot render path (%d)\n", maxVertices); 293 return; 294 } 295 296 // determine primitiveType 297 int maxIndices = 0; 298 GrPrimitiveType primitiveType; 299 if (this->isHairline()) { 300 if (isIndexed) { 301 maxIndices = 2 * maxVertices; 302 primitiveType = kLines_GrPrimitiveType; 303 } else { 304 primitiveType = kLineStrip_GrPrimitiveType; 305 } 306 } else { 307 if (isIndexed) { 308 maxIndices = 3 * maxVertices; 309 primitiveType = kTriangles_GrPrimitiveType; 310 } else { 311 primitiveType = kTriangleFan_GrPrimitiveType; 312 } 313 } 314 315 // allocate vertex / index buffers 316 const GrVertexBuffer* vertexBuffer; 317 int firstVertex; 318 319 void* verts = target->makeVertexSpace(vertexStride, maxVertices, 320 &vertexBuffer, &firstVertex); 321 322 if (!verts) { 323 SkDebugf("Could not allocate vertices\n"); 324 return; 325 } 326 327 const GrIndexBuffer* indexBuffer = nullptr; 328 int firstIndex = 0; 329 330 void* indices = nullptr; 331 if (isIndexed) { 332 indices = target->makeIndexSpace(maxIndices, &indexBuffer, &firstIndex); 333 334 if (!indices) { 335 SkDebugf("Could not allocate indices\n"); 336 return; 337 } 338 } 339 340 // fill buffers 341 int vertexOffset = 0; 342 int indexOffset = 0; 343 for (int i = 0; i < instanceCount; i++) { 344 const Geometry& args = fGeoData[i]; 345 346 int vertexCnt = 0; 347 int indexCnt = 0; 348 if (!this->createGeom(verts, 349 vertexOffset, 350 indices, 351 indexOffset, 352 &vertexCnt, 353 &indexCnt, 354 args.fPath, 355 args.fTolerance, 356 isIndexed)) { 357 return; 358 } 359 360 vertexOffset += vertexCnt; 361 indexOffset += indexCnt; 362 SkASSERT(vertexOffset <= maxVertices && indexOffset <= maxIndices); 363 } 364 365 GrVertices vertices; 366 if (isIndexed) { 367 vertices.initIndexed(primitiveType, vertexBuffer, indexBuffer, firstVertex, firstIndex, 368 vertexOffset, indexOffset); 369 } else { 370 vertices.init(primitiveType, vertexBuffer, firstVertex, vertexOffset); 371 } 372 target->draw(vertices); 373 374 // put back reserves 375 target->putBackIndices((size_t)(maxIndices - indexOffset)); 376 target->putBackVertices((size_t)(maxVertices - vertexOffset), (size_t)vertexStride); 377 } 378 379 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } 380 381 DefaultPathBatch(const Geometry& geometry, uint8_t coverage, const SkMatrix& viewMatrix, 382 bool isHairline, const SkRect& devBounds) 383 : INHERITED(ClassID()) { 384 fBatch.fCoverage = coverage; 385 fBatch.fIsHairline = isHairline; 386 fBatch.fViewMatrix = viewMatrix; 387 fGeoData.push_back(geometry); 388 389 this->setBounds(devBounds); 390 391 // This is b.c. hairlines are notionally infinitely thin so without expansion 392 // two overlapping lines could be reordered even though they hit the same pixels. 393 if (isHairline) { 394 fBounds.outset(0.5f, 0.5f); 395 } 396 } 397 398 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { 399 DefaultPathBatch* that = t->cast<DefaultPathBatch>(); 400 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), 401 that->bounds(), caps)) { 402 return false; 403 } 404 405 if (this->color() != that->color()) { 406 return false; 407 } 408 409 if (this->coverage() != that->coverage()) { 410 return false; 411 } 412 413 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { 414 return false; 415 } 416 417 if (this->isHairline() != that->isHairline()) { 418 return false; 419 } 420 421 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()); 422 this->joinBounds(that->bounds()); 423 return true; 424 } 425 426 bool createGeom(void* vertices, 427 size_t vertexOffset, 428 void* indices, 429 size_t indexOffset, 430 int* vertexCnt, 431 int* indexCnt, 432 const SkPath& path, 433 SkScalar srcSpaceTol, 434 bool isIndexed) const { 435 { 436 SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol); 437 438 uint16_t indexOffsetU16 = (uint16_t)indexOffset; 439 uint16_t vertexOffsetU16 = (uint16_t)vertexOffset; 440 441 uint16_t* idxBase = reinterpret_cast<uint16_t*>(indices) + indexOffsetU16; 442 uint16_t* idx = idxBase; 443 uint16_t subpathIdxStart = vertexOffsetU16; 444 445 SkPoint* base = reinterpret_cast<SkPoint*>(vertices) + vertexOffset; 446 SkPoint* vert = base; 447 448 SkPoint pts[4]; 449 450 bool first = true; 451 int subpath = 0; 452 453 SkPath::Iter iter(path, false); 454 455 bool done = false; 456 while (!done) { 457 SkPath::Verb verb = iter.next(pts); 458 switch (verb) { 459 case SkPath::kMove_Verb: 460 if (!first) { 461 uint16_t currIdx = (uint16_t) (vert - base) + vertexOffsetU16; 462 subpathIdxStart = currIdx; 463 ++subpath; 464 } 465 *vert = pts[0]; 466 vert++; 467 break; 468 case SkPath::kLine_Verb: 469 if (isIndexed) { 470 uint16_t prevIdx = (uint16_t)(vert - base) - 1 + vertexOffsetU16; 471 append_countour_edge_indices(this->isHairline(), subpathIdxStart, 472 prevIdx, &idx); 473 } 474 *(vert++) = pts[1]; 475 break; 476 case SkPath::kConic_Verb: { 477 SkScalar weight = iter.conicWeight(); 478 SkAutoConicToQuads converter; 479 // Converting in src-space, hance the finer tolerance (0.25) 480 // TODO: find a way to do this in dev-space so the tolerance means something 481 const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.25f); 482 for (int i = 0; i < converter.countQuads(); ++i) { 483 add_quad(&vert, base, quadPts + i*2, srcSpaceTolSqd, srcSpaceTol, 484 isIndexed, this->isHairline(), subpathIdxStart, 485 (int)vertexOffset, &idx); 486 } 487 break; 488 } 489 case SkPath::kQuad_Verb: 490 add_quad(&vert, base, pts, srcSpaceTolSqd, srcSpaceTol, isIndexed, 491 this->isHairline(), subpathIdxStart, (int)vertexOffset, &idx); 492 break; 493 case SkPath::kCubic_Verb: { 494 // first pt of cubic is the pt we ended on in previous step 495 uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1 + vertexOffsetU16; 496 uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints( 497 pts[0], pts[1], pts[2], pts[3], 498 srcSpaceTolSqd, &vert, 499 GrPathUtils::cubicPointCount(pts, srcSpaceTol)); 500 if (isIndexed) { 501 for (uint16_t i = 0; i < numPts; ++i) { 502 append_countour_edge_indices(this->isHairline(), subpathIdxStart, 503 firstCPtIdx + i, &idx); 504 } 505 } 506 break; 507 } 508 case SkPath::kClose_Verb: 509 break; 510 case SkPath::kDone_Verb: 511 done = true; 512 } 513 first = false; 514 } 515 516 *vertexCnt = static_cast<int>(vert - base); 517 *indexCnt = static_cast<int>(idx - idxBase); 518 519 } 520 return true; 521 } 522 523 GrColor color() const { return fBatch.fColor; } 524 uint8_t coverage() const { return fBatch.fCoverage; } 525 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } 526 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; } 527 bool isHairline() const { return fBatch.fIsHairline; } 528 bool coverageIgnored() const { return fBatch.fCoverageIgnored; } 529 530 struct BatchTracker { 531 GrColor fColor; 532 uint8_t fCoverage; 533 SkMatrix fViewMatrix; 534 bool fUsesLocalCoords; 535 bool fColorIgnored; 536 bool fCoverageIgnored; 537 bool fIsHairline; 538 }; 539 540 BatchTracker fBatch; 541 SkSTArray<1, Geometry, true> fGeoData; 542 543 typedef GrVertexBatch INHERITED; 544 }; 545 546 bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target, 547 GrPipelineBuilder* pipelineBuilder, 548 GrColor color, 549 const SkMatrix& viewMatrix, 550 const SkPath& path, 551 const GrStrokeInfo& origStroke, 552 bool stencilOnly) { 553 SkTCopyOnFirstWrite<GrStrokeInfo> stroke(origStroke); 554 555 SkScalar hairlineCoverage; 556 uint8_t newCoverage = 0xff; 557 if (IsStrokeHairlineOrEquivalent(*stroke, viewMatrix, &hairlineCoverage)) { 558 newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff); 559 560 if (!stroke->isHairlineStyle()) { 561 stroke.writable()->setHairlineStyle(); 562 } 563 } 564 565 const bool isHairline = stroke->isHairlineStyle(); 566 567 // Save the current xp on the draw state so we can reset it if needed 568 const GrXPFactory* xpFactory = pipelineBuilder->getXPFactory(); 569 SkAutoTUnref<const GrXPFactory> backupXPFactory(SkSafeRef(xpFactory)); 570 // face culling doesn't make sense here 571 SkASSERT(GrPipelineBuilder::kBoth_DrawFace == pipelineBuilder->getDrawFace()); 572 573 int passCount = 0; 574 const GrStencilSettings* passes[3]; 575 GrPipelineBuilder::DrawFace drawFace[3]; 576 bool reverse = false; 577 bool lastPassIsBounds; 578 579 if (isHairline) { 580 passCount = 1; 581 if (stencilOnly) { 582 passes[0] = &gDirectToStencil; 583 } else { 584 passes[0] = nullptr; 585 } 586 lastPassIsBounds = false; 587 drawFace[0] = GrPipelineBuilder::kBoth_DrawFace; 588 } else { 589 if (single_pass_path(path, *stroke)) { 590 passCount = 1; 591 if (stencilOnly) { 592 passes[0] = &gDirectToStencil; 593 } else { 594 passes[0] = nullptr; 595 } 596 drawFace[0] = GrPipelineBuilder::kBoth_DrawFace; 597 lastPassIsBounds = false; 598 } else { 599 switch (path.getFillType()) { 600 case SkPath::kInverseEvenOdd_FillType: 601 reverse = true; 602 // fallthrough 603 case SkPath::kEvenOdd_FillType: 604 passes[0] = &gEOStencilPass; 605 if (stencilOnly) { 606 passCount = 1; 607 lastPassIsBounds = false; 608 } else { 609 passCount = 2; 610 lastPassIsBounds = true; 611 if (reverse) { 612 passes[1] = &gInvEOColorPass; 613 } else { 614 passes[1] = &gEOColorPass; 615 } 616 } 617 drawFace[0] = drawFace[1] = GrPipelineBuilder::kBoth_DrawFace; 618 break; 619 620 case SkPath::kInverseWinding_FillType: 621 reverse = true; 622 // fallthrough 623 case SkPath::kWinding_FillType: 624 if (fSeparateStencil) { 625 if (fStencilWrapOps) { 626 passes[0] = &gWindStencilSeparateWithWrap; 627 } else { 628 passes[0] = &gWindStencilSeparateNoWrap; 629 } 630 passCount = 2; 631 drawFace[0] = GrPipelineBuilder::kBoth_DrawFace; 632 } else { 633 if (fStencilWrapOps) { 634 passes[0] = &gWindSingleStencilWithWrapInc; 635 passes[1] = &gWindSingleStencilWithWrapDec; 636 } else { 637 passes[0] = &gWindSingleStencilNoWrapInc; 638 passes[1] = &gWindSingleStencilNoWrapDec; 639 } 640 // which is cw and which is ccw is arbitrary. 641 drawFace[0] = GrPipelineBuilder::kCW_DrawFace; 642 drawFace[1] = GrPipelineBuilder::kCCW_DrawFace; 643 passCount = 3; 644 } 645 if (stencilOnly) { 646 lastPassIsBounds = false; 647 --passCount; 648 } else { 649 lastPassIsBounds = true; 650 drawFace[passCount-1] = GrPipelineBuilder::kBoth_DrawFace; 651 if (reverse) { 652 passes[passCount-1] = &gInvWindColorPass; 653 } else { 654 passes[passCount-1] = &gWindColorPass; 655 } 656 } 657 break; 658 default: 659 SkDEBUGFAIL("Unknown path fFill!"); 660 return false; 661 } 662 } 663 } 664 665 SkScalar tol = GrPathUtils::kDefaultTolerance; 666 SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds()); 667 668 SkRect devBounds; 669 GetPathDevBounds(path, pipelineBuilder->getRenderTarget(), viewMatrix, &devBounds); 670 671 for (int p = 0; p < passCount; ++p) { 672 pipelineBuilder->setDrawFace(drawFace[p]); 673 if (passes[p]) { 674 *pipelineBuilder->stencil() = *passes[p]; 675 } 676 677 if (lastPassIsBounds && (p == passCount-1)) { 678 // Reset the XP Factory on pipelineBuilder 679 pipelineBuilder->setXPFactory(backupXPFactory); 680 SkRect bounds; 681 SkMatrix localMatrix = SkMatrix::I(); 682 if (reverse) { 683 SkASSERT(pipelineBuilder->getRenderTarget()); 684 // draw over the dev bounds (which will be the whole dst surface for inv fill). 685 bounds = devBounds; 686 SkMatrix vmi; 687 // mapRect through persp matrix may not be correct 688 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) { 689 vmi.mapRect(&bounds); 690 } else { 691 if (!viewMatrix.invert(&localMatrix)) { 692 return false; 693 } 694 } 695 } else { 696 bounds = path.getBounds(); 697 } 698 const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() : 699 viewMatrix; 700 SkAutoTUnref<GrDrawBatch> batch( 701 GrRectBatchFactory::CreateNonAAFill(color, viewM, bounds, nullptr, 702 &localMatrix)); 703 target->drawBatch(*pipelineBuilder, batch); 704 } else { 705 if (passCount > 1) { 706 pipelineBuilder->setDisableColorXPFactory(); 707 } 708 709 DefaultPathBatch::Geometry geometry; 710 geometry.fColor = color; 711 geometry.fPath = path; 712 geometry.fTolerance = srcSpaceTol; 713 714 SkAutoTUnref<GrDrawBatch> batch(DefaultPathBatch::Create(geometry, newCoverage, 715 viewMatrix, isHairline, 716 devBounds)); 717 718 target->drawBatch(*pipelineBuilder, batch); 719 } 720 } 721 return true; 722 } 723 724 bool GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { 725 // this class can draw any path with any fill but doesn't do any anti-aliasing. 726 return !args.fAntiAlias && (args.fStroke->isFillStyle() || 727 IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, 728 nullptr)); 729 } 730 731 bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) { 732 GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), "GrDefaultPathRenderer::onDrawPath"); 733 return this->internalDrawPath(args.fTarget, 734 args.fPipelineBuilder, 735 args.fColor, 736 *args.fViewMatrix, 737 *args.fPath, 738 *args.fStroke, 739 false); 740 } 741 742 void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) { 743 GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),"GrDefaultPathRenderer::onStencilPath"); 744 SkASSERT(SkPath::kInverseEvenOdd_FillType != args.fPath->getFillType()); 745 SkASSERT(SkPath::kInverseWinding_FillType != args.fPath->getFillType()); 746 this->internalDrawPath(args.fTarget, args.fPipelineBuilder, GrColor_WHITE, *args.fViewMatrix, 747 *args.fPath, *args.fStroke, true); 748 } 749 750 /////////////////////////////////////////////////////////////////////////////////////////////////// 751 752 #ifdef GR_TEST_UTILS 753 754 DRAW_BATCH_TEST_DEFINE(DefaultPathBatch) { 755 GrColor color = GrRandomColor(random); 756 SkMatrix viewMatrix = GrTest::TestMatrix(random); 757 758 // For now just hairlines because the other types of draws require two batches. 759 // TODO we should figure out a way to combine the stencil and cover steps into one batch 760 GrStrokeInfo stroke(SkStrokeRec::kHairline_InitStyle); 761 SkPath path = GrTest::TestPath(random); 762 763 // Compute srcSpaceTol 764 SkRect bounds = path.getBounds(); 765 SkScalar tol = GrPathUtils::kDefaultTolerance; 766 SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, bounds); 767 768 DefaultPathBatch::Geometry geometry; 769 geometry.fColor = color; 770 geometry.fPath = path; 771 geometry.fTolerance = srcSpaceTol; 772 773 viewMatrix.mapRect(&bounds); 774 uint8_t coverage = GrRandomCoverage(random); 775 return DefaultPathBatch::Create(geometry, coverage, viewMatrix, true, bounds); 776 } 777 778 #endif 779