blob: 0f28fa92ccb078279d3cb146dab2022c391cfbcf [file] [log] [blame]
bsalomon@google.comffca4002011-02-22 20:34:01 +00001#include "GrPathRenderer.h"
2
3#include "GrPoint.h"
4#include "GrDrawTarget.h"
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +00005#include "GrPathUtils.h"
bsalomon@google.comffca4002011-02-22 20:34:01 +00006#include "GrTexture.h"
7
tomhudson@google.com278cbb42011-06-30 19:37:01 +00008#include "SkString.h"
bsalomon@google.com3582bf92011-06-30 21:32:31 +00009#include "SkTemplates.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000010#include "SkTrace.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000011
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000012GrPathRenderer::GrPathRenderer()
bsalomon@google.comee435122011-07-01 14:57:55 +000013 : fCurveTolerance (GR_Scalar1)
14 , fPath(NULL)
15 , fTarget(NULL) {
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000016}
bsalomon@google.comee435122011-07-01 14:57:55 +000017
18
19void GrPathRenderer::setPath(GrDrawTarget* target,
20 const SkPath* path,
21 GrPathFill fill,
22 const GrPoint* translate) {
23 GrAssert(NULL == fPath);
24 GrAssert(NULL == fTarget);
25 GrAssert(NULL != target);
26
27 fTarget = target;
28 fPath = path;
29 fFill = fill;
30 if (NULL != translate) {
31 fTranslate = *translate;
32 } else {
33 fTranslate.fX = fTranslate.fY = 0;
34 }
35 this->pathWasSet();
36}
37
38void GrPathRenderer::clearPath() {
39 this->pathWillClear();
40 fTarget->resetVertexSource();
bsalomon@google.com25fd36c2011-07-06 17:41:08 +000041 fTarget->resetIndexSource();
bsalomon@google.comee435122011-07-01 14:57:55 +000042 fTarget = NULL;
43 fPath = NULL;
44}
45
46////////////////////////////////////////////////////////////////////////////////
47
bsalomon@google.comd302f142011-03-03 13:54:13 +000048GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
49 bool stencilWrapOpsSupport)
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000050 : fSeparateStencil(separateStencilSupport)
bsalomon@google.comee435122011-07-01 14:57:55 +000051 , fStencilWrapOps(stencilWrapOpsSupport)
52 , fSubpathCount(0)
53 , fSubpathVertCount(0)
54 , fPreviousSrcTol(-GR_Scalar1)
55 , fPreviousStages(-1) {
56 fTarget = NULL;
bsalomon@google.comffca4002011-02-22 20:34:01 +000057}
58
59////////////////////////////////////////////////////////////////////////////////
bsalomon@google.comd302f142011-03-03 13:54:13 +000060// Stencil rules for paths
61
62////// Even/Odd
63
64static const GrStencilSettings gEOStencilPass = {
65 kInvert_StencilOp, kInvert_StencilOp,
66 kKeep_StencilOp, kKeep_StencilOp,
67 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
68 0xffffffff, 0xffffffff,
69 0xffffffff, 0xffffffff,
70 0xffffffff, 0xffffffff
71};
72
73// ok not to check clip b/c stencil pass only wrote inside clip
74static const GrStencilSettings gEOColorPass = {
75 kZero_StencilOp, kZero_StencilOp,
76 kZero_StencilOp, kZero_StencilOp,
77 kNotEqual_StencilFunc, kNotEqual_StencilFunc,
78 0xffffffff, 0xffffffff,
79 0x0, 0x0,
80 0xffffffff, 0xffffffff
81};
82
83// have to check clip b/c outside clip will always be zero.
84static const GrStencilSettings gInvEOColorPass = {
85 kZero_StencilOp, kZero_StencilOp,
86 kZero_StencilOp, kZero_StencilOp,
87 kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
88 0xffffffff, 0xffffffff,
89 0x0, 0x0,
90 0xffffffff, 0xffffffff
91};
92
93////// Winding
94
95// when we have separate stencil we increment front faces / decrement back faces
96// when we don't have wrap incr and decr we use the stencil test to simulate
97// them.
98
99static const GrStencilSettings gWindStencilSeparateWithWrap = {
100 kIncWrap_StencilOp, kDecWrap_StencilOp,
101 kKeep_StencilOp, kKeep_StencilOp,
102 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
103 0xffffffff, 0xffffffff,
104 0xffffffff, 0xffffffff,
105 0xffffffff, 0xffffffff
106};
107
108// if inc'ing the max value, invert to make 0
109// if dec'ing zero invert to make all ones.
110// we can't avoid touching the stencil on both passing and
111// failing, so we can't resctrict ourselves to the clip.
112static const GrStencilSettings gWindStencilSeparateNoWrap = {
113 kInvert_StencilOp, kInvert_StencilOp,
114 kIncClamp_StencilOp, kDecClamp_StencilOp,
115 kEqual_StencilFunc, kEqual_StencilFunc,
116 0xffffffff, 0xffffffff,
117 0xffffffff, 0x0,
118 0xffffffff, 0xffffffff
119};
120
121// When there are no separate faces we do two passes to setup the winding rule
122// stencil. First we draw the front faces and inc, then we draw the back faces
123// and dec. These are same as the above two split into the incrementing and
124// decrementing passes.
125static const GrStencilSettings gWindSingleStencilWithWrapInc = {
126 kIncWrap_StencilOp, kIncWrap_StencilOp,
127 kKeep_StencilOp, kKeep_StencilOp,
128 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
129 0xffffffff, 0xffffffff,
130 0xffffffff, 0xffffffff,
131 0xffffffff, 0xffffffff
132};
133static const GrStencilSettings gWindSingleStencilWithWrapDec = {
134 kDecWrap_StencilOp, kDecWrap_StencilOp,
135 kKeep_StencilOp, kKeep_StencilOp,
136 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
137 0xffffffff, 0xffffffff,
138 0xffffffff, 0xffffffff,
139 0xffffffff, 0xffffffff
140};
141static const GrStencilSettings gWindSingleStencilNoWrapInc = {
142 kInvert_StencilOp, kInvert_StencilOp,
143 kIncClamp_StencilOp, kIncClamp_StencilOp,
144 kEqual_StencilFunc, kEqual_StencilFunc,
145 0xffffffff, 0xffffffff,
146 0xffffffff, 0xffffffff,
147 0xffffffff, 0xffffffff
148};
149static const GrStencilSettings gWindSingleStencilNoWrapDec = {
150 kInvert_StencilOp, kInvert_StencilOp,
151 kDecClamp_StencilOp, kDecClamp_StencilOp,
152 kEqual_StencilFunc, kEqual_StencilFunc,
153 0xffffffff, 0xffffffff,
154 0x0, 0x0,
155 0xffffffff, 0xffffffff
156};
157
158static const GrStencilSettings gWindColorPass = {
159 kZero_StencilOp, kZero_StencilOp,
160 kZero_StencilOp, kZero_StencilOp,
161 kNonZeroIfInClip_StencilFunc, kNonZeroIfInClip_StencilFunc,
162 0xffffffff, 0xffffffff,
163 0x0, 0x0,
164 0xffffffff, 0xffffffff
165};
166
167static const GrStencilSettings gInvWindColorPass = {
168 kZero_StencilOp, kZero_StencilOp,
169 kZero_StencilOp, kZero_StencilOp,
170 kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
171 0xffffffff, 0xffffffff,
172 0x0, 0x0,
173 0xffffffff, 0xffffffff
174};
175
176////// Normal render to stencil
177
178// Sometimes the default path renderer can draw a path directly to the stencil
179// buffer without having to first resolve the interior / exterior.
180static const GrStencilSettings gDirectToStencil = {
181 kZero_StencilOp, kZero_StencilOp,
182 kIncClamp_StencilOp, kIncClamp_StencilOp,
183 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
184 0xffffffff, 0xffffffff,
185 0x0, 0x0,
186 0xffffffff, 0xffffffff
187};
188
189////////////////////////////////////////////////////////////////////////////////
190// Helpers for drawPath
bsalomon@google.comffca4002011-02-22 20:34:01 +0000191
reed@google.com07f3ee12011-05-16 17:21:57 +0000192static GrConvexHint getConvexHint(const SkPath& path) {
193 return path.isConvex() ? kConvex_ConvexHint : kConcave_ConvexHint;
194}
195
bsalomon@google.comffca4002011-02-22 20:34:01 +0000196#define STENCIL_OFF 0 // Always disable stencil (even when needed)
bsalomon@google.comffca4002011-02-22 20:34:01 +0000197
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000198static inline bool single_pass_path(const GrDrawTarget& target,
reed@google.com07f3ee12011-05-16 17:21:57 +0000199 const GrPath& path,
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000200 GrPathFill fill) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000201#if STENCIL_OFF
202 return true;
203#else
204 if (kEvenOdd_PathFill == fill) {
reed@google.com07f3ee12011-05-16 17:21:57 +0000205 GrConvexHint hint = getConvexHint(path);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000206 return hint == kConvex_ConvexHint ||
207 hint == kNonOverlappingConvexPieces_ConvexHint;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000208 } else if (kWinding_PathFill == fill) {
reed@google.com07f3ee12011-05-16 17:21:57 +0000209 GrConvexHint hint = getConvexHint(path);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000210 return hint == kConvex_ConvexHint ||
211 hint == kNonOverlappingConvexPieces_ConvexHint ||
212 (hint == kSameWindingConvexPieces_ConvexHint &&
bsalomon@google.comffca4002011-02-22 20:34:01 +0000213 target.canDisableBlend() && !target.isDitherState());
214
215 }
216 return false;
217#endif
218}
219
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000220bool GrDefaultPathRenderer::requiresStencilPass(const GrDrawTarget* target,
reed@google.com07f3ee12011-05-16 17:21:57 +0000221 const GrPath& path,
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000222 GrPathFill fill) const {
reed@google.com07f3ee12011-05-16 17:21:57 +0000223 return !single_pass_path(*target, path, fill);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000224}
225
bsalomon@google.comee435122011-07-01 14:57:55 +0000226void GrDefaultPathRenderer::pathWillClear() {
227 fSubpathVertCount.realloc(0);
228 fTarget->resetVertexSource();
229 fPreviousSrcTol = -GR_Scalar1;
230 fPreviousStages = -1;
231}
232
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000233static inline void append_countour_edge_indices(GrPathFill fillType,
234 uint16_t fanCenterIdx,
235 uint16_t edgeV0Idx,
236 uint16_t** indices) {
237 // when drawing lines we're appending line segments along
238 // the contour. When applying the other fill rules we're
239 // drawing triangle fans around fanCenterIdx.
240 if (kHairLine_PathFill != fillType) {
241 *((*indices)++) = fanCenterIdx;
242 }
243 *((*indices)++) = edgeV0Idx;
244 *((*indices)++) = edgeV0Idx + 1;
245}
246
247bool GrDefaultPathRenderer::createGeom(GrScalar srcSpaceTol,
bsalomon@google.comee435122011-07-01 14:57:55 +0000248 GrDrawTarget::StageBitfield stages) {
249 {
250 SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
251
bsalomon@google.comee435122011-07-01 14:57:55 +0000252 GrScalar srcSpaceTolSqd = GrMul(srcSpaceTol, srcSpaceTol);
253 int maxPts = GrPathUtils::worstCasePointCount(*fPath, &fSubpathCount,
254 srcSpaceTol);
255
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000256 if (maxPts <= 0) {
257 return false;
258 }
259 if (maxPts > ((int)SK_MaxU16 + 1)) {
260 GrPrintf("Path not rendered, too many verts (%d)\n", maxPts);
261 return false;
262 }
263
264 fPreviousSrcTol = srcSpaceTol;
265 fPreviousStages = stages;
266
bsalomon@google.comee435122011-07-01 14:57:55 +0000267 GrVertexLayout layout = 0;
268 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
269 if ((1 << s) & stages) {
270 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
271 }
272 }
273
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000274 fUseIndexedDraw = fSubpathCount > 1;
bsalomon@google.comee435122011-07-01 14:57:55 +0000275
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000276 int maxIdxs = 0;
277 if (kHairLine_PathFill == fFill) {
278 if (fUseIndexedDraw) {
279 maxIdxs = 2 * maxPts;
280 fPrimitiveType = kLines_PrimitiveType;
281 } else {
282 fPrimitiveType = kLineStrip_PrimitiveType;
283 }
284 } else {
285 if (fUseIndexedDraw) {
286 maxIdxs = 3 * maxPts;
287 fPrimitiveType = kTriangles_PrimitiveType;
288 } else {
289 fPrimitiveType = kTriangleFan_PrimitiveType;
290 }
291 }
292
293 GrPoint* base;
294 fTarget->reserveVertexSpace(layout, maxPts, (void**)&base);
bsalomon@google.comee435122011-07-01 14:57:55 +0000295 GrPoint* vert = base;
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000296
297 uint16_t* idxBase = NULL;
298 uint16_t* idx = NULL;
299 uint16_t subpathIdxStart = 0;
300 if (fUseIndexedDraw) {
301 fTarget->reserveIndexSpace(maxIdxs, (void**)&idxBase);
302 idx = idxBase;
303 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000304
305 fSubpathVertCount.realloc(fSubpathCount);
306
307 GrPoint pts[4];
308
309 bool first = true;
310 int subpath = 0;
311
312 SkPath::Iter iter(*fPath, false);
313
314 for (;;) {
315 GrPathCmd cmd = (GrPathCmd)iter.next(pts);
316 switch (cmd) {
317 case kMove_PathCmd:
318 if (!first) {
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000319 uint16_t currIdx = (uint16_t) (vert - base);
320 fSubpathVertCount[subpath] = currIdx - subpathIdxStart;
321 subpathIdxStart = currIdx;
bsalomon@google.comee435122011-07-01 14:57:55 +0000322 ++subpath;
323 }
324 *vert = pts[0];
325 vert++;
326 break;
327 case kLine_PathCmd:
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000328 if (fUseIndexedDraw) {
329 uint16_t prevIdx = (uint16_t)(vert - base) - 1;
330 append_countour_edge_indices(fFill, subpathIdxStart,
331 prevIdx, &idx);
332 }
333 *(vert++) = pts[1];
bsalomon@google.comee435122011-07-01 14:57:55 +0000334 break;
335 case kQuadratic_PathCmd: {
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000336 // first pt of quad is the pt we ended on in previous step
337 uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
338 uint16_t numPts = (uint16_t)
339 GrPathUtils::generateQuadraticPoints(
340 pts[0], pts[1], pts[2],
341 srcSpaceTolSqd, &vert,
342 GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
343 if (fUseIndexedDraw) {
344 for (uint16_t i = 0; i < numPts; ++i) {
345 append_countour_edge_indices(fFill, subpathIdxStart,
346 firstQPtIdx + i, &idx);
347 }
348 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000349 break;
350 }
351 case kCubic_PathCmd: {
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000352 // first pt of cubic is the pt we ended on in previous step
353 uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
354 uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
355 pts[0], pts[1], pts[2], pts[3],
356 srcSpaceTolSqd, &vert,
357 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
358 if (fUseIndexedDraw) {
359 for (uint16_t i = 0; i < numPts; ++i) {
360 append_countour_edge_indices(fFill, subpathIdxStart,
361 firstCPtIdx + i, &idx);
362 }
363 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000364 break;
365 }
366 case kClose_PathCmd:
367 break;
368 case kEnd_PathCmd:
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000369 uint16_t currIdx = (uint16_t) (vert - base);
370 fSubpathVertCount[subpath] = currIdx - subpathIdxStart;
bsalomon@google.comee435122011-07-01 14:57:55 +0000371 goto FINISHED;
372 }
373 first = false;
374 }
375FINISHED:
bsalomon@google.comee435122011-07-01 14:57:55 +0000376 GrAssert((vert - base) <= maxPts);
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000377 GrAssert((idx - idxBase) <= maxIdxs);
378
379 fVertexCnt = vert - base;
380 fIndexCnt = idx - idxBase;
bsalomon@google.comee435122011-07-01 14:57:55 +0000381
382 if (fTranslate.fX || fTranslate.fY) {
383 int count = vert - base;
384 for (int i = 0; i < count; i++) {
385 base[i].offset(fTranslate.fX, fTranslate.fY);
386 }
387 }
388 }
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000389 return true;
bsalomon@google.comee435122011-07-01 14:57:55 +0000390}
391
392void GrDefaultPathRenderer::onDrawPath(GrDrawTarget::StageBitfield stages,
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000393 bool stencilOnly) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000394
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000395 SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath",
396 "points", SkStringPrintf("%i", path.countPoints()).c_str());
bsalomon@google.comffca4002011-02-22 20:34:01 +0000397
bsalomon@google.comee435122011-07-01 14:57:55 +0000398 GrMatrix viewM = fTarget->getViewMatrix();
bsalomon@google.comffca4002011-02-22 20:34:01 +0000399 // In order to tesselate the path we get a bound on how much the matrix can
400 // stretch when mapping to screen coordinates.
401 GrScalar stretch = viewM.getMaxStretch();
402 bool useStretch = stretch > 0;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000403 GrScalar tol = fCurveTolerance;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000404
405 if (!useStretch) {
406 // TODO: deal with perspective in some better way.
407 tol /= 10;
408 } else {
bungeman@google.com8c5753e2011-05-20 19:11:50 +0000409 tol = GrScalarDiv(tol, stretch);
bsalomon@google.comffca4002011-02-22 20:34:01 +0000410 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000411 // FIXME: It's really dumb that we recreate the verts for a new vertex
412 // layout. We only do that because the GrDrawTarget API doesn't allow
413 // us to change the vertex layout after reserveVertexSpace(). We won't
414 // actually change the vertex data when the layout changes since all the
415 // stages reference the positions (rather than having separate tex coords)
416 // and we don't ever have per-vert colors. In practice our call sites
417 // won't change the stages in use inside a setPath / removePath pair. But
418 // it is a silly limitation of the GrDrawTarget design that should be fixed.
419 if (tol != fPreviousSrcTol ||
420 stages != fPreviousStages) {
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000421 if (!this->createGeom(tol, stages)) {
422 return;
423 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000424 }
425
bsalomon@google.comee435122011-07-01 14:57:55 +0000426 GrAssert(NULL != fTarget);
427 GrDrawTarget::AutoStateRestore asr(fTarget);
428 bool colorWritesWereDisabled = fTarget->isColorWriteDisabled();
429 // face culling doesn't make sense here
430 GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace());
bsalomon@google.comffca4002011-02-22 20:34:01 +0000431
bsalomon@google.comffca4002011-02-22 20:34:01 +0000432 int passCount = 0;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000433 const GrStencilSettings* passes[3];
434 GrDrawTarget::DrawFace drawFace[3];
bsalomon@google.comffca4002011-02-22 20:34:01 +0000435 bool reverse = false;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000436 bool lastPassIsBounds;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000437
bsalomon@google.comee435122011-07-01 14:57:55 +0000438 if (kHairLine_PathFill == fFill) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000439 passCount = 1;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000440 if (stencilOnly) {
441 passes[0] = &gDirectToStencil;
442 } else {
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000443 passes[0] = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000444 }
445 lastPassIsBounds = false;
446 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000447 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +0000448 if (single_pass_path(*fTarget, *fPath, fFill)) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000449 passCount = 1;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000450 if (stencilOnly) {
451 passes[0] = &gDirectToStencil;
452 } else {
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000453 passes[0] = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000454 }
455 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
456 lastPassIsBounds = false;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000457 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +0000458 switch (fFill) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000459 case kInverseEvenOdd_PathFill:
460 reverse = true;
461 // fallthrough
462 case kEvenOdd_PathFill:
bsalomon@google.comd302f142011-03-03 13:54:13 +0000463 passes[0] = &gEOStencilPass;
464 if (stencilOnly) {
465 passCount = 1;
466 lastPassIsBounds = false;
467 } else {
468 passCount = 2;
469 lastPassIsBounds = true;
470 if (reverse) {
471 passes[1] = &gInvEOColorPass;
472 } else {
473 passes[1] = &gEOColorPass;
474 }
475 }
476 drawFace[0] = drawFace[1] = GrDrawTarget::kBoth_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000477 break;
478
479 case kInverseWinding_PathFill:
480 reverse = true;
481 // fallthrough
482 case kWinding_PathFill:
bsalomon@google.comd302f142011-03-03 13:54:13 +0000483 if (fSeparateStencil) {
484 if (fStencilWrapOps) {
485 passes[0] = &gWindStencilSeparateWithWrap;
486 } else {
487 passes[0] = &gWindStencilSeparateNoWrap;
488 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000489 passCount = 2;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000490 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000491 } else {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000492 if (fStencilWrapOps) {
493 passes[0] = &gWindSingleStencilWithWrapInc;
494 passes[1] = &gWindSingleStencilWithWrapDec;
495 } else {
496 passes[0] = &gWindSingleStencilNoWrapInc;
497 passes[1] = &gWindSingleStencilNoWrapDec;
498 }
499 // which is cw and which is ccw is arbitrary.
500 drawFace[0] = GrDrawTarget::kCW_DrawFace;
501 drawFace[1] = GrDrawTarget::kCCW_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000502 passCount = 3;
503 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000504 if (stencilOnly) {
505 lastPassIsBounds = false;
506 --passCount;
507 } else {
508 lastPassIsBounds = true;
509 drawFace[passCount-1] = GrDrawTarget::kBoth_DrawFace;
510 if (reverse) {
511 passes[passCount-1] = &gInvWindColorPass;
512 } else {
513 passes[passCount-1] = &gWindColorPass;
514 }
515 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000516 break;
517 default:
bsalomon@google.comee435122011-07-01 14:57:55 +0000518 GrAssert(!"Unknown path fFill!");
bsalomon@google.comffca4002011-02-22 20:34:01 +0000519 return;
520 }
521 }
522 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000523
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000524 {
525 SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath::renderPasses",
526 "verts", SkStringPrintf("%i", vert - base).c_str());
bsalomon@google.comffca4002011-02-22 20:34:01 +0000527 for (int p = 0; p < passCount; ++p) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000528 fTarget->setDrawFace(drawFace[p]);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000529 if (NULL != passes[p]) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000530 fTarget->setStencil(*passes[p]);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000531 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000532
533 if (lastPassIsBounds && (p == passCount-1)) {
534 if (!colorWritesWereDisabled) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000535 fTarget->disableState(GrDrawTarget::kNoColorWrites_StateBit);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000536 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000537 GrRect bounds;
538 if (reverse) {
539 GrAssert(NULL != fTarget->getRenderTarget());
540 // draw over the whole world.
541 bounds.setLTRB(0, 0,
542 GrIntToScalar(fTarget->getRenderTarget()->width()),
543 GrIntToScalar(fTarget->getRenderTarget()->height()));
544 GrMatrix vmi;
545 if (fTarget->getViewInverse(&vmi)) {
546 vmi.mapRect(&bounds);
547 }
548 } else {
549 bounds = fPath->getBounds();
bsalomon@google.comfc899272011-07-01 22:10:30 +0000550 bounds.offset(fTranslate);
bsalomon@google.comee435122011-07-01 14:57:55 +0000551 }
552 GrDrawTarget::AutoGeometryPush agp(fTarget);
553 fTarget->drawSimpleRect(bounds, NULL, stages);
bsalomon@google.comffca4002011-02-22 20:34:01 +0000554 } else {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000555 if (passCount > 1) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000556 fTarget->enableState(GrDrawTarget::kNoColorWrites_StateBit);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000557 }
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000558 if (fUseIndexedDraw) {
559 fTarget->drawIndexed(fPrimitiveType, 0, 0,
560 fVertexCnt, fIndexCnt);
561 } else {
562 int baseVertex = 0;
563 for (int sp = 0; sp < fSubpathCount; ++sp) {
564 fTarget->drawNonIndexed(fPrimitiveType, baseVertex,
565 fSubpathVertCount[sp]);
566 baseVertex += fSubpathVertCount[sp];
567 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000568 }
569 }
570 }
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000571 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000572}
bsalomon@google.comd302f142011-03-03 13:54:13 +0000573
bsalomon@google.comee435122011-07-01 14:57:55 +0000574void GrDefaultPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
575 this->onDrawPath(stages, false);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000576}
577
bsalomon@google.comee435122011-07-01 14:57:55 +0000578void GrDefaultPathRenderer::drawPathToStencil() {
579 GrAssert(kInverseEvenOdd_PathFill != fFill);
580 GrAssert(kInverseWinding_PathFill != fFill);
581 this->onDrawPath(0, true);
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000582}