blob: e82774d1f2c7744dffdf03bc6186ac821fc44b1a [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();
41 fTarget = NULL;
42 fPath = NULL;
43}
44
45////////////////////////////////////////////////////////////////////////////////
46
bsalomon@google.comd302f142011-03-03 13:54:13 +000047GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
48 bool stencilWrapOpsSupport)
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000049 : fSeparateStencil(separateStencilSupport)
bsalomon@google.comee435122011-07-01 14:57:55 +000050 , fStencilWrapOps(stencilWrapOpsSupport)
51 , fSubpathCount(0)
52 , fSubpathVertCount(0)
53 , fPreviousSrcTol(-GR_Scalar1)
54 , fPreviousStages(-1) {
55 fTarget = NULL;
bsalomon@google.comffca4002011-02-22 20:34:01 +000056}
57
58////////////////////////////////////////////////////////////////////////////////
bsalomon@google.comd302f142011-03-03 13:54:13 +000059// Stencil rules for paths
60
61////// Even/Odd
62
63static const GrStencilSettings gEOStencilPass = {
64 kInvert_StencilOp, kInvert_StencilOp,
65 kKeep_StencilOp, kKeep_StencilOp,
66 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
67 0xffffffff, 0xffffffff,
68 0xffffffff, 0xffffffff,
69 0xffffffff, 0xffffffff
70};
71
72// ok not to check clip b/c stencil pass only wrote inside clip
73static const GrStencilSettings gEOColorPass = {
74 kZero_StencilOp, kZero_StencilOp,
75 kZero_StencilOp, kZero_StencilOp,
76 kNotEqual_StencilFunc, kNotEqual_StencilFunc,
77 0xffffffff, 0xffffffff,
78 0x0, 0x0,
79 0xffffffff, 0xffffffff
80};
81
82// have to check clip b/c outside clip will always be zero.
83static const GrStencilSettings gInvEOColorPass = {
84 kZero_StencilOp, kZero_StencilOp,
85 kZero_StencilOp, kZero_StencilOp,
86 kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
87 0xffffffff, 0xffffffff,
88 0x0, 0x0,
89 0xffffffff, 0xffffffff
90};
91
92////// Winding
93
94// when we have separate stencil we increment front faces / decrement back faces
95// when we don't have wrap incr and decr we use the stencil test to simulate
96// them.
97
98static const GrStencilSettings gWindStencilSeparateWithWrap = {
99 kIncWrap_StencilOp, kDecWrap_StencilOp,
100 kKeep_StencilOp, kKeep_StencilOp,
101 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
102 0xffffffff, 0xffffffff,
103 0xffffffff, 0xffffffff,
104 0xffffffff, 0xffffffff
105};
106
107// if inc'ing the max value, invert to make 0
108// if dec'ing zero invert to make all ones.
109// we can't avoid touching the stencil on both passing and
110// failing, so we can't resctrict ourselves to the clip.
111static const GrStencilSettings gWindStencilSeparateNoWrap = {
112 kInvert_StencilOp, kInvert_StencilOp,
113 kIncClamp_StencilOp, kDecClamp_StencilOp,
114 kEqual_StencilFunc, kEqual_StencilFunc,
115 0xffffffff, 0xffffffff,
116 0xffffffff, 0x0,
117 0xffffffff, 0xffffffff
118};
119
120// When there are no separate faces we do two passes to setup the winding rule
121// stencil. First we draw the front faces and inc, then we draw the back faces
122// and dec. These are same as the above two split into the incrementing and
123// decrementing passes.
124static const GrStencilSettings gWindSingleStencilWithWrapInc = {
125 kIncWrap_StencilOp, kIncWrap_StencilOp,
126 kKeep_StencilOp, kKeep_StencilOp,
127 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
128 0xffffffff, 0xffffffff,
129 0xffffffff, 0xffffffff,
130 0xffffffff, 0xffffffff
131};
132static const GrStencilSettings gWindSingleStencilWithWrapDec = {
133 kDecWrap_StencilOp, kDecWrap_StencilOp,
134 kKeep_StencilOp, kKeep_StencilOp,
135 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
136 0xffffffff, 0xffffffff,
137 0xffffffff, 0xffffffff,
138 0xffffffff, 0xffffffff
139};
140static const GrStencilSettings gWindSingleStencilNoWrapInc = {
141 kInvert_StencilOp, kInvert_StencilOp,
142 kIncClamp_StencilOp, kIncClamp_StencilOp,
143 kEqual_StencilFunc, kEqual_StencilFunc,
144 0xffffffff, 0xffffffff,
145 0xffffffff, 0xffffffff,
146 0xffffffff, 0xffffffff
147};
148static const GrStencilSettings gWindSingleStencilNoWrapDec = {
149 kInvert_StencilOp, kInvert_StencilOp,
150 kDecClamp_StencilOp, kDecClamp_StencilOp,
151 kEqual_StencilFunc, kEqual_StencilFunc,
152 0xffffffff, 0xffffffff,
153 0x0, 0x0,
154 0xffffffff, 0xffffffff
155};
156
157static const GrStencilSettings gWindColorPass = {
158 kZero_StencilOp, kZero_StencilOp,
159 kZero_StencilOp, kZero_StencilOp,
160 kNonZeroIfInClip_StencilFunc, kNonZeroIfInClip_StencilFunc,
161 0xffffffff, 0xffffffff,
162 0x0, 0x0,
163 0xffffffff, 0xffffffff
164};
165
166static const GrStencilSettings gInvWindColorPass = {
167 kZero_StencilOp, kZero_StencilOp,
168 kZero_StencilOp, kZero_StencilOp,
169 kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
170 0xffffffff, 0xffffffff,
171 0x0, 0x0,
172 0xffffffff, 0xffffffff
173};
174
175////// Normal render to stencil
176
177// Sometimes the default path renderer can draw a path directly to the stencil
178// buffer without having to first resolve the interior / exterior.
179static const GrStencilSettings gDirectToStencil = {
180 kZero_StencilOp, kZero_StencilOp,
181 kIncClamp_StencilOp, kIncClamp_StencilOp,
182 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
183 0xffffffff, 0xffffffff,
184 0x0, 0x0,
185 0xffffffff, 0xffffffff
186};
187
188////////////////////////////////////////////////////////////////////////////////
189// Helpers for drawPath
bsalomon@google.comffca4002011-02-22 20:34:01 +0000190
reed@google.com07f3ee12011-05-16 17:21:57 +0000191static GrConvexHint getConvexHint(const SkPath& path) {
192 return path.isConvex() ? kConvex_ConvexHint : kConcave_ConvexHint;
193}
194
bsalomon@google.comffca4002011-02-22 20:34:01 +0000195#define STENCIL_OFF 0 // Always disable stencil (even when needed)
bsalomon@google.comffca4002011-02-22 20:34:01 +0000196
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000197static inline bool single_pass_path(const GrDrawTarget& target,
reed@google.com07f3ee12011-05-16 17:21:57 +0000198 const GrPath& path,
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000199 GrPathFill fill) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000200#if STENCIL_OFF
201 return true;
202#else
203 if (kEvenOdd_PathFill == fill) {
reed@google.com07f3ee12011-05-16 17:21:57 +0000204 GrConvexHint hint = getConvexHint(path);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000205 return hint == kConvex_ConvexHint ||
206 hint == kNonOverlappingConvexPieces_ConvexHint;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000207 } else if (kWinding_PathFill == fill) {
reed@google.com07f3ee12011-05-16 17:21:57 +0000208 GrConvexHint hint = getConvexHint(path);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000209 return hint == kConvex_ConvexHint ||
210 hint == kNonOverlappingConvexPieces_ConvexHint ||
211 (hint == kSameWindingConvexPieces_ConvexHint &&
bsalomon@google.comffca4002011-02-22 20:34:01 +0000212 target.canDisableBlend() && !target.isDitherState());
213
214 }
215 return false;
216#endif
217}
218
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000219bool GrDefaultPathRenderer::requiresStencilPass(const GrDrawTarget* target,
reed@google.com07f3ee12011-05-16 17:21:57 +0000220 const GrPath& path,
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000221 GrPathFill fill) const {
reed@google.com07f3ee12011-05-16 17:21:57 +0000222 return !single_pass_path(*target, path, fill);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000223}
224
bsalomon@google.comee435122011-07-01 14:57:55 +0000225void GrDefaultPathRenderer::pathWillClear() {
226 fSubpathVertCount.realloc(0);
227 fTarget->resetVertexSource();
228 fPreviousSrcTol = -GR_Scalar1;
229 fPreviousStages = -1;
230}
231
232void GrDefaultPathRenderer::createGeom(GrScalar srcSpaceTol,
233 GrDrawTarget::StageBitfield stages) {
234 {
235 SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
236
237 fPreviousSrcTol = srcSpaceTol;
238 fPreviousStages = stages;
239
240 GrScalar srcSpaceTolSqd = GrMul(srcSpaceTol, srcSpaceTol);
241 int maxPts = GrPathUtils::worstCasePointCount(*fPath, &fSubpathCount,
242 srcSpaceTol);
243
244 GrVertexLayout layout = 0;
245 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
246 if ((1 << s) & stages) {
247 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
248 }
249 }
250
251 // add 4 to hold the bounding rect
252 GrPoint* base;
253 fTarget->reserveVertexSpace(layout, maxPts + 4, (void**)&base);
254
255 GrPoint* vert = base;
256 GrPoint* subpathBase = base;
257
258 fSubpathVertCount.realloc(fSubpathCount);
259
260 GrPoint pts[4];
261
262 bool first = true;
263 int subpath = 0;
264
265 SkPath::Iter iter(*fPath, false);
266
267 for (;;) {
268 GrPathCmd cmd = (GrPathCmd)iter.next(pts);
269 switch (cmd) {
270 case kMove_PathCmd:
271 if (!first) {
272 fSubpathVertCount[subpath] = vert-subpathBase;
273 subpathBase = vert;
274 ++subpath;
275 }
276 *vert = pts[0];
277 vert++;
278 break;
279 case kLine_PathCmd:
280 *vert = pts[1];
281 vert++;
282 break;
283 case kQuadratic_PathCmd: {
284 GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
285 srcSpaceTolSqd, &vert,
286 GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
287 break;
288 }
289 case kCubic_PathCmd: {
290 GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
291 srcSpaceTolSqd, &vert,
292 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
293 break;
294 }
295 case kClose_PathCmd:
296 break;
297 case kEnd_PathCmd:
298 fSubpathVertCount[subpath] = vert-subpathBase;
299 ++subpath; // this could be only in debug
300 goto FINISHED;
301 }
302 first = false;
303 }
304FINISHED:
305 GrAssert(subpath == fSubpathCount);
306 GrAssert((vert - base) <= maxPts);
307
308 if (fTranslate.fX || fTranslate.fY) {
309 int count = vert - base;
310 for (int i = 0; i < count; i++) {
311 base[i].offset(fTranslate.fX, fTranslate.fY);
312 }
313 }
314 }
315}
316
317void GrDefaultPathRenderer::onDrawPath(GrDrawTarget::StageBitfield stages,
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000318 bool stencilOnly) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000319
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000320 SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath",
321 "points", SkStringPrintf("%i", path.countPoints()).c_str());
bsalomon@google.comffca4002011-02-22 20:34:01 +0000322
bsalomon@google.comee435122011-07-01 14:57:55 +0000323 GrMatrix viewM = fTarget->getViewMatrix();
bsalomon@google.comffca4002011-02-22 20:34:01 +0000324 // In order to tesselate the path we get a bound on how much the matrix can
325 // stretch when mapping to screen coordinates.
326 GrScalar stretch = viewM.getMaxStretch();
327 bool useStretch = stretch > 0;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000328 GrScalar tol = fCurveTolerance;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000329
330 if (!useStretch) {
331 // TODO: deal with perspective in some better way.
332 tol /= 10;
333 } else {
bungeman@google.com8c5753e2011-05-20 19:11:50 +0000334 tol = GrScalarDiv(tol, stretch);
bsalomon@google.comffca4002011-02-22 20:34:01 +0000335 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000336 // FIXME: It's really dumb that we recreate the verts for a new vertex
337 // layout. We only do that because the GrDrawTarget API doesn't allow
338 // us to change the vertex layout after reserveVertexSpace(). We won't
339 // actually change the vertex data when the layout changes since all the
340 // stages reference the positions (rather than having separate tex coords)
341 // and we don't ever have per-vert colors. In practice our call sites
342 // won't change the stages in use inside a setPath / removePath pair. But
343 // it is a silly limitation of the GrDrawTarget design that should be fixed.
344 if (tol != fPreviousSrcTol ||
345 stages != fPreviousStages) {
346 this->createGeom(tol, stages);
bsalomon@google.comffca4002011-02-22 20:34:01 +0000347 }
348
bsalomon@google.comee435122011-07-01 14:57:55 +0000349 GrAssert(NULL != fTarget);
350 GrDrawTarget::AutoStateRestore asr(fTarget);
351 bool colorWritesWereDisabled = fTarget->isColorWriteDisabled();
352 // face culling doesn't make sense here
353 GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace());
bsalomon@google.comffca4002011-02-22 20:34:01 +0000354
bsalomon@google.comffca4002011-02-22 20:34:01 +0000355 GrPrimitiveType type;
356 int passCount = 0;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000357 const GrStencilSettings* passes[3];
358 GrDrawTarget::DrawFace drawFace[3];
bsalomon@google.comffca4002011-02-22 20:34:01 +0000359 bool reverse = false;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000360 bool lastPassIsBounds;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000361
bsalomon@google.comee435122011-07-01 14:57:55 +0000362 if (kHairLine_PathFill == fFill) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000363 type = kLineStrip_PrimitiveType;
364 passCount = 1;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000365 if (stencilOnly) {
366 passes[0] = &gDirectToStencil;
367 } else {
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000368 passes[0] = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000369 }
370 lastPassIsBounds = false;
371 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000372 } else {
373 type = kTriangleFan_PrimitiveType;
bsalomon@google.comee435122011-07-01 14:57:55 +0000374 if (single_pass_path(*fTarget, *fPath, fFill)) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000375 passCount = 1;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000376 if (stencilOnly) {
377 passes[0] = &gDirectToStencil;
378 } else {
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000379 passes[0] = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000380 }
381 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
382 lastPassIsBounds = false;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000383 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +0000384 switch (fFill) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000385 case kInverseEvenOdd_PathFill:
386 reverse = true;
387 // fallthrough
388 case kEvenOdd_PathFill:
bsalomon@google.comd302f142011-03-03 13:54:13 +0000389 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] = GrDrawTarget::kBoth_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000403 break;
404
405 case kInverseWinding_PathFill:
406 reverse = true;
407 // fallthrough
408 case kWinding_PathFill:
bsalomon@google.comd302f142011-03-03 13:54:13 +0000409 if (fSeparateStencil) {
410 if (fStencilWrapOps) {
411 passes[0] = &gWindStencilSeparateWithWrap;
412 } else {
413 passes[0] = &gWindStencilSeparateNoWrap;
414 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000415 passCount = 2;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000416 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000417 } else {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000418 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] = GrDrawTarget::kCW_DrawFace;
427 drawFace[1] = GrDrawTarget::kCCW_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000428 passCount = 3;
429 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000430 if (stencilOnly) {
431 lastPassIsBounds = false;
432 --passCount;
433 } else {
434 lastPassIsBounds = true;
435 drawFace[passCount-1] = GrDrawTarget::kBoth_DrawFace;
436 if (reverse) {
437 passes[passCount-1] = &gInvWindColorPass;
438 } else {
439 passes[passCount-1] = &gWindColorPass;
440 }
441 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000442 break;
443 default:
bsalomon@google.comee435122011-07-01 14:57:55 +0000444 GrAssert(!"Unknown path fFill!");
bsalomon@google.comffca4002011-02-22 20:34:01 +0000445 return;
446 }
447 }
448 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000449
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000450 {
451 SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath::renderPasses",
452 "verts", SkStringPrintf("%i", vert - base).c_str());
bsalomon@google.comffca4002011-02-22 20:34:01 +0000453 for (int p = 0; p < passCount; ++p) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000454 fTarget->setDrawFace(drawFace[p]);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000455 if (NULL != passes[p]) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000456 fTarget->setStencil(*passes[p]);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000457 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000458
459 if (lastPassIsBounds && (p == passCount-1)) {
460 if (!colorWritesWereDisabled) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000461 fTarget->disableState(GrDrawTarget::kNoColorWrites_StateBit);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000462 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000463 GrRect bounds;
464 if (reverse) {
465 GrAssert(NULL != fTarget->getRenderTarget());
466 // draw over the whole world.
467 bounds.setLTRB(0, 0,
468 GrIntToScalar(fTarget->getRenderTarget()->width()),
469 GrIntToScalar(fTarget->getRenderTarget()->height()));
470 GrMatrix vmi;
471 if (fTarget->getViewInverse(&vmi)) {
472 vmi.mapRect(&bounds);
473 }
474 } else {
475 bounds = fPath->getBounds();
bsalomon@google.comfc899272011-07-01 22:10:30 +0000476 bounds.offset(fTranslate);
bsalomon@google.comee435122011-07-01 14:57:55 +0000477 }
478 GrDrawTarget::AutoGeometryPush agp(fTarget);
479 fTarget->drawSimpleRect(bounds, NULL, stages);
bsalomon@google.comffca4002011-02-22 20:34:01 +0000480 } else {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000481 if (passCount > 1) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000482 fTarget->enableState(GrDrawTarget::kNoColorWrites_StateBit);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000483 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000484 int baseVertex = 0;
bsalomon@google.comee435122011-07-01 14:57:55 +0000485 for (int sp = 0; sp < fSubpathCount; ++sp) {
486 fTarget->drawNonIndexed(type, baseVertex,
487 fSubpathVertCount[sp]);
488 baseVertex += fSubpathVertCount[sp];
bsalomon@google.comffca4002011-02-22 20:34:01 +0000489 }
490 }
491 }
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000492 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000493}
bsalomon@google.comd302f142011-03-03 13:54:13 +0000494
bsalomon@google.comee435122011-07-01 14:57:55 +0000495void GrDefaultPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
496 this->onDrawPath(stages, false);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000497}
498
bsalomon@google.comee435122011-07-01 14:57:55 +0000499void GrDefaultPathRenderer::drawPathToStencil() {
500 GrAssert(kInverseEvenOdd_PathFill != fFill);
501 GrAssert(kInverseWinding_PathFill != fFill);
502 this->onDrawPath(0, true);
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000503}