1
2 /*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9 #include "GrDefaultPathRenderer.h"
10
11 #include "GrContext.h"
12 #include "GrDrawState.h"
13 #include "GrPathUtils.h"
14 #include "SkString.h"
15 #include "SkTrace.h"
16
17
GrDefaultPathRenderer(bool separateStencilSupport,bool stencilWrapOpsSupport)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
single_pass_path(const GrPath & path,GrPathFill fill)153 static inline bool single_pass_path(const GrPath& path, GrPathFill fill) {
154 #if STENCIL_OFF
155 return true;
156 #else
157 if (kEvenOdd_PathFill == fill || kWinding_PathFill == fill) {
158 return path.isConvex();
159 }
160 return false;
161 #endif
162 }
163
requiresStencilPass(const SkPath & path,GrPathFill fill,const GrDrawTarget * target) const164 bool GrDefaultPathRenderer::requiresStencilPass(const SkPath& path,
165 GrPathFill fill,
166 const GrDrawTarget* target) const {
167 return !single_pass_path(path, fill);
168 }
169
append_countour_edge_indices(GrPathFill fillType,uint16_t fanCenterIdx,uint16_t edgeV0Idx,uint16_t ** indices)170 static inline void append_countour_edge_indices(GrPathFill fillType,
171 uint16_t fanCenterIdx,
172 uint16_t edgeV0Idx,
173 uint16_t** indices) {
174 // when drawing lines we're appending line segments along
175 // the contour. When applying the other fill rules we're
176 // drawing triangle fans around fanCenterIdx.
177 if (kHairLine_PathFill != fillType) {
178 *((*indices)++) = fanCenterIdx;
179 }
180 *((*indices)++) = edgeV0Idx;
181 *((*indices)++) = edgeV0Idx + 1;
182 }
183
createGeom(const SkPath & path,GrPathFill fill,const GrVec * translate,GrScalar srcSpaceTol,GrDrawTarget * target,GrDrawState::StageMask stageMask,GrPrimitiveType * primType,int * vertexCnt,int * indexCnt)184 bool GrDefaultPathRenderer::createGeom(const SkPath& path,
185 GrPathFill fill,
186 const GrVec* translate,
187 GrScalar srcSpaceTol,
188 GrDrawTarget* target,
189 GrDrawState::StageMask stageMask,
190 GrPrimitiveType* primType,
191 int* vertexCnt,
192 int* indexCnt) {
193 {
194 SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
195
196 GrScalar srcSpaceTolSqd = GrMul(srcSpaceTol, srcSpaceTol);
197 int contourCnt;
198 int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt,
199 srcSpaceTol);
200
201 if (maxPts <= 0) {
202 return false;
203 }
204 if (maxPts > ((int)SK_MaxU16 + 1)) {
205 GrPrintf("Path not rendered, too many verts (%d)\n", maxPts);
206 return false;
207 }
208
209 GrVertexLayout layout = 0;
210 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
211 if ((1 << s) & stageMask) {
212 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
213 }
214 }
215
216 bool indexed = contourCnt > 1;
217
218 int maxIdxs = 0;
219 if (kHairLine_PathFill == fill) {
220 if (indexed) {
221 maxIdxs = 2 * maxPts;
222 *primType = kLines_PrimitiveType;
223 } else {
224 *primType = kLineStrip_PrimitiveType;
225 }
226 } else {
227 if (indexed) {
228 maxIdxs = 3 * maxPts;
229 *primType = kTriangles_PrimitiveType;
230 } else {
231 *primType = kTriangleFan_PrimitiveType;
232 }
233 }
234
235 GrPoint* base;
236 if (!target->reserveVertexSpace(layout, maxPts, (void**)&base)) {
237 return false;
238 }
239 GrAssert(NULL != base);
240 GrPoint* vert = base;
241
242 uint16_t* idxBase = NULL;
243 uint16_t* idx = NULL;
244 uint16_t subpathIdxStart = 0;
245 if (indexed) {
246 if (!target->reserveIndexSpace(maxIdxs, (void**)&idxBase)) {
247 target->resetVertexSource();
248 return false;
249 }
250 GrAssert(NULL != idxBase);
251 idx = idxBase;
252 }
253
254 GrPoint pts[4];
255
256 bool first = true;
257 int subpath = 0;
258
259 SkPath::Iter iter(path, false);
260
261 for (;;) {
262 GrPathCmd cmd = (GrPathCmd)iter.next(pts);
263 switch (cmd) {
264 case kMove_PathCmd:
265 if (!first) {
266 uint16_t currIdx = (uint16_t) (vert - base);
267 subpathIdxStart = currIdx;
268 ++subpath;
269 }
270 *vert = pts[0];
271 vert++;
272 break;
273 case kLine_PathCmd:
274 if (indexed) {
275 uint16_t prevIdx = (uint16_t)(vert - base) - 1;
276 append_countour_edge_indices(fill, subpathIdxStart,
277 prevIdx, &idx);
278 }
279 *(vert++) = pts[1];
280 break;
281 case kQuadratic_PathCmd: {
282 // first pt of quad is the pt we ended on in previous step
283 uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
284 uint16_t numPts = (uint16_t)
285 GrPathUtils::generateQuadraticPoints(
286 pts[0], pts[1], pts[2],
287 srcSpaceTolSqd, &vert,
288 GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
289 if (indexed) {
290 for (uint16_t i = 0; i < numPts; ++i) {
291 append_countour_edge_indices(fill, subpathIdxStart,
292 firstQPtIdx + i, &idx);
293 }
294 }
295 break;
296 }
297 case kCubic_PathCmd: {
298 // first pt of cubic is the pt we ended on in previous step
299 uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
300 uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
301 pts[0], pts[1], pts[2], pts[3],
302 srcSpaceTolSqd, &vert,
303 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
304 if (indexed) {
305 for (uint16_t i = 0; i < numPts; ++i) {
306 append_countour_edge_indices(fill, subpathIdxStart,
307 firstCPtIdx + i, &idx);
308 }
309 }
310 break;
311 }
312 case kClose_PathCmd:
313 break;
314 case kEnd_PathCmd:
315 uint16_t currIdx = (uint16_t) (vert - base);
316 goto FINISHED;
317 }
318 first = false;
319 }
320 FINISHED:
321 GrAssert((vert - base) <= maxPts);
322 GrAssert((idx - idxBase) <= maxIdxs);
323
324 *vertexCnt = vert - base;
325 *indexCnt = idx - idxBase;
326
327 if (NULL != translate &&
328 (translate->fX || translate->fY)) {
329 int count = vert - base;
330 for (int i = 0; i < count; i++) {
331 base[i].offset(translate->fX, translate->fY);
332 }
333 }
334 }
335 return true;
336 }
337
internalDrawPath(const SkPath & path,GrPathFill fill,const GrVec * translate,GrDrawTarget * target,GrDrawState::StageMask stageMask,bool stencilOnly)338 bool GrDefaultPathRenderer::internalDrawPath(const SkPath& path,
339 GrPathFill fill,
340 const GrVec* translate,
341 GrDrawTarget* target,
342 GrDrawState::StageMask stageMask,
343 bool stencilOnly) {
344
345 GrMatrix viewM = target->getDrawState().getViewMatrix();
346 GrScalar tol = GR_Scalar1;
347 tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds());
348 GrDrawState* drawState = target->drawState();
349
350 int vertexCnt;
351 int indexCnt;
352 GrPrimitiveType primType;
353 if (!this->createGeom(path,
354 fill,
355 translate,
356 tol,
357 target,
358 stageMask,
359 &primType,
360 &vertexCnt,
361 &indexCnt)) {
362 return false;
363 }
364
365 GrAssert(NULL != target);
366 GrDrawTarget::AutoStateRestore asr(target);
367 bool colorWritesWereDisabled = drawState->isColorWriteDisabled();
368 // face culling doesn't make sense here
369 GrAssert(GrDrawState::kBoth_DrawFace == drawState->getDrawFace());
370
371 int passCount = 0;
372 const GrStencilSettings* passes[3];
373 GrDrawState::DrawFace drawFace[3];
374 bool reverse = false;
375 bool lastPassIsBounds;
376
377 if (kHairLine_PathFill == fill) {
378 passCount = 1;
379 if (stencilOnly) {
380 passes[0] = &gDirectToStencil;
381 } else {
382 passes[0] = NULL;
383 }
384 lastPassIsBounds = false;
385 drawFace[0] = GrDrawState::kBoth_DrawFace;
386 } else {
387 if (single_pass_path(path, fill)) {
388 passCount = 1;
389 if (stencilOnly) {
390 passes[0] = &gDirectToStencil;
391 } else {
392 passes[0] = NULL;
393 }
394 drawFace[0] = GrDrawState::kBoth_DrawFace;
395 lastPassIsBounds = false;
396 } else {
397 switch (fill) {
398 case kInverseEvenOdd_PathFill:
399 reverse = true;
400 // fallthrough
401 case kEvenOdd_PathFill:
402 passes[0] = &gEOStencilPass;
403 if (stencilOnly) {
404 passCount = 1;
405 lastPassIsBounds = false;
406 } else {
407 passCount = 2;
408 lastPassIsBounds = true;
409 if (reverse) {
410 passes[1] = &gInvEOColorPass;
411 } else {
412 passes[1] = &gEOColorPass;
413 }
414 }
415 drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace;
416 break;
417
418 case kInverseWinding_PathFill:
419 reverse = true;
420 // fallthrough
421 case kWinding_PathFill:
422 if (fSeparateStencil) {
423 if (fStencilWrapOps) {
424 passes[0] = &gWindStencilSeparateWithWrap;
425 } else {
426 passes[0] = &gWindStencilSeparateNoWrap;
427 }
428 passCount = 2;
429 drawFace[0] = GrDrawState::kBoth_DrawFace;
430 } else {
431 if (fStencilWrapOps) {
432 passes[0] = &gWindSingleStencilWithWrapInc;
433 passes[1] = &gWindSingleStencilWithWrapDec;
434 } else {
435 passes[0] = &gWindSingleStencilNoWrapInc;
436 passes[1] = &gWindSingleStencilNoWrapDec;
437 }
438 // which is cw and which is ccw is arbitrary.
439 drawFace[0] = GrDrawState::kCW_DrawFace;
440 drawFace[1] = GrDrawState::kCCW_DrawFace;
441 passCount = 3;
442 }
443 if (stencilOnly) {
444 lastPassIsBounds = false;
445 --passCount;
446 } else {
447 lastPassIsBounds = true;
448 drawFace[passCount-1] = GrDrawState::kBoth_DrawFace;
449 if (reverse) {
450 passes[passCount-1] = &gInvWindColorPass;
451 } else {
452 passes[passCount-1] = &gWindColorPass;
453 }
454 }
455 break;
456 default:
457 GrAssert(!"Unknown path fFill!");
458 return false;
459 }
460 }
461 }
462
463 {
464 for (int p = 0; p < passCount; ++p) {
465 drawState->setDrawFace(drawFace[p]);
466 if (NULL != passes[p]) {
467 *drawState->stencil() = *passes[p];
468 }
469
470 if (lastPassIsBounds && (p == passCount-1)) {
471 if (!colorWritesWereDisabled) {
472 drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
473 }
474 GrRect bounds;
475 if (reverse) {
476 GrAssert(NULL != drawState->getRenderTarget());
477 // draw over the whole world.
478 bounds.setLTRB(0, 0,
479 GrIntToScalar(drawState->getRenderTarget()->width()),
480 GrIntToScalar(drawState->getRenderTarget()->height()));
481 GrMatrix vmi;
482 // mapRect through persp matrix may not be correct
483 if (!drawState->getViewMatrix().hasPerspective() &&
484 drawState->getViewInverse(&vmi)) {
485 vmi.mapRect(&bounds);
486 } else {
487 if (stageMask) {
488 if (!drawState->getViewInverse(&vmi)) {
489 GrPrintf("Could not invert matrix.");
490 return false;
491 }
492 drawState->preConcatSamplerMatrices(stageMask, vmi);
493 }
494 drawState->setViewMatrix(GrMatrix::I());
495 }
496 } else {
497 bounds = path.getBounds();
498 if (NULL != translate) {
499 bounds.offset(*translate);
500 }
501 }
502 GrDrawTarget::AutoGeometryPush agp(target);
503 target->drawSimpleRect(bounds, NULL, stageMask);
504 } else {
505 if (passCount > 1) {
506 drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
507 }
508 if (indexCnt) {
509 target->drawIndexed(primType, 0, 0,
510 vertexCnt, indexCnt);
511 } else {
512 target->drawNonIndexed(primType, 0, vertexCnt);
513 }
514 }
515 }
516 }
517 return true;
518 }
519
canDrawPath(const SkPath & path,GrPathFill fill,const GrDrawTarget * target,bool antiAlias) const520 bool GrDefaultPathRenderer::canDrawPath(const SkPath& path,
521 GrPathFill fill,
522 const GrDrawTarget* target,
523 bool antiAlias) const {
524 // this class can draw any path with any fill but doesn't do any
525 // anti-aliasing.
526 return !antiAlias;
527 }
528
onDrawPath(const SkPath & path,GrPathFill fill,const GrVec * translate,GrDrawTarget * target,GrDrawState::StageMask stageMask,bool antiAlias)529 bool GrDefaultPathRenderer::onDrawPath(const SkPath& path,
530 GrPathFill fill,
531 const GrVec* translate,
532 GrDrawTarget* target,
533 GrDrawState::StageMask stageMask,
534 bool antiAlias) {
535 return this->internalDrawPath(path,
536 fill,
537 translate,
538 target,
539 stageMask,
540 false);
541 }
542
drawPathToStencil(const SkPath & path,GrPathFill fill,GrDrawTarget * target)543 void GrDefaultPathRenderer::drawPathToStencil(const SkPath& path,
544 GrPathFill fill,
545 GrDrawTarget* target) {
546 GrAssert(kInverseEvenOdd_PathFill != fill);
547 GrAssert(kInverseWinding_PathFill != fill);
548 this->internalDrawPath(path, fill, NULL, target, 0, true);
549 }
550