1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/gpu/GrDefaultPathRenderer.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,539 @@ 1.4 +/* 1.5 + * Copyright 2011 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "GrDefaultPathRenderer.h" 1.12 + 1.13 +#include "GrContext.h" 1.14 +#include "GrDrawState.h" 1.15 +#include "GrPathUtils.h" 1.16 +#include "SkString.h" 1.17 +#include "SkStrokeRec.h" 1.18 +#include "SkTLazy.h" 1.19 +#include "SkTrace.h" 1.20 + 1.21 + 1.22 +GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport, 1.23 + bool stencilWrapOpsSupport) 1.24 + : fSeparateStencil(separateStencilSupport) 1.25 + , fStencilWrapOps(stencilWrapOpsSupport) { 1.26 +} 1.27 + 1.28 + 1.29 +//////////////////////////////////////////////////////////////////////////////// 1.30 +// Stencil rules for paths 1.31 + 1.32 +////// Even/Odd 1.33 + 1.34 +GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass, 1.35 + kInvert_StencilOp, 1.36 + kKeep_StencilOp, 1.37 + kAlwaysIfInClip_StencilFunc, 1.38 + 0xffff, 1.39 + 0xffff, 1.40 + 0xffff); 1.41 + 1.42 +// ok not to check clip b/c stencil pass only wrote inside clip 1.43 +GR_STATIC_CONST_SAME_STENCIL(gEOColorPass, 1.44 + kZero_StencilOp, 1.45 + kZero_StencilOp, 1.46 + kNotEqual_StencilFunc, 1.47 + 0xffff, 1.48 + 0x0000, 1.49 + 0xffff); 1.50 + 1.51 +// have to check clip b/c outside clip will always be zero. 1.52 +GR_STATIC_CONST_SAME_STENCIL(gInvEOColorPass, 1.53 + kZero_StencilOp, 1.54 + kZero_StencilOp, 1.55 + kEqualIfInClip_StencilFunc, 1.56 + 0xffff, 1.57 + 0x0000, 1.58 + 0xffff); 1.59 + 1.60 +////// Winding 1.61 + 1.62 +// when we have separate stencil we increment front faces / decrement back faces 1.63 +// when we don't have wrap incr and decr we use the stencil test to simulate 1.64 +// them. 1.65 + 1.66 +GR_STATIC_CONST_STENCIL(gWindStencilSeparateWithWrap, 1.67 + kIncWrap_StencilOp, kDecWrap_StencilOp, 1.68 + kKeep_StencilOp, kKeep_StencilOp, 1.69 + kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc, 1.70 + 0xffff, 0xffff, 1.71 + 0xffff, 0xffff, 1.72 + 0xffff, 0xffff); 1.73 + 1.74 +// if inc'ing the max value, invert to make 0 1.75 +// if dec'ing zero invert to make all ones. 1.76 +// we can't avoid touching the stencil on both passing and 1.77 +// failing, so we can't resctrict ourselves to the clip. 1.78 +GR_STATIC_CONST_STENCIL(gWindStencilSeparateNoWrap, 1.79 + kInvert_StencilOp, kInvert_StencilOp, 1.80 + kIncClamp_StencilOp, kDecClamp_StencilOp, 1.81 + kEqual_StencilFunc, kEqual_StencilFunc, 1.82 + 0xffff, 0xffff, 1.83 + 0xffff, 0x0000, 1.84 + 0xffff, 0xffff); 1.85 + 1.86 +// When there are no separate faces we do two passes to setup the winding rule 1.87 +// stencil. First we draw the front faces and inc, then we draw the back faces 1.88 +// and dec. These are same as the above two split into the incrementing and 1.89 +// decrementing passes. 1.90 +GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc, 1.91 + kIncWrap_StencilOp, 1.92 + kKeep_StencilOp, 1.93 + kAlwaysIfInClip_StencilFunc, 1.94 + 0xffff, 1.95 + 0xffff, 1.96 + 0xffff); 1.97 + 1.98 +GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec, 1.99 + kDecWrap_StencilOp, 1.100 + kKeep_StencilOp, 1.101 + kAlwaysIfInClip_StencilFunc, 1.102 + 0xffff, 1.103 + 0xffff, 1.104 + 0xffff); 1.105 + 1.106 +GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc, 1.107 + kInvert_StencilOp, 1.108 + kIncClamp_StencilOp, 1.109 + kEqual_StencilFunc, 1.110 + 0xffff, 1.111 + 0xffff, 1.112 + 0xffff); 1.113 + 1.114 +GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec, 1.115 + kInvert_StencilOp, 1.116 + kDecClamp_StencilOp, 1.117 + kEqual_StencilFunc, 1.118 + 0xffff, 1.119 + 0x0000, 1.120 + 0xffff); 1.121 + 1.122 +// Color passes are the same whether we use the two-sided stencil or two passes 1.123 + 1.124 +GR_STATIC_CONST_SAME_STENCIL(gWindColorPass, 1.125 + kZero_StencilOp, 1.126 + kZero_StencilOp, 1.127 + kNonZeroIfInClip_StencilFunc, 1.128 + 0xffff, 1.129 + 0x0000, 1.130 + 0xffff); 1.131 + 1.132 +GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass, 1.133 + kZero_StencilOp, 1.134 + kZero_StencilOp, 1.135 + kEqualIfInClip_StencilFunc, 1.136 + 0xffff, 1.137 + 0x0000, 1.138 + 0xffff); 1.139 + 1.140 +////// Normal render to stencil 1.141 + 1.142 +// Sometimes the default path renderer can draw a path directly to the stencil 1.143 +// buffer without having to first resolve the interior / exterior. 1.144 +GR_STATIC_CONST_SAME_STENCIL(gDirectToStencil, 1.145 + kZero_StencilOp, 1.146 + kIncClamp_StencilOp, 1.147 + kAlwaysIfInClip_StencilFunc, 1.148 + 0xffff, 1.149 + 0x0000, 1.150 + 0xffff); 1.151 + 1.152 +//////////////////////////////////////////////////////////////////////////////// 1.153 +// Helpers for drawPath 1.154 + 1.155 +#define STENCIL_OFF 0 // Always disable stencil (even when needed) 1.156 + 1.157 +static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& stroke) { 1.158 +#if STENCIL_OFF 1.159 + return true; 1.160 +#else 1.161 + if (!stroke.isHairlineStyle() && !path.isInverseFillType()) { 1.162 + return path.isConvex(); 1.163 + } 1.164 + return false; 1.165 +#endif 1.166 +} 1.167 + 1.168 +GrPathRenderer::StencilSupport GrDefaultPathRenderer::onGetStencilSupport( 1.169 + const SkPath& path, 1.170 + const SkStrokeRec& stroke, 1.171 + const GrDrawTarget*) const { 1.172 + if (single_pass_path(path, stroke)) { 1.173 + return GrPathRenderer::kNoRestriction_StencilSupport; 1.174 + } else { 1.175 + return GrPathRenderer::kStencilOnly_StencilSupport; 1.176 + } 1.177 +} 1.178 + 1.179 +static inline void append_countour_edge_indices(bool hairLine, 1.180 + uint16_t fanCenterIdx, 1.181 + uint16_t edgeV0Idx, 1.182 + uint16_t** indices) { 1.183 + // when drawing lines we're appending line segments along 1.184 + // the contour. When applying the other fill rules we're 1.185 + // drawing triangle fans around fanCenterIdx. 1.186 + if (!hairLine) { 1.187 + *((*indices)++) = fanCenterIdx; 1.188 + } 1.189 + *((*indices)++) = edgeV0Idx; 1.190 + *((*indices)++) = edgeV0Idx + 1; 1.191 +} 1.192 + 1.193 +bool GrDefaultPathRenderer::createGeom(const SkPath& path, 1.194 + const SkStrokeRec& stroke, 1.195 + SkScalar srcSpaceTol, 1.196 + GrDrawTarget* target, 1.197 + GrPrimitiveType* primType, 1.198 + int* vertexCnt, 1.199 + int* indexCnt, 1.200 + GrDrawTarget::AutoReleaseGeometry* arg) { 1.201 + { 1.202 + SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom"); 1.203 + 1.204 + SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol); 1.205 + int contourCnt; 1.206 + int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, 1.207 + srcSpaceTol); 1.208 + 1.209 + if (maxPts <= 0) { 1.210 + return false; 1.211 + } 1.212 + if (maxPts > ((int)SK_MaxU16 + 1)) { 1.213 + GrPrintf("Path not rendered, too many verts (%d)\n", maxPts); 1.214 + return false; 1.215 + } 1.216 + 1.217 + bool indexed = contourCnt > 1; 1.218 + 1.219 + const bool isHairline = stroke.isHairlineStyle(); 1.220 + 1.221 + int maxIdxs = 0; 1.222 + if (isHairline) { 1.223 + if (indexed) { 1.224 + maxIdxs = 2 * maxPts; 1.225 + *primType = kLines_GrPrimitiveType; 1.226 + } else { 1.227 + *primType = kLineStrip_GrPrimitiveType; 1.228 + } 1.229 + } else { 1.230 + if (indexed) { 1.231 + maxIdxs = 3 * maxPts; 1.232 + *primType = kTriangles_GrPrimitiveType; 1.233 + } else { 1.234 + *primType = kTriangleFan_GrPrimitiveType; 1.235 + } 1.236 + } 1.237 + 1.238 + target->drawState()->setDefaultVertexAttribs(); 1.239 + if (!arg->set(target, maxPts, maxIdxs)) { 1.240 + return false; 1.241 + } 1.242 + 1.243 + uint16_t* idxBase = reinterpret_cast<uint16_t*>(arg->indices()); 1.244 + uint16_t* idx = idxBase; 1.245 + uint16_t subpathIdxStart = 0; 1.246 + 1.247 + GrPoint* base = reinterpret_cast<GrPoint*>(arg->vertices()); 1.248 + SkASSERT(NULL != base); 1.249 + GrPoint* vert = base; 1.250 + 1.251 + GrPoint pts[4]; 1.252 + 1.253 + bool first = true; 1.254 + int subpath = 0; 1.255 + 1.256 + SkPath::Iter iter(path, false); 1.257 + 1.258 + for (;;) { 1.259 + SkPath::Verb verb = iter.next(pts); 1.260 + switch (verb) { 1.261 + case SkPath::kConic_Verb: 1.262 + SkASSERT(0); 1.263 + break; 1.264 + case SkPath::kMove_Verb: 1.265 + if (!first) { 1.266 + uint16_t currIdx = (uint16_t) (vert - base); 1.267 + subpathIdxStart = currIdx; 1.268 + ++subpath; 1.269 + } 1.270 + *vert = pts[0]; 1.271 + vert++; 1.272 + break; 1.273 + case SkPath::kLine_Verb: 1.274 + if (indexed) { 1.275 + uint16_t prevIdx = (uint16_t)(vert - base) - 1; 1.276 + append_countour_edge_indices(isHairline, subpathIdxStart, 1.277 + prevIdx, &idx); 1.278 + } 1.279 + *(vert++) = pts[1]; 1.280 + break; 1.281 + case SkPath::kQuad_Verb: { 1.282 + // first pt of quad is the pt we ended on in previous step 1.283 + uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1; 1.284 + uint16_t numPts = (uint16_t) 1.285 + GrPathUtils::generateQuadraticPoints( 1.286 + pts[0], pts[1], pts[2], 1.287 + srcSpaceTolSqd, &vert, 1.288 + GrPathUtils::quadraticPointCount(pts, srcSpaceTol)); 1.289 + if (indexed) { 1.290 + for (uint16_t i = 0; i < numPts; ++i) { 1.291 + append_countour_edge_indices(isHairline, subpathIdxStart, 1.292 + firstQPtIdx + i, &idx); 1.293 + } 1.294 + } 1.295 + break; 1.296 + } 1.297 + case SkPath::kCubic_Verb: { 1.298 + // first pt of cubic is the pt we ended on in previous step 1.299 + uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1; 1.300 + uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints( 1.301 + pts[0], pts[1], pts[2], pts[3], 1.302 + srcSpaceTolSqd, &vert, 1.303 + GrPathUtils::cubicPointCount(pts, srcSpaceTol)); 1.304 + if (indexed) { 1.305 + for (uint16_t i = 0; i < numPts; ++i) { 1.306 + append_countour_edge_indices(isHairline, subpathIdxStart, 1.307 + firstCPtIdx + i, &idx); 1.308 + } 1.309 + } 1.310 + break; 1.311 + } 1.312 + case SkPath::kClose_Verb: 1.313 + break; 1.314 + case SkPath::kDone_Verb: 1.315 + // uint16_t currIdx = (uint16_t) (vert - base); 1.316 + goto FINISHED; 1.317 + } 1.318 + first = false; 1.319 + } 1.320 +FINISHED: 1.321 + SkASSERT((vert - base) <= maxPts); 1.322 + SkASSERT((idx - idxBase) <= maxIdxs); 1.323 + 1.324 + *vertexCnt = static_cast<int>(vert - base); 1.325 + *indexCnt = static_cast<int>(idx - idxBase); 1.326 + 1.327 + } 1.328 + return true; 1.329 +} 1.330 + 1.331 +bool GrDefaultPathRenderer::internalDrawPath(const SkPath& path, 1.332 + const SkStrokeRec& origStroke, 1.333 + GrDrawTarget* target, 1.334 + bool stencilOnly) { 1.335 + 1.336 + SkMatrix viewM = target->getDrawState().getViewMatrix(); 1.337 + SkTCopyOnFirstWrite<SkStrokeRec> stroke(origStroke); 1.338 + 1.339 + SkScalar hairlineCoverage; 1.340 + if (IsStrokeHairlineOrEquivalent(*stroke, target->getDrawState().getViewMatrix(), 1.341 + &hairlineCoverage)) { 1.342 + uint8_t newCoverage = SkScalarRoundToInt(hairlineCoverage * 1.343 + target->getDrawState().getCoverage()); 1.344 + target->drawState()->setCoverage(newCoverage); 1.345 + 1.346 + if (!stroke->isHairlineStyle()) { 1.347 + stroke.writable()->setHairlineStyle(); 1.348 + } 1.349 + } 1.350 + 1.351 + SkScalar tol = SK_Scalar1; 1.352 + tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds()); 1.353 + 1.354 + int vertexCnt; 1.355 + int indexCnt; 1.356 + GrPrimitiveType primType; 1.357 + GrDrawTarget::AutoReleaseGeometry arg; 1.358 + if (!this->createGeom(path, 1.359 + *stroke, 1.360 + tol, 1.361 + target, 1.362 + &primType, 1.363 + &vertexCnt, 1.364 + &indexCnt, 1.365 + &arg)) { 1.366 + return false; 1.367 + } 1.368 + 1.369 + SkASSERT(NULL != target); 1.370 + GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit); 1.371 + GrDrawState* drawState = target->drawState(); 1.372 + bool colorWritesWereDisabled = drawState->isColorWriteDisabled(); 1.373 + // face culling doesn't make sense here 1.374 + SkASSERT(GrDrawState::kBoth_DrawFace == drawState->getDrawFace()); 1.375 + 1.376 + int passCount = 0; 1.377 + const GrStencilSettings* passes[3]; 1.378 + GrDrawState::DrawFace drawFace[3]; 1.379 + bool reverse = false; 1.380 + bool lastPassIsBounds; 1.381 + 1.382 + if (stroke->isHairlineStyle()) { 1.383 + passCount = 1; 1.384 + if (stencilOnly) { 1.385 + passes[0] = &gDirectToStencil; 1.386 + } else { 1.387 + passes[0] = NULL; 1.388 + } 1.389 + lastPassIsBounds = false; 1.390 + drawFace[0] = GrDrawState::kBoth_DrawFace; 1.391 + } else { 1.392 + if (single_pass_path(path, *stroke)) { 1.393 + passCount = 1; 1.394 + if (stencilOnly) { 1.395 + passes[0] = &gDirectToStencil; 1.396 + } else { 1.397 + passes[0] = NULL; 1.398 + } 1.399 + drawFace[0] = GrDrawState::kBoth_DrawFace; 1.400 + lastPassIsBounds = false; 1.401 + } else { 1.402 + switch (path.getFillType()) { 1.403 + case SkPath::kInverseEvenOdd_FillType: 1.404 + reverse = true; 1.405 + // fallthrough 1.406 + case SkPath::kEvenOdd_FillType: 1.407 + passes[0] = &gEOStencilPass; 1.408 + if (stencilOnly) { 1.409 + passCount = 1; 1.410 + lastPassIsBounds = false; 1.411 + } else { 1.412 + passCount = 2; 1.413 + lastPassIsBounds = true; 1.414 + if (reverse) { 1.415 + passes[1] = &gInvEOColorPass; 1.416 + } else { 1.417 + passes[1] = &gEOColorPass; 1.418 + } 1.419 + } 1.420 + drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace; 1.421 + break; 1.422 + 1.423 + case SkPath::kInverseWinding_FillType: 1.424 + reverse = true; 1.425 + // fallthrough 1.426 + case SkPath::kWinding_FillType: 1.427 + if (fSeparateStencil) { 1.428 + if (fStencilWrapOps) { 1.429 + passes[0] = &gWindStencilSeparateWithWrap; 1.430 + } else { 1.431 + passes[0] = &gWindStencilSeparateNoWrap; 1.432 + } 1.433 + passCount = 2; 1.434 + drawFace[0] = GrDrawState::kBoth_DrawFace; 1.435 + } else { 1.436 + if (fStencilWrapOps) { 1.437 + passes[0] = &gWindSingleStencilWithWrapInc; 1.438 + passes[1] = &gWindSingleStencilWithWrapDec; 1.439 + } else { 1.440 + passes[0] = &gWindSingleStencilNoWrapInc; 1.441 + passes[1] = &gWindSingleStencilNoWrapDec; 1.442 + } 1.443 + // which is cw and which is ccw is arbitrary. 1.444 + drawFace[0] = GrDrawState::kCW_DrawFace; 1.445 + drawFace[1] = GrDrawState::kCCW_DrawFace; 1.446 + passCount = 3; 1.447 + } 1.448 + if (stencilOnly) { 1.449 + lastPassIsBounds = false; 1.450 + --passCount; 1.451 + } else { 1.452 + lastPassIsBounds = true; 1.453 + drawFace[passCount-1] = GrDrawState::kBoth_DrawFace; 1.454 + if (reverse) { 1.455 + passes[passCount-1] = &gInvWindColorPass; 1.456 + } else { 1.457 + passes[passCount-1] = &gWindColorPass; 1.458 + } 1.459 + } 1.460 + break; 1.461 + default: 1.462 + SkDEBUGFAIL("Unknown path fFill!"); 1.463 + return false; 1.464 + } 1.465 + } 1.466 + } 1.467 + 1.468 + SkRect devBounds; 1.469 + GetPathDevBounds(path, drawState->getRenderTarget(), viewM, &devBounds); 1.470 + 1.471 + for (int p = 0; p < passCount; ++p) { 1.472 + drawState->setDrawFace(drawFace[p]); 1.473 + if (NULL != passes[p]) { 1.474 + *drawState->stencil() = *passes[p]; 1.475 + } 1.476 + 1.477 + if (lastPassIsBounds && (p == passCount-1)) { 1.478 + if (!colorWritesWereDisabled) { 1.479 + drawState->disableState(GrDrawState::kNoColorWrites_StateBit); 1.480 + } 1.481 + SkRect bounds; 1.482 + GrDrawState::AutoViewMatrixRestore avmr; 1.483 + if (reverse) { 1.484 + SkASSERT(NULL != drawState->getRenderTarget()); 1.485 + // draw over the dev bounds (which will be the whole dst surface for inv fill). 1.486 + bounds = devBounds; 1.487 + SkMatrix vmi; 1.488 + // mapRect through persp matrix may not be correct 1.489 + if (!drawState->getViewMatrix().hasPerspective() && 1.490 + drawState->getViewInverse(&vmi)) { 1.491 + vmi.mapRect(&bounds); 1.492 + } else { 1.493 + avmr.setIdentity(drawState); 1.494 + } 1.495 + } else { 1.496 + bounds = path.getBounds(); 1.497 + } 1.498 + GrDrawTarget::AutoGeometryAndStatePush agasp(target, GrDrawTarget::kPreserve_ASRInit); 1.499 + target->drawSimpleRect(bounds, NULL); 1.500 + } else { 1.501 + if (passCount > 1) { 1.502 + drawState->enableState(GrDrawState::kNoColorWrites_StateBit); 1.503 + } 1.504 + if (indexCnt) { 1.505 + target->drawIndexed(primType, 0, 0, 1.506 + vertexCnt, indexCnt, &devBounds); 1.507 + } else { 1.508 + target->drawNonIndexed(primType, 0, vertexCnt, &devBounds); 1.509 + } 1.510 + } 1.511 + } 1.512 + return true; 1.513 +} 1.514 + 1.515 +bool GrDefaultPathRenderer::canDrawPath(const SkPath& path, 1.516 + const SkStrokeRec& stroke, 1.517 + const GrDrawTarget* target, 1.518 + bool antiAlias) const { 1.519 + // this class can draw any path with any fill but doesn't do any anti-aliasing. 1.520 + 1.521 + return !antiAlias && 1.522 + (stroke.isFillStyle() || 1.523 + IsStrokeHairlineOrEquivalent(stroke, target->getDrawState().getViewMatrix(), NULL)); 1.524 +} 1.525 + 1.526 +bool GrDefaultPathRenderer::onDrawPath(const SkPath& path, 1.527 + const SkStrokeRec& stroke, 1.528 + GrDrawTarget* target, 1.529 + bool antiAlias) { 1.530 + return this->internalDrawPath(path, 1.531 + stroke, 1.532 + target, 1.533 + false); 1.534 +} 1.535 + 1.536 +void GrDefaultPathRenderer::onStencilPath(const SkPath& path, 1.537 + const SkStrokeRec& stroke, 1.538 + GrDrawTarget* target) { 1.539 + SkASSERT(SkPath::kInverseEvenOdd_FillType != path.getFillType()); 1.540 + SkASSERT(SkPath::kInverseWinding_FillType != path.getFillType()); 1.541 + this->internalDrawPath(path, stroke, target, true); 1.542 +}