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