GrDefaultPathRenderer.cpp revision 2e3b3e369d79e78f7635d4c20e83a47ab571bdf2
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 "GrContext.h" 11#include "GrDefaultGeoProcFactory.h" 12#include "GrDrawState.h" 13#include "GrPathUtils.h" 14#include "SkString.h" 15#include "SkStrokeRec.h" 16#include "SkTLazy.h" 17#include "SkTraceEvent.h" 18 19 20GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport, 21 bool stencilWrapOpsSupport) 22 : fSeparateStencil(separateStencilSupport) 23 , fStencilWrapOps(stencilWrapOpsSupport) { 24} 25 26 27//////////////////////////////////////////////////////////////////////////////// 28// Stencil rules for paths 29 30////// Even/Odd 31 32GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass, 33 kInvert_StencilOp, 34 kKeep_StencilOp, 35 kAlwaysIfInClip_StencilFunc, 36 0xffff, 37 0xffff, 38 0xffff); 39 40// ok not to check clip b/c stencil pass only wrote inside clip 41GR_STATIC_CONST_SAME_STENCIL(gEOColorPass, 42 kZero_StencilOp, 43 kZero_StencilOp, 44 kNotEqual_StencilFunc, 45 0xffff, 46 0x0000, 47 0xffff); 48 49// have to check clip b/c outside clip will always be zero. 50GR_STATIC_CONST_SAME_STENCIL(gInvEOColorPass, 51 kZero_StencilOp, 52 kZero_StencilOp, 53 kEqualIfInClip_StencilFunc, 54 0xffff, 55 0x0000, 56 0xffff); 57 58////// Winding 59 60// when we have separate stencil we increment front faces / decrement back faces 61// when we don't have wrap incr and decr we use the stencil test to simulate 62// them. 63 64GR_STATIC_CONST_STENCIL(gWindStencilSeparateWithWrap, 65 kIncWrap_StencilOp, kDecWrap_StencilOp, 66 kKeep_StencilOp, kKeep_StencilOp, 67 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc, 68 0xffff, 0xffff, 69 0xffff, 0xffff, 70 0xffff, 0xffff); 71 72// if inc'ing the max value, invert to make 0 73// if dec'ing zero invert to make all ones. 74// we can't avoid touching the stencil on both passing and 75// failing, so we can't resctrict ourselves to the clip. 76GR_STATIC_CONST_STENCIL(gWindStencilSeparateNoWrap, 77 kInvert_StencilOp, kInvert_StencilOp, 78 kIncClamp_StencilOp, kDecClamp_StencilOp, 79 kEqual_StencilFunc, kEqual_StencilFunc, 80 0xffff, 0xffff, 81 0xffff, 0x0000, 82 0xffff, 0xffff); 83 84// When there are no separate faces we do two passes to setup the winding rule 85// stencil. First we draw the front faces and inc, then we draw the back faces 86// and dec. These are same as the above two split into the incrementing and 87// decrementing passes. 88GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc, 89 kIncWrap_StencilOp, 90 kKeep_StencilOp, 91 kAlwaysIfInClip_StencilFunc, 92 0xffff, 93 0xffff, 94 0xffff); 95 96GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec, 97 kDecWrap_StencilOp, 98 kKeep_StencilOp, 99 kAlwaysIfInClip_StencilFunc, 100 0xffff, 101 0xffff, 102 0xffff); 103 104GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc, 105 kInvert_StencilOp, 106 kIncClamp_StencilOp, 107 kEqual_StencilFunc, 108 0xffff, 109 0xffff, 110 0xffff); 111 112GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec, 113 kInvert_StencilOp, 114 kDecClamp_StencilOp, 115 kEqual_StencilFunc, 116 0xffff, 117 0x0000, 118 0xffff); 119 120// Color passes are the same whether we use the two-sided stencil or two passes 121 122GR_STATIC_CONST_SAME_STENCIL(gWindColorPass, 123 kZero_StencilOp, 124 kZero_StencilOp, 125 kNonZeroIfInClip_StencilFunc, 126 0xffff, 127 0x0000, 128 0xffff); 129 130GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass, 131 kZero_StencilOp, 132 kZero_StencilOp, 133 kEqualIfInClip_StencilFunc, 134 0xffff, 135 0x0000, 136 0xffff); 137 138////// Normal render to stencil 139 140// Sometimes the default path renderer can draw a path directly to the stencil 141// buffer without having to first resolve the interior / exterior. 142GR_STATIC_CONST_SAME_STENCIL(gDirectToStencil, 143 kZero_StencilOp, 144 kIncClamp_StencilOp, 145 kAlwaysIfInClip_StencilFunc, 146 0xffff, 147 0x0000, 148 0xffff); 149 150//////////////////////////////////////////////////////////////////////////////// 151// Helpers for drawPath 152 153#define STENCIL_OFF 0 // Always disable stencil (even when needed) 154 155static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& stroke) { 156#if STENCIL_OFF 157 return true; 158#else 159 if (!stroke.isHairlineStyle() && !path.isInverseFillType()) { 160 return path.isConvex(); 161 } 162 return false; 163#endif 164} 165 166GrPathRenderer::StencilSupport 167GrDefaultPathRenderer::onGetStencilSupport(const GrDrawTarget*, 168 const GrDrawState*, 169 const SkPath& path, 170 const SkStrokeRec& stroke) const { 171 if (single_pass_path(path, stroke)) { 172 return GrPathRenderer::kNoRestriction_StencilSupport; 173 } else { 174 return GrPathRenderer::kStencilOnly_StencilSupport; 175 } 176} 177 178static inline void append_countour_edge_indices(bool hairLine, 179 uint16_t fanCenterIdx, 180 uint16_t edgeV0Idx, 181 uint16_t** indices) { 182 // when drawing lines we're appending line segments along 183 // the contour. When applying the other fill rules we're 184 // drawing triangle fans around fanCenterIdx. 185 if (!hairLine) { 186 *((*indices)++) = fanCenterIdx; 187 } 188 *((*indices)++) = edgeV0Idx; 189 *((*indices)++) = edgeV0Idx + 1; 190} 191 192bool GrDefaultPathRenderer::createGeom(GrDrawTarget* target, 193 GrDrawState* drawState, 194 GrPrimitiveType* primType, 195 int* vertexCnt, 196 int* indexCnt, 197 GrDrawTarget::AutoReleaseGeometry* arg, 198 const SkPath& path, 199 const SkStrokeRec& stroke, 200 SkScalar srcSpaceTol) { 201 { 202 SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol); 203 int contourCnt; 204 int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, 205 srcSpaceTol); 206 207 if (maxPts <= 0) { 208 return false; 209 } 210 if (maxPts > ((int)SK_MaxU16 + 1)) { 211 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts); 212 return false; 213 } 214 215 bool indexed = contourCnt > 1; 216 217 const bool isHairline = stroke.isHairlineStyle(); 218 219 int maxIdxs = 0; 220 if (isHairline) { 221 if (indexed) { 222 maxIdxs = 2 * maxPts; 223 *primType = kLines_GrPrimitiveType; 224 } else { 225 *primType = kLineStrip_GrPrimitiveType; 226 } 227 } else { 228 if (indexed) { 229 maxIdxs = 3 * maxPts; 230 *primType = kTriangles_GrPrimitiveType; 231 } else { 232 *primType = kTriangleFan_GrPrimitiveType; 233 } 234 } 235 236 if (!arg->set(target, maxPts, GrDefaultGeoProcFactory::DefaultVertexStride(), maxIdxs)) { 237 return false; 238 } 239 SkASSERT(GrDefaultGeoProcFactory::DefaultVertexStride() == sizeof(SkPoint)); 240 241 uint16_t* idxBase = reinterpret_cast<uint16_t*>(arg->indices()); 242 uint16_t* idx = idxBase; 243 uint16_t subpathIdxStart = 0; 244 245 SkPoint* base = reinterpret_cast<SkPoint*>(arg->vertices()); 246 SkASSERT(base); 247 SkPoint* vert = base; 248 249 SkPoint pts[4]; 250 251 bool first = true; 252 int subpath = 0; 253 254 SkPath::Iter iter(path, false); 255 256 for (;;) { 257 SkPath::Verb verb = iter.next(pts); 258 switch (verb) { 259 case SkPath::kConic_Verb: 260 SkASSERT(0); 261 break; 262 case SkPath::kMove_Verb: 263 if (!first) { 264 uint16_t currIdx = (uint16_t) (vert - base); 265 subpathIdxStart = currIdx; 266 ++subpath; 267 } 268 *vert = pts[0]; 269 vert++; 270 break; 271 case SkPath::kLine_Verb: 272 if (indexed) { 273 uint16_t prevIdx = (uint16_t)(vert - base) - 1; 274 append_countour_edge_indices(isHairline, subpathIdxStart, 275 prevIdx, &idx); 276 } 277 *(vert++) = pts[1]; 278 break; 279 case SkPath::kQuad_Verb: { 280 // first pt of quad is the pt we ended on in previous step 281 uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1; 282 uint16_t numPts = (uint16_t) 283 GrPathUtils::generateQuadraticPoints( 284 pts[0], pts[1], pts[2], 285 srcSpaceTolSqd, &vert, 286 GrPathUtils::quadraticPointCount(pts, srcSpaceTol)); 287 if (indexed) { 288 for (uint16_t i = 0; i < numPts; ++i) { 289 append_countour_edge_indices(isHairline, subpathIdxStart, 290 firstQPtIdx + i, &idx); 291 } 292 } 293 break; 294 } 295 case SkPath::kCubic_Verb: { 296 // first pt of cubic is the pt we ended on in previous step 297 uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1; 298 uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints( 299 pts[0], pts[1], pts[2], pts[3], 300 srcSpaceTolSqd, &vert, 301 GrPathUtils::cubicPointCount(pts, srcSpaceTol)); 302 if (indexed) { 303 for (uint16_t i = 0; i < numPts; ++i) { 304 append_countour_edge_indices(isHairline, subpathIdxStart, 305 firstCPtIdx + i, &idx); 306 } 307 } 308 break; 309 } 310 case SkPath::kClose_Verb: 311 break; 312 case SkPath::kDone_Verb: 313 // uint16_t currIdx = (uint16_t) (vert - base); 314 goto FINISHED; 315 } 316 first = false; 317 } 318FINISHED: 319 SkASSERT((vert - base) <= maxPts); 320 SkASSERT((idx - idxBase) <= maxIdxs); 321 322 *vertexCnt = static_cast<int>(vert - base); 323 *indexCnt = static_cast<int>(idx - idxBase); 324 325 } 326 return true; 327} 328 329bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target, 330 GrDrawState* drawState, 331 GrColor color, 332 const SkPath& path, 333 const SkStrokeRec& origStroke, 334 bool stencilOnly) { 335 SkMatrix viewM = drawState->getViewMatrix(); 336 SkTCopyOnFirstWrite<SkStrokeRec> stroke(origStroke); 337 338 SkScalar hairlineCoverage; 339 uint8_t newCoverage = 0xff; 340 if (IsStrokeHairlineOrEquivalent(*stroke, drawState->getViewMatrix(), 341 &hairlineCoverage)) { 342 newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff); 343 344 if (!stroke->isHairlineStyle()) { 345 stroke.writable()->setHairlineStyle(); 346 } 347 } 348 349 SkScalar tol = SK_Scalar1; 350 tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds()); 351 352 int vertexCnt; 353 int indexCnt; 354 GrPrimitiveType primType; 355 GrDrawTarget::AutoReleaseGeometry arg; 356 if (!this->createGeom(target, 357 drawState, 358 &primType, 359 &vertexCnt, 360 &indexCnt, 361 &arg, 362 path, 363 *stroke, 364 tol)) { 365 return false; 366 } 367 368 bool colorWritesWereDisabled = drawState->isColorWriteDisabled(); 369 // face culling doesn't make sense here 370 SkASSERT(GrDrawState::kBoth_DrawFace == drawState->getDrawFace()); 371 372 int passCount = 0; 373 const GrStencilSettings* passes[3]; 374 GrDrawState::DrawFace drawFace[3]; 375 bool reverse = false; 376 bool lastPassIsBounds; 377 378 if (stroke->isHairlineStyle()) { 379 passCount = 1; 380 if (stencilOnly) { 381 passes[0] = &gDirectToStencil; 382 } else { 383 passes[0] = NULL; 384 } 385 lastPassIsBounds = false; 386 drawFace[0] = GrDrawState::kBoth_DrawFace; 387 } else { 388 if (single_pass_path(path, *stroke)) { 389 passCount = 1; 390 if (stencilOnly) { 391 passes[0] = &gDirectToStencil; 392 } else { 393 passes[0] = NULL; 394 } 395 drawFace[0] = GrDrawState::kBoth_DrawFace; 396 lastPassIsBounds = false; 397 } else { 398 switch (path.getFillType()) { 399 case SkPath::kInverseEvenOdd_FillType: 400 reverse = true; 401 // fallthrough 402 case SkPath::kEvenOdd_FillType: 403 passes[0] = &gEOStencilPass; 404 if (stencilOnly) { 405 passCount = 1; 406 lastPassIsBounds = false; 407 } else { 408 passCount = 2; 409 lastPassIsBounds = true; 410 if (reverse) { 411 passes[1] = &gInvEOColorPass; 412 } else { 413 passes[1] = &gEOColorPass; 414 } 415 } 416 drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace; 417 break; 418 419 case SkPath::kInverseWinding_FillType: 420 reverse = true; 421 // fallthrough 422 case SkPath::kWinding_FillType: 423 if (fSeparateStencil) { 424 if (fStencilWrapOps) { 425 passes[0] = &gWindStencilSeparateWithWrap; 426 } else { 427 passes[0] = &gWindStencilSeparateNoWrap; 428 } 429 passCount = 2; 430 drawFace[0] = GrDrawState::kBoth_DrawFace; 431 } else { 432 if (fStencilWrapOps) { 433 passes[0] = &gWindSingleStencilWithWrapInc; 434 passes[1] = &gWindSingleStencilWithWrapDec; 435 } else { 436 passes[0] = &gWindSingleStencilNoWrapInc; 437 passes[1] = &gWindSingleStencilNoWrapDec; 438 } 439 // which is cw and which is ccw is arbitrary. 440 drawFace[0] = GrDrawState::kCW_DrawFace; 441 drawFace[1] = GrDrawState::kCCW_DrawFace; 442 passCount = 3; 443 } 444 if (stencilOnly) { 445 lastPassIsBounds = false; 446 --passCount; 447 } else { 448 lastPassIsBounds = true; 449 drawFace[passCount-1] = GrDrawState::kBoth_DrawFace; 450 if (reverse) { 451 passes[passCount-1] = &gInvWindColorPass; 452 } else { 453 passes[passCount-1] = &gWindColorPass; 454 } 455 } 456 break; 457 default: 458 SkDEBUGFAIL("Unknown path fFill!"); 459 return false; 460 } 461 } 462 } 463 464 SkRect devBounds; 465 GetPathDevBounds(path, drawState->getRenderTarget(), viewM, &devBounds); 466 467 for (int p = 0; p < passCount; ++p) { 468 drawState->setDrawFace(drawFace[p]); 469 if (passes[p]) { 470 *drawState->stencil() = *passes[p]; 471 } 472 473 if (lastPassIsBounds && (p == passCount-1)) { 474 if (!colorWritesWereDisabled) { 475 drawState->disableState(GrDrawState::kNoColorWrites_StateBit); 476 } 477 SkRect bounds; 478 GrDrawState::AutoViewMatrixRestore avmr; 479 if (reverse) { 480 SkASSERT(drawState->getRenderTarget()); 481 // draw over the dev bounds (which will be the whole dst surface for inv fill). 482 bounds = devBounds; 483 SkMatrix vmi; 484 // mapRect through persp matrix may not be correct 485 if (!drawState->getViewMatrix().hasPerspective() && 486 drawState->getViewInverse(&vmi)) { 487 vmi.mapRect(&bounds); 488 } else { 489 avmr.setIdentity(drawState); 490 } 491 } else { 492 bounds = path.getBounds(); 493 } 494 GrDrawTarget::AutoGeometryPush agp(target); 495 target->drawSimpleRect(drawState, color, bounds); 496 } else { 497 if (passCount > 1) { 498 drawState->enableState(GrDrawState::kNoColorWrites_StateBit); 499 } 500 GrDrawState::AutoRestoreEffects are(drawState); 501 drawState->setGeometryProcessor( 502 GrDefaultGeoProcFactory::Create(color, 503 GrDefaultGeoProcFactory::kPosition_GPType, 504 newCoverage))->unref(); 505 if (indexCnt) { 506 target->drawIndexed(drawState, 507 primType, 508 0, 509 0, 510 vertexCnt, 511 indexCnt, 512 &devBounds); 513 } else { 514 target->drawNonIndexed(drawState, primType, 0, vertexCnt, &devBounds); 515 } 516 } 517 } 518 return true; 519} 520 521bool GrDefaultPathRenderer::canDrawPath(const GrDrawTarget* target, 522 const GrDrawState* drawState, 523 const SkPath& path, 524 const SkStrokeRec& stroke, 525 bool antiAlias) const { 526 // this class can draw any path with any fill but doesn't do any anti-aliasing. 527 528 return !antiAlias && !(SkPath::kConic_SegmentMask & path.getSegmentMasks()) && 529 (stroke.isFillStyle() || 530 IsStrokeHairlineOrEquivalent(stroke, drawState->getViewMatrix(), NULL)); 531} 532 533bool GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target, 534 GrDrawState* drawState, 535 GrColor color, 536 const SkPath& path, 537 const SkStrokeRec& stroke, 538 bool antiAlias) { 539 return this->internalDrawPath(target, 540 drawState, 541 color, 542 path, 543 stroke, 544 false); 545} 546 547void GrDefaultPathRenderer::onStencilPath(GrDrawTarget* target, 548 GrDrawState* drawState, 549 const SkPath& path, 550 const SkStrokeRec& stroke) { 551 SkASSERT(SkPath::kInverseEvenOdd_FillType != path.getFillType()); 552 SkASSERT(SkPath::kInverseWinding_FillType != path.getFillType()); 553 this->internalDrawPath(target, drawState, GrColor_WHITE, path, stroke, true); 554} 555