blob: 7220d0e4aad13619c1150fe2effce67c48c184e9 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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 */
bsalomon@google.comffca4002011-02-22 20:34:01 +00008#include "GrPathRenderer.h"
9
10#include "GrPoint.h"
11#include "GrDrawTarget.h"
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +000012#include "GrPathUtils.h"
bsalomon@google.comffca4002011-02-22 20:34:01 +000013#include "GrTexture.h"
14
tomhudson@google.com278cbb42011-06-30 19:37:01 +000015#include "SkString.h"
bsalomon@google.com3582bf92011-06-30 21:32:31 +000016#include "SkTemplates.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000017#include "SkTrace.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000018
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000019GrPathRenderer::GrPathRenderer()
bsalomon@google.comee435122011-07-01 14:57:55 +000020 : fCurveTolerance (GR_Scalar1)
21 , fPath(NULL)
22 , fTarget(NULL) {
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000023}
bsalomon@google.comee435122011-07-01 14:57:55 +000024
25
26void GrPathRenderer::setPath(GrDrawTarget* target,
27 const SkPath* path,
28 GrPathFill fill,
29 const GrPoint* translate) {
30 GrAssert(NULL == fPath);
31 GrAssert(NULL == fTarget);
32 GrAssert(NULL != target);
33
34 fTarget = target;
35 fPath = path;
36 fFill = fill;
37 if (NULL != translate) {
38 fTranslate = *translate;
39 } else {
40 fTranslate.fX = fTranslate.fY = 0;
41 }
42 this->pathWasSet();
43}
44
45void GrPathRenderer::clearPath() {
46 this->pathWillClear();
47 fTarget->resetVertexSource();
bsalomon@google.com25fd36c2011-07-06 17:41:08 +000048 fTarget->resetIndexSource();
bsalomon@google.comee435122011-07-01 14:57:55 +000049 fTarget = NULL;
50 fPath = NULL;
51}
52
53////////////////////////////////////////////////////////////////////////////////
54
bsalomon@google.comd302f142011-03-03 13:54:13 +000055GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
56 bool stencilWrapOpsSupport)
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000057 : fSeparateStencil(separateStencilSupport)
bsalomon@google.comee435122011-07-01 14:57:55 +000058 , fStencilWrapOps(stencilWrapOpsSupport)
59 , fSubpathCount(0)
60 , fSubpathVertCount(0)
61 , fPreviousSrcTol(-GR_Scalar1)
62 , fPreviousStages(-1) {
63 fTarget = NULL;
bsalomon@google.comffca4002011-02-22 20:34:01 +000064}
65
66////////////////////////////////////////////////////////////////////////////////
bsalomon@google.comd302f142011-03-03 13:54:13 +000067// Stencil rules for paths
68
69////// Even/Odd
70
71static const GrStencilSettings gEOStencilPass = {
72 kInvert_StencilOp, kInvert_StencilOp,
73 kKeep_StencilOp, kKeep_StencilOp,
74 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
75 0xffffffff, 0xffffffff,
76 0xffffffff, 0xffffffff,
77 0xffffffff, 0xffffffff
78};
79
80// ok not to check clip b/c stencil pass only wrote inside clip
81static const GrStencilSettings gEOColorPass = {
82 kZero_StencilOp, kZero_StencilOp,
83 kZero_StencilOp, kZero_StencilOp,
84 kNotEqual_StencilFunc, kNotEqual_StencilFunc,
85 0xffffffff, 0xffffffff,
86 0x0, 0x0,
87 0xffffffff, 0xffffffff
88};
89
90// have to check clip b/c outside clip will always be zero.
91static const GrStencilSettings gInvEOColorPass = {
92 kZero_StencilOp, kZero_StencilOp,
93 kZero_StencilOp, kZero_StencilOp,
94 kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
95 0xffffffff, 0xffffffff,
96 0x0, 0x0,
97 0xffffffff, 0xffffffff
98};
99
100////// Winding
101
102// when we have separate stencil we increment front faces / decrement back faces
103// when we don't have wrap incr and decr we use the stencil test to simulate
104// them.
105
106static const GrStencilSettings gWindStencilSeparateWithWrap = {
107 kIncWrap_StencilOp, kDecWrap_StencilOp,
108 kKeep_StencilOp, kKeep_StencilOp,
109 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
110 0xffffffff, 0xffffffff,
111 0xffffffff, 0xffffffff,
112 0xffffffff, 0xffffffff
113};
114
115// if inc'ing the max value, invert to make 0
116// if dec'ing zero invert to make all ones.
117// we can't avoid touching the stencil on both passing and
118// failing, so we can't resctrict ourselves to the clip.
119static const GrStencilSettings gWindStencilSeparateNoWrap = {
120 kInvert_StencilOp, kInvert_StencilOp,
121 kIncClamp_StencilOp, kDecClamp_StencilOp,
122 kEqual_StencilFunc, kEqual_StencilFunc,
123 0xffffffff, 0xffffffff,
124 0xffffffff, 0x0,
125 0xffffffff, 0xffffffff
126};
127
128// When there are no separate faces we do two passes to setup the winding rule
129// stencil. First we draw the front faces and inc, then we draw the back faces
130// and dec. These are same as the above two split into the incrementing and
131// decrementing passes.
132static const GrStencilSettings gWindSingleStencilWithWrapInc = {
133 kIncWrap_StencilOp, kIncWrap_StencilOp,
134 kKeep_StencilOp, kKeep_StencilOp,
135 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
136 0xffffffff, 0xffffffff,
137 0xffffffff, 0xffffffff,
138 0xffffffff, 0xffffffff
139};
140static const GrStencilSettings gWindSingleStencilWithWrapDec = {
141 kDecWrap_StencilOp, kDecWrap_StencilOp,
142 kKeep_StencilOp, kKeep_StencilOp,
143 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
144 0xffffffff, 0xffffffff,
145 0xffffffff, 0xffffffff,
146 0xffffffff, 0xffffffff
147};
148static const GrStencilSettings gWindSingleStencilNoWrapInc = {
149 kInvert_StencilOp, kInvert_StencilOp,
150 kIncClamp_StencilOp, kIncClamp_StencilOp,
151 kEqual_StencilFunc, kEqual_StencilFunc,
152 0xffffffff, 0xffffffff,
153 0xffffffff, 0xffffffff,
154 0xffffffff, 0xffffffff
155};
156static const GrStencilSettings gWindSingleStencilNoWrapDec = {
157 kInvert_StencilOp, kInvert_StencilOp,
158 kDecClamp_StencilOp, kDecClamp_StencilOp,
159 kEqual_StencilFunc, kEqual_StencilFunc,
160 0xffffffff, 0xffffffff,
161 0x0, 0x0,
162 0xffffffff, 0xffffffff
163};
164
165static const GrStencilSettings gWindColorPass = {
166 kZero_StencilOp, kZero_StencilOp,
167 kZero_StencilOp, kZero_StencilOp,
168 kNonZeroIfInClip_StencilFunc, kNonZeroIfInClip_StencilFunc,
169 0xffffffff, 0xffffffff,
170 0x0, 0x0,
171 0xffffffff, 0xffffffff
172};
173
174static const GrStencilSettings gInvWindColorPass = {
175 kZero_StencilOp, kZero_StencilOp,
176 kZero_StencilOp, kZero_StencilOp,
177 kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
178 0xffffffff, 0xffffffff,
179 0x0, 0x0,
180 0xffffffff, 0xffffffff
181};
182
183////// Normal render to stencil
184
185// Sometimes the default path renderer can draw a path directly to the stencil
186// buffer without having to first resolve the interior / exterior.
187static const GrStencilSettings gDirectToStencil = {
188 kZero_StencilOp, kZero_StencilOp,
189 kIncClamp_StencilOp, kIncClamp_StencilOp,
190 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
191 0xffffffff, 0xffffffff,
192 0x0, 0x0,
193 0xffffffff, 0xffffffff
194};
195
196////////////////////////////////////////////////////////////////////////////////
197// Helpers for drawPath
bsalomon@google.comffca4002011-02-22 20:34:01 +0000198
reed@google.com07f3ee12011-05-16 17:21:57 +0000199static GrConvexHint getConvexHint(const SkPath& path) {
200 return path.isConvex() ? kConvex_ConvexHint : kConcave_ConvexHint;
201}
202
bsalomon@google.comffca4002011-02-22 20:34:01 +0000203#define STENCIL_OFF 0 // Always disable stencil (even when needed)
bsalomon@google.comffca4002011-02-22 20:34:01 +0000204
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000205static inline bool single_pass_path(const GrDrawTarget& target,
reed@google.com07f3ee12011-05-16 17:21:57 +0000206 const GrPath& path,
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000207 GrPathFill fill) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000208#if STENCIL_OFF
209 return true;
210#else
211 if (kEvenOdd_PathFill == fill) {
reed@google.com07f3ee12011-05-16 17:21:57 +0000212 GrConvexHint hint = getConvexHint(path);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000213 return hint == kConvex_ConvexHint ||
214 hint == kNonOverlappingConvexPieces_ConvexHint;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000215 } else if (kWinding_PathFill == fill) {
reed@google.com07f3ee12011-05-16 17:21:57 +0000216 GrConvexHint hint = getConvexHint(path);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000217 return hint == kConvex_ConvexHint ||
218 hint == kNonOverlappingConvexPieces_ConvexHint ||
219 (hint == kSameWindingConvexPieces_ConvexHint &&
bsalomon@google.comffca4002011-02-22 20:34:01 +0000220 target.canDisableBlend() && !target.isDitherState());
221
222 }
223 return false;
224#endif
225}
226
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000227bool GrDefaultPathRenderer::requiresStencilPass(const GrDrawTarget* target,
reed@google.com07f3ee12011-05-16 17:21:57 +0000228 const GrPath& path,
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000229 GrPathFill fill) const {
reed@google.com07f3ee12011-05-16 17:21:57 +0000230 return !single_pass_path(*target, path, fill);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000231}
232
bsalomon@google.comee435122011-07-01 14:57:55 +0000233void GrDefaultPathRenderer::pathWillClear() {
234 fSubpathVertCount.realloc(0);
235 fTarget->resetVertexSource();
236 fPreviousSrcTol = -GR_Scalar1;
237 fPreviousStages = -1;
238}
239
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000240static inline void append_countour_edge_indices(GrPathFill fillType,
241 uint16_t fanCenterIdx,
242 uint16_t edgeV0Idx,
243 uint16_t** indices) {
244 // when drawing lines we're appending line segments along
245 // the contour. When applying the other fill rules we're
246 // drawing triangle fans around fanCenterIdx.
247 if (kHairLine_PathFill != fillType) {
248 *((*indices)++) = fanCenterIdx;
249 }
250 *((*indices)++) = edgeV0Idx;
251 *((*indices)++) = edgeV0Idx + 1;
252}
253
254bool GrDefaultPathRenderer::createGeom(GrScalar srcSpaceTol,
bsalomon@google.comee435122011-07-01 14:57:55 +0000255 GrDrawTarget::StageBitfield stages) {
256 {
257 SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
258
bsalomon@google.comee435122011-07-01 14:57:55 +0000259 GrScalar srcSpaceTolSqd = GrMul(srcSpaceTol, srcSpaceTol);
260 int maxPts = GrPathUtils::worstCasePointCount(*fPath, &fSubpathCount,
261 srcSpaceTol);
262
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000263 if (maxPts <= 0) {
264 return false;
265 }
266 if (maxPts > ((int)SK_MaxU16 + 1)) {
267 GrPrintf("Path not rendered, too many verts (%d)\n", maxPts);
268 return false;
269 }
270
271 fPreviousSrcTol = srcSpaceTol;
272 fPreviousStages = stages;
273
bsalomon@google.comee435122011-07-01 14:57:55 +0000274 GrVertexLayout layout = 0;
275 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
276 if ((1 << s) & stages) {
277 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
278 }
279 }
280
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000281 fUseIndexedDraw = fSubpathCount > 1;
bsalomon@google.comee435122011-07-01 14:57:55 +0000282
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000283 int maxIdxs = 0;
284 if (kHairLine_PathFill == fFill) {
285 if (fUseIndexedDraw) {
286 maxIdxs = 2 * maxPts;
287 fPrimitiveType = kLines_PrimitiveType;
288 } else {
289 fPrimitiveType = kLineStrip_PrimitiveType;
290 }
291 } else {
292 if (fUseIndexedDraw) {
293 maxIdxs = 3 * maxPts;
294 fPrimitiveType = kTriangles_PrimitiveType;
295 } else {
296 fPrimitiveType = kTriangleFan_PrimitiveType;
297 }
298 }
299
300 GrPoint* base;
301 fTarget->reserveVertexSpace(layout, maxPts, (void**)&base);
bsalomon@google.comee435122011-07-01 14:57:55 +0000302 GrPoint* vert = base;
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000303
304 uint16_t* idxBase = NULL;
305 uint16_t* idx = NULL;
306 uint16_t subpathIdxStart = 0;
307 if (fUseIndexedDraw) {
308 fTarget->reserveIndexSpace(maxIdxs, (void**)&idxBase);
309 idx = idxBase;
310 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000311
312 fSubpathVertCount.realloc(fSubpathCount);
313
314 GrPoint pts[4];
315
316 bool first = true;
317 int subpath = 0;
318
319 SkPath::Iter iter(*fPath, false);
320
321 for (;;) {
322 GrPathCmd cmd = (GrPathCmd)iter.next(pts);
323 switch (cmd) {
324 case kMove_PathCmd:
325 if (!first) {
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000326 uint16_t currIdx = (uint16_t) (vert - base);
327 fSubpathVertCount[subpath] = currIdx - subpathIdxStart;
328 subpathIdxStart = currIdx;
bsalomon@google.comee435122011-07-01 14:57:55 +0000329 ++subpath;
330 }
331 *vert = pts[0];
332 vert++;
333 break;
334 case kLine_PathCmd:
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000335 if (fUseIndexedDraw) {
336 uint16_t prevIdx = (uint16_t)(vert - base) - 1;
337 append_countour_edge_indices(fFill, subpathIdxStart,
338 prevIdx, &idx);
339 }
340 *(vert++) = pts[1];
bsalomon@google.comee435122011-07-01 14:57:55 +0000341 break;
342 case kQuadratic_PathCmd: {
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000343 // first pt of quad is the pt we ended on in previous step
344 uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
345 uint16_t numPts = (uint16_t)
346 GrPathUtils::generateQuadraticPoints(
347 pts[0], pts[1], pts[2],
348 srcSpaceTolSqd, &vert,
349 GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
350 if (fUseIndexedDraw) {
351 for (uint16_t i = 0; i < numPts; ++i) {
352 append_countour_edge_indices(fFill, subpathIdxStart,
353 firstQPtIdx + i, &idx);
354 }
355 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000356 break;
357 }
358 case kCubic_PathCmd: {
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000359 // first pt of cubic is the pt we ended on in previous step
360 uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
361 uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
362 pts[0], pts[1], pts[2], pts[3],
363 srcSpaceTolSqd, &vert,
364 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
365 if (fUseIndexedDraw) {
366 for (uint16_t i = 0; i < numPts; ++i) {
367 append_countour_edge_indices(fFill, subpathIdxStart,
368 firstCPtIdx + i, &idx);
369 }
370 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000371 break;
372 }
373 case kClose_PathCmd:
374 break;
375 case kEnd_PathCmd:
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000376 uint16_t currIdx = (uint16_t) (vert - base);
377 fSubpathVertCount[subpath] = currIdx - subpathIdxStart;
bsalomon@google.comee435122011-07-01 14:57:55 +0000378 goto FINISHED;
379 }
380 first = false;
381 }
382FINISHED:
bsalomon@google.comee435122011-07-01 14:57:55 +0000383 GrAssert((vert - base) <= maxPts);
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000384 GrAssert((idx - idxBase) <= maxIdxs);
385
386 fVertexCnt = vert - base;
387 fIndexCnt = idx - idxBase;
bsalomon@google.comee435122011-07-01 14:57:55 +0000388
389 if (fTranslate.fX || fTranslate.fY) {
390 int count = vert - base;
391 for (int i = 0; i < count; i++) {
392 base[i].offset(fTranslate.fX, fTranslate.fY);
393 }
394 }
395 }
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000396 return true;
bsalomon@google.comee435122011-07-01 14:57:55 +0000397}
398
399void GrDefaultPathRenderer::onDrawPath(GrDrawTarget::StageBitfield stages,
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000400 bool stencilOnly) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000401
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000402 SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath",
403 "points", SkStringPrintf("%i", path.countPoints()).c_str());
bsalomon@google.comffca4002011-02-22 20:34:01 +0000404
bsalomon@google.comee435122011-07-01 14:57:55 +0000405 GrMatrix viewM = fTarget->getViewMatrix();
bsalomon@google.comffca4002011-02-22 20:34:01 +0000406 // In order to tesselate the path we get a bound on how much the matrix can
407 // stretch when mapping to screen coordinates.
408 GrScalar stretch = viewM.getMaxStretch();
409 bool useStretch = stretch > 0;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000410 GrScalar tol = fCurveTolerance;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000411
412 if (!useStretch) {
413 // TODO: deal with perspective in some better way.
414 tol /= 10;
415 } else {
bungeman@google.com8c5753e2011-05-20 19:11:50 +0000416 tol = GrScalarDiv(tol, stretch);
bsalomon@google.comffca4002011-02-22 20:34:01 +0000417 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000418 // FIXME: It's really dumb that we recreate the verts for a new vertex
419 // layout. We only do that because the GrDrawTarget API doesn't allow
420 // us to change the vertex layout after reserveVertexSpace(). We won't
421 // actually change the vertex data when the layout changes since all the
422 // stages reference the positions (rather than having separate tex coords)
423 // and we don't ever have per-vert colors. In practice our call sites
424 // won't change the stages in use inside a setPath / removePath pair. But
425 // it is a silly limitation of the GrDrawTarget design that should be fixed.
426 if (tol != fPreviousSrcTol ||
427 stages != fPreviousStages) {
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000428 if (!this->createGeom(tol, stages)) {
429 return;
430 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000431 }
432
bsalomon@google.comee435122011-07-01 14:57:55 +0000433 GrAssert(NULL != fTarget);
434 GrDrawTarget::AutoStateRestore asr(fTarget);
435 bool colorWritesWereDisabled = fTarget->isColorWriteDisabled();
436 // face culling doesn't make sense here
437 GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace());
bsalomon@google.comffca4002011-02-22 20:34:01 +0000438
bsalomon@google.comffca4002011-02-22 20:34:01 +0000439 int passCount = 0;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000440 const GrStencilSettings* passes[3];
441 GrDrawTarget::DrawFace drawFace[3];
bsalomon@google.comffca4002011-02-22 20:34:01 +0000442 bool reverse = false;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000443 bool lastPassIsBounds;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000444
bsalomon@google.comee435122011-07-01 14:57:55 +0000445 if (kHairLine_PathFill == fFill) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000446 passCount = 1;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000447 if (stencilOnly) {
448 passes[0] = &gDirectToStencil;
449 } else {
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000450 passes[0] = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000451 }
452 lastPassIsBounds = false;
453 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000454 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +0000455 if (single_pass_path(*fTarget, *fPath, fFill)) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000456 passCount = 1;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000457 if (stencilOnly) {
458 passes[0] = &gDirectToStencil;
459 } else {
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000460 passes[0] = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000461 }
462 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
463 lastPassIsBounds = false;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000464 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +0000465 switch (fFill) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000466 case kInverseEvenOdd_PathFill:
467 reverse = true;
468 // fallthrough
469 case kEvenOdd_PathFill:
bsalomon@google.comd302f142011-03-03 13:54:13 +0000470 passes[0] = &gEOStencilPass;
471 if (stencilOnly) {
472 passCount = 1;
473 lastPassIsBounds = false;
474 } else {
475 passCount = 2;
476 lastPassIsBounds = true;
477 if (reverse) {
478 passes[1] = &gInvEOColorPass;
479 } else {
480 passes[1] = &gEOColorPass;
481 }
482 }
483 drawFace[0] = drawFace[1] = GrDrawTarget::kBoth_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000484 break;
485
486 case kInverseWinding_PathFill:
487 reverse = true;
488 // fallthrough
489 case kWinding_PathFill:
bsalomon@google.comd302f142011-03-03 13:54:13 +0000490 if (fSeparateStencil) {
491 if (fStencilWrapOps) {
492 passes[0] = &gWindStencilSeparateWithWrap;
493 } else {
494 passes[0] = &gWindStencilSeparateNoWrap;
495 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000496 passCount = 2;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000497 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000498 } else {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000499 if (fStencilWrapOps) {
500 passes[0] = &gWindSingleStencilWithWrapInc;
501 passes[1] = &gWindSingleStencilWithWrapDec;
502 } else {
503 passes[0] = &gWindSingleStencilNoWrapInc;
504 passes[1] = &gWindSingleStencilNoWrapDec;
505 }
506 // which is cw and which is ccw is arbitrary.
507 drawFace[0] = GrDrawTarget::kCW_DrawFace;
508 drawFace[1] = GrDrawTarget::kCCW_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000509 passCount = 3;
510 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000511 if (stencilOnly) {
512 lastPassIsBounds = false;
513 --passCount;
514 } else {
515 lastPassIsBounds = true;
516 drawFace[passCount-1] = GrDrawTarget::kBoth_DrawFace;
517 if (reverse) {
518 passes[passCount-1] = &gInvWindColorPass;
519 } else {
520 passes[passCount-1] = &gWindColorPass;
521 }
522 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000523 break;
524 default:
bsalomon@google.comee435122011-07-01 14:57:55 +0000525 GrAssert(!"Unknown path fFill!");
bsalomon@google.comffca4002011-02-22 20:34:01 +0000526 return;
527 }
528 }
529 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000530
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000531 {
532 SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath::renderPasses",
533 "verts", SkStringPrintf("%i", vert - base).c_str());
bsalomon@google.comffca4002011-02-22 20:34:01 +0000534 for (int p = 0; p < passCount; ++p) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000535 fTarget->setDrawFace(drawFace[p]);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000536 if (NULL != passes[p]) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000537 fTarget->setStencil(*passes[p]);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000538 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000539
540 if (lastPassIsBounds && (p == passCount-1)) {
541 if (!colorWritesWereDisabled) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000542 fTarget->disableState(GrDrawTarget::kNoColorWrites_StateBit);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000543 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000544 GrRect bounds;
545 if (reverse) {
546 GrAssert(NULL != fTarget->getRenderTarget());
547 // draw over the whole world.
548 bounds.setLTRB(0, 0,
549 GrIntToScalar(fTarget->getRenderTarget()->width()),
550 GrIntToScalar(fTarget->getRenderTarget()->height()));
551 GrMatrix vmi;
552 if (fTarget->getViewInverse(&vmi)) {
553 vmi.mapRect(&bounds);
554 }
555 } else {
556 bounds = fPath->getBounds();
bsalomon@google.comfc899272011-07-01 22:10:30 +0000557 bounds.offset(fTranslate);
bsalomon@google.comee435122011-07-01 14:57:55 +0000558 }
559 GrDrawTarget::AutoGeometryPush agp(fTarget);
560 fTarget->drawSimpleRect(bounds, NULL, stages);
bsalomon@google.comffca4002011-02-22 20:34:01 +0000561 } else {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000562 if (passCount > 1) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000563 fTarget->enableState(GrDrawTarget::kNoColorWrites_StateBit);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000564 }
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000565 if (fUseIndexedDraw) {
566 fTarget->drawIndexed(fPrimitiveType, 0, 0,
567 fVertexCnt, fIndexCnt);
568 } else {
569 int baseVertex = 0;
570 for (int sp = 0; sp < fSubpathCount; ++sp) {
571 fTarget->drawNonIndexed(fPrimitiveType, baseVertex,
572 fSubpathVertCount[sp]);
573 baseVertex += fSubpathVertCount[sp];
574 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000575 }
576 }
577 }
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000578 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000579}
bsalomon@google.comd302f142011-03-03 13:54:13 +0000580
bsalomon@google.comee435122011-07-01 14:57:55 +0000581void GrDefaultPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
582 this->onDrawPath(stages, false);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000583}
584
bsalomon@google.comee435122011-07-01 14:57:55 +0000585void GrDefaultPathRenderer::drawPathToStencil() {
586 GrAssert(kInverseEvenOdd_PathFill != fFill);
587 GrAssert(kInverseWinding_PathFill != fFill);
588 this->onDrawPath(0, true);
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000589}