blob: 26c92b84002ff6171038c58b2b4d55a42e5f25ac [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();
bsalomon@google.com82866fd2011-08-05 16:27:32 +0000236 if (fUseIndexedDraw) {
237 fTarget->resetIndexSource();
238 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000239 fPreviousSrcTol = -GR_Scalar1;
240 fPreviousStages = -1;
241}
242
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000243static inline void append_countour_edge_indices(GrPathFill fillType,
244 uint16_t fanCenterIdx,
245 uint16_t edgeV0Idx,
246 uint16_t** indices) {
247 // when drawing lines we're appending line segments along
248 // the contour. When applying the other fill rules we're
249 // drawing triangle fans around fanCenterIdx.
250 if (kHairLine_PathFill != fillType) {
251 *((*indices)++) = fanCenterIdx;
252 }
253 *((*indices)++) = edgeV0Idx;
254 *((*indices)++) = edgeV0Idx + 1;
255}
256
257bool GrDefaultPathRenderer::createGeom(GrScalar srcSpaceTol,
bsalomon@google.comee435122011-07-01 14:57:55 +0000258 GrDrawTarget::StageBitfield stages) {
259 {
260 SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
261
bsalomon@google.comee435122011-07-01 14:57:55 +0000262 GrScalar srcSpaceTolSqd = GrMul(srcSpaceTol, srcSpaceTol);
263 int maxPts = GrPathUtils::worstCasePointCount(*fPath, &fSubpathCount,
264 srcSpaceTol);
265
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000266 if (maxPts <= 0) {
267 return false;
268 }
269 if (maxPts > ((int)SK_MaxU16 + 1)) {
270 GrPrintf("Path not rendered, too many verts (%d)\n", maxPts);
271 return false;
272 }
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;
bsalomon@google.com82866fd2011-08-05 16:27:32 +0000301 if (!fTarget->reserveVertexSpace(layout, maxPts, (void**)&base)) {
302 return false;
303 }
304 GrAssert(NULL != base);
bsalomon@google.comee435122011-07-01 14:57:55 +0000305 GrPoint* vert = base;
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000306
307 uint16_t* idxBase = NULL;
308 uint16_t* idx = NULL;
309 uint16_t subpathIdxStart = 0;
310 if (fUseIndexedDraw) {
bsalomon@google.com82866fd2011-08-05 16:27:32 +0000311 if (!fTarget->reserveIndexSpace(maxIdxs, (void**)&idxBase)) {
312 fTarget->resetVertexSource();
313 return false;
314 }
315 GrAssert(NULL != idxBase);
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000316 idx = idxBase;
317 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000318
319 fSubpathVertCount.realloc(fSubpathCount);
320
321 GrPoint pts[4];
322
323 bool first = true;
324 int subpath = 0;
325
326 SkPath::Iter iter(*fPath, false);
327
328 for (;;) {
329 GrPathCmd cmd = (GrPathCmd)iter.next(pts);
330 switch (cmd) {
331 case kMove_PathCmd:
332 if (!first) {
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000333 uint16_t currIdx = (uint16_t) (vert - base);
334 fSubpathVertCount[subpath] = currIdx - subpathIdxStart;
335 subpathIdxStart = currIdx;
bsalomon@google.comee435122011-07-01 14:57:55 +0000336 ++subpath;
337 }
338 *vert = pts[0];
339 vert++;
340 break;
341 case kLine_PathCmd:
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000342 if (fUseIndexedDraw) {
343 uint16_t prevIdx = (uint16_t)(vert - base) - 1;
344 append_countour_edge_indices(fFill, subpathIdxStart,
345 prevIdx, &idx);
346 }
347 *(vert++) = pts[1];
bsalomon@google.comee435122011-07-01 14:57:55 +0000348 break;
349 case kQuadratic_PathCmd: {
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000350 // first pt of quad is the pt we ended on in previous step
351 uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
352 uint16_t numPts = (uint16_t)
353 GrPathUtils::generateQuadraticPoints(
354 pts[0], pts[1], pts[2],
355 srcSpaceTolSqd, &vert,
356 GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
357 if (fUseIndexedDraw) {
358 for (uint16_t i = 0; i < numPts; ++i) {
359 append_countour_edge_indices(fFill, subpathIdxStart,
360 firstQPtIdx + i, &idx);
361 }
362 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000363 break;
364 }
365 case kCubic_PathCmd: {
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000366 // first pt of cubic is the pt we ended on in previous step
367 uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
368 uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
369 pts[0], pts[1], pts[2], pts[3],
370 srcSpaceTolSqd, &vert,
371 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
372 if (fUseIndexedDraw) {
373 for (uint16_t i = 0; i < numPts; ++i) {
374 append_countour_edge_indices(fFill, subpathIdxStart,
375 firstCPtIdx + i, &idx);
376 }
377 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000378 break;
379 }
380 case kClose_PathCmd:
381 break;
382 case kEnd_PathCmd:
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000383 uint16_t currIdx = (uint16_t) (vert - base);
384 fSubpathVertCount[subpath] = currIdx - subpathIdxStart;
bsalomon@google.comee435122011-07-01 14:57:55 +0000385 goto FINISHED;
386 }
387 first = false;
388 }
389FINISHED:
bsalomon@google.comee435122011-07-01 14:57:55 +0000390 GrAssert((vert - base) <= maxPts);
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000391 GrAssert((idx - idxBase) <= maxIdxs);
392
393 fVertexCnt = vert - base;
394 fIndexCnt = idx - idxBase;
bsalomon@google.comee435122011-07-01 14:57:55 +0000395
396 if (fTranslate.fX || fTranslate.fY) {
397 int count = vert - base;
398 for (int i = 0; i < count; i++) {
399 base[i].offset(fTranslate.fX, fTranslate.fY);
400 }
401 }
402 }
bsalomon@google.com82866fd2011-08-05 16:27:32 +0000403 // set these at the end so if we failed on first drawPath inside a
404 // setPath/clearPath block we won't assume geom was created on a subsequent
405 // drawPath in the same block.
406 fPreviousSrcTol = srcSpaceTol;
407 fPreviousStages = stages;
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000408 return true;
bsalomon@google.comee435122011-07-01 14:57:55 +0000409}
410
411void GrDefaultPathRenderer::onDrawPath(GrDrawTarget::StageBitfield stages,
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000412 bool stencilOnly) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000413
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000414 SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath",
415 "points", SkStringPrintf("%i", path.countPoints()).c_str());
bsalomon@google.comffca4002011-02-22 20:34:01 +0000416
bsalomon@google.comee435122011-07-01 14:57:55 +0000417 GrMatrix viewM = fTarget->getViewMatrix();
bsalomon@google.comffca4002011-02-22 20:34:01 +0000418 // In order to tesselate the path we get a bound on how much the matrix can
419 // stretch when mapping to screen coordinates.
420 GrScalar stretch = viewM.getMaxStretch();
421 bool useStretch = stretch > 0;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000422 GrScalar tol = fCurveTolerance;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000423
424 if (!useStretch) {
425 // TODO: deal with perspective in some better way.
426 tol /= 10;
427 } else {
bungeman@google.com8c5753e2011-05-20 19:11:50 +0000428 tol = GrScalarDiv(tol, stretch);
bsalomon@google.comffca4002011-02-22 20:34:01 +0000429 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000430 // FIXME: It's really dumb that we recreate the verts for a new vertex
431 // layout. We only do that because the GrDrawTarget API doesn't allow
432 // us to change the vertex layout after reserveVertexSpace(). We won't
433 // actually change the vertex data when the layout changes since all the
434 // stages reference the positions (rather than having separate tex coords)
435 // and we don't ever have per-vert colors. In practice our call sites
436 // won't change the stages in use inside a setPath / removePath pair. But
437 // it is a silly limitation of the GrDrawTarget design that should be fixed.
438 if (tol != fPreviousSrcTol ||
439 stages != fPreviousStages) {
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000440 if (!this->createGeom(tol, stages)) {
441 return;
442 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000443 }
444
bsalomon@google.comee435122011-07-01 14:57:55 +0000445 GrAssert(NULL != fTarget);
446 GrDrawTarget::AutoStateRestore asr(fTarget);
447 bool colorWritesWereDisabled = fTarget->isColorWriteDisabled();
448 // face culling doesn't make sense here
449 GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace());
bsalomon@google.comffca4002011-02-22 20:34:01 +0000450
bsalomon@google.comffca4002011-02-22 20:34:01 +0000451 int passCount = 0;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000452 const GrStencilSettings* passes[3];
453 GrDrawTarget::DrawFace drawFace[3];
bsalomon@google.comffca4002011-02-22 20:34:01 +0000454 bool reverse = false;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000455 bool lastPassIsBounds;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000456
bsalomon@google.comee435122011-07-01 14:57:55 +0000457 if (kHairLine_PathFill == fFill) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000458 passCount = 1;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000459 if (stencilOnly) {
460 passes[0] = &gDirectToStencil;
461 } else {
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000462 passes[0] = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000463 }
464 lastPassIsBounds = false;
465 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000466 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +0000467 if (single_pass_path(*fTarget, *fPath, fFill)) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000468 passCount = 1;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000469 if (stencilOnly) {
470 passes[0] = &gDirectToStencil;
471 } else {
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000472 passes[0] = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000473 }
474 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
475 lastPassIsBounds = false;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000476 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +0000477 switch (fFill) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000478 case kInverseEvenOdd_PathFill:
479 reverse = true;
480 // fallthrough
481 case kEvenOdd_PathFill:
bsalomon@google.comd302f142011-03-03 13:54:13 +0000482 passes[0] = &gEOStencilPass;
483 if (stencilOnly) {
484 passCount = 1;
485 lastPassIsBounds = false;
486 } else {
487 passCount = 2;
488 lastPassIsBounds = true;
489 if (reverse) {
490 passes[1] = &gInvEOColorPass;
491 } else {
492 passes[1] = &gEOColorPass;
493 }
494 }
495 drawFace[0] = drawFace[1] = GrDrawTarget::kBoth_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000496 break;
497
498 case kInverseWinding_PathFill:
499 reverse = true;
500 // fallthrough
501 case kWinding_PathFill:
bsalomon@google.comd302f142011-03-03 13:54:13 +0000502 if (fSeparateStencil) {
503 if (fStencilWrapOps) {
504 passes[0] = &gWindStencilSeparateWithWrap;
505 } else {
506 passes[0] = &gWindStencilSeparateNoWrap;
507 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000508 passCount = 2;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000509 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000510 } else {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000511 if (fStencilWrapOps) {
512 passes[0] = &gWindSingleStencilWithWrapInc;
513 passes[1] = &gWindSingleStencilWithWrapDec;
514 } else {
515 passes[0] = &gWindSingleStencilNoWrapInc;
516 passes[1] = &gWindSingleStencilNoWrapDec;
517 }
518 // which is cw and which is ccw is arbitrary.
519 drawFace[0] = GrDrawTarget::kCW_DrawFace;
520 drawFace[1] = GrDrawTarget::kCCW_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000521 passCount = 3;
522 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000523 if (stencilOnly) {
524 lastPassIsBounds = false;
525 --passCount;
526 } else {
527 lastPassIsBounds = true;
528 drawFace[passCount-1] = GrDrawTarget::kBoth_DrawFace;
529 if (reverse) {
530 passes[passCount-1] = &gInvWindColorPass;
531 } else {
532 passes[passCount-1] = &gWindColorPass;
533 }
534 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000535 break;
536 default:
bsalomon@google.comee435122011-07-01 14:57:55 +0000537 GrAssert(!"Unknown path fFill!");
bsalomon@google.comffca4002011-02-22 20:34:01 +0000538 return;
539 }
540 }
541 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000542
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000543 {
544 SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath::renderPasses",
545 "verts", SkStringPrintf("%i", vert - base).c_str());
bsalomon@google.comffca4002011-02-22 20:34:01 +0000546 for (int p = 0; p < passCount; ++p) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000547 fTarget->setDrawFace(drawFace[p]);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000548 if (NULL != passes[p]) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000549 fTarget->setStencil(*passes[p]);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000550 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000551
552 if (lastPassIsBounds && (p == passCount-1)) {
553 if (!colorWritesWereDisabled) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000554 fTarget->disableState(GrDrawTarget::kNoColorWrites_StateBit);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000555 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000556 GrRect bounds;
557 if (reverse) {
558 GrAssert(NULL != fTarget->getRenderTarget());
559 // draw over the whole world.
560 bounds.setLTRB(0, 0,
561 GrIntToScalar(fTarget->getRenderTarget()->width()),
562 GrIntToScalar(fTarget->getRenderTarget()->height()));
563 GrMatrix vmi;
564 if (fTarget->getViewInverse(&vmi)) {
565 vmi.mapRect(&bounds);
566 }
567 } else {
568 bounds = fPath->getBounds();
bsalomon@google.comfc899272011-07-01 22:10:30 +0000569 bounds.offset(fTranslate);
bsalomon@google.comee435122011-07-01 14:57:55 +0000570 }
571 GrDrawTarget::AutoGeometryPush agp(fTarget);
572 fTarget->drawSimpleRect(bounds, NULL, stages);
bsalomon@google.comffca4002011-02-22 20:34:01 +0000573 } else {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000574 if (passCount > 1) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000575 fTarget->enableState(GrDrawTarget::kNoColorWrites_StateBit);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000576 }
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000577 if (fUseIndexedDraw) {
578 fTarget->drawIndexed(fPrimitiveType, 0, 0,
579 fVertexCnt, fIndexCnt);
580 } else {
581 int baseVertex = 0;
582 for (int sp = 0; sp < fSubpathCount; ++sp) {
583 fTarget->drawNonIndexed(fPrimitiveType, baseVertex,
584 fSubpathVertCount[sp]);
585 baseVertex += fSubpathVertCount[sp];
586 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000587 }
588 }
589 }
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000590 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000591}
bsalomon@google.comd302f142011-03-03 13:54:13 +0000592
bsalomon@google.comee435122011-07-01 14:57:55 +0000593void GrDefaultPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
594 this->onDrawPath(stages, false);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000595}
596
bsalomon@google.comee435122011-07-01 14:57:55 +0000597void GrDefaultPathRenderer::drawPathToStencil() {
598 GrAssert(kInverseEvenOdd_PathFill != fFill);
599 GrAssert(kInverseWinding_PathFill != fFill);
600 this->onDrawPath(0, true);
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000601}