1 #include "GrPathRenderer.h"
2
3 #include "GrPoint.h"
4 #include "GrDrawTarget.h"
5 #include "GrPathUtils.h"
6 #include "GrMemory.h"
7 #include "GrTexture.h"
8
GrDefaultPathRenderer(bool separateStencilSupport,bool stencilWrapOpsSupport)9 GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
10 bool stencilWrapOpsSupport)
11 : fSeparateStencil(separateStencilSupport),
12 fStencilWrapOps(stencilWrapOpsSupport) {
13
14 }
15
16 ////////////////////////////////////////////////////////////////////////////////
17 // Stencil rules for paths
18
19 ////// Even/Odd
20
21 static const GrStencilSettings gEOStencilPass = {
22 kInvert_StencilOp, kInvert_StencilOp,
23 kKeep_StencilOp, kKeep_StencilOp,
24 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
25 0xffffffff, 0xffffffff,
26 0xffffffff, 0xffffffff,
27 0xffffffff, 0xffffffff
28 };
29
30 // ok not to check clip b/c stencil pass only wrote inside clip
31 static const GrStencilSettings gEOColorPass = {
32 kZero_StencilOp, kZero_StencilOp,
33 kZero_StencilOp, kZero_StencilOp,
34 kNotEqual_StencilFunc, kNotEqual_StencilFunc,
35 0xffffffff, 0xffffffff,
36 0x0, 0x0,
37 0xffffffff, 0xffffffff
38 };
39
40 // have to check clip b/c outside clip will always be zero.
41 static const GrStencilSettings gInvEOColorPass = {
42 kZero_StencilOp, kZero_StencilOp,
43 kZero_StencilOp, kZero_StencilOp,
44 kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
45 0xffffffff, 0xffffffff,
46 0x0, 0x0,
47 0xffffffff, 0xffffffff
48 };
49
50 ////// Winding
51
52 // when we have separate stencil we increment front faces / decrement back faces
53 // when we don't have wrap incr and decr we use the stencil test to simulate
54 // them.
55
56 static const GrStencilSettings gWindStencilSeparateWithWrap = {
57 kIncWrap_StencilOp, kDecWrap_StencilOp,
58 kKeep_StencilOp, kKeep_StencilOp,
59 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
60 0xffffffff, 0xffffffff,
61 0xffffffff, 0xffffffff,
62 0xffffffff, 0xffffffff
63 };
64
65 // if inc'ing the max value, invert to make 0
66 // if dec'ing zero invert to make all ones.
67 // we can't avoid touching the stencil on both passing and
68 // failing, so we can't resctrict ourselves to the clip.
69 static const GrStencilSettings gWindStencilSeparateNoWrap = {
70 kInvert_StencilOp, kInvert_StencilOp,
71 kIncClamp_StencilOp, kDecClamp_StencilOp,
72 kEqual_StencilFunc, kEqual_StencilFunc,
73 0xffffffff, 0xffffffff,
74 0xffffffff, 0x0,
75 0xffffffff, 0xffffffff
76 };
77
78 // When there are no separate faces we do two passes to setup the winding rule
79 // stencil. First we draw the front faces and inc, then we draw the back faces
80 // and dec. These are same as the above two split into the incrementing and
81 // decrementing passes.
82 static const GrStencilSettings gWindSingleStencilWithWrapInc = {
83 kIncWrap_StencilOp, kIncWrap_StencilOp,
84 kKeep_StencilOp, kKeep_StencilOp,
85 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
86 0xffffffff, 0xffffffff,
87 0xffffffff, 0xffffffff,
88 0xffffffff, 0xffffffff
89 };
90 static const GrStencilSettings gWindSingleStencilWithWrapDec = {
91 kDecWrap_StencilOp, kDecWrap_StencilOp,
92 kKeep_StencilOp, kKeep_StencilOp,
93 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
94 0xffffffff, 0xffffffff,
95 0xffffffff, 0xffffffff,
96 0xffffffff, 0xffffffff
97 };
98 static const GrStencilSettings gWindSingleStencilNoWrapInc = {
99 kInvert_StencilOp, kInvert_StencilOp,
100 kIncClamp_StencilOp, kIncClamp_StencilOp,
101 kEqual_StencilFunc, kEqual_StencilFunc,
102 0xffffffff, 0xffffffff,
103 0xffffffff, 0xffffffff,
104 0xffffffff, 0xffffffff
105 };
106 static const GrStencilSettings gWindSingleStencilNoWrapDec = {
107 kInvert_StencilOp, kInvert_StencilOp,
108 kDecClamp_StencilOp, kDecClamp_StencilOp,
109 kEqual_StencilFunc, kEqual_StencilFunc,
110 0xffffffff, 0xffffffff,
111 0x0, 0x0,
112 0xffffffff, 0xffffffff
113 };
114
115 static const GrStencilSettings gWindColorPass = {
116 kZero_StencilOp, kZero_StencilOp,
117 kZero_StencilOp, kZero_StencilOp,
118 kNonZeroIfInClip_StencilFunc, kNonZeroIfInClip_StencilFunc,
119 0xffffffff, 0xffffffff,
120 0x0, 0x0,
121 0xffffffff, 0xffffffff
122 };
123
124 static const GrStencilSettings gInvWindColorPass = {
125 kZero_StencilOp, kZero_StencilOp,
126 kZero_StencilOp, kZero_StencilOp,
127 kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
128 0xffffffff, 0xffffffff,
129 0x0, 0x0,
130 0xffffffff, 0xffffffff
131 };
132
133 ////// Normal render to stencil
134
135 // Sometimes the default path renderer can draw a path directly to the stencil
136 // buffer without having to first resolve the interior / exterior.
137 static const GrStencilSettings gDirectToStencil = {
138 kZero_StencilOp, kZero_StencilOp,
139 kIncClamp_StencilOp, kIncClamp_StencilOp,
140 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
141 0xffffffff, 0xffffffff,
142 0x0, 0x0,
143 0xffffffff, 0xffffffff
144 };
145
146 ////////////////////////////////////////////////////////////////////////////////
147 // Helpers for drawPath
148
getConvexHint(const SkPath & path)149 static GrConvexHint getConvexHint(const SkPath& path) {
150 return path.isConvex() ? kConvex_ConvexHint : kConcave_ConvexHint;
151 }
152
153 #define STENCIL_OFF 0 // Always disable stencil (even when needed)
154
single_pass_path(const GrDrawTarget & target,const GrPath & path,GrPathFill fill)155 static inline bool single_pass_path(const GrDrawTarget& target,
156 const GrPath& path,
157 GrPathFill fill) {
158 #if STENCIL_OFF
159 return true;
160 #else
161 if (kEvenOdd_PathFill == fill) {
162 GrConvexHint hint = getConvexHint(path);
163 return hint == kConvex_ConvexHint ||
164 hint == kNonOverlappingConvexPieces_ConvexHint;
165 } else if (kWinding_PathFill == fill) {
166 GrConvexHint hint = getConvexHint(path);
167 return hint == kConvex_ConvexHint ||
168 hint == kNonOverlappingConvexPieces_ConvexHint ||
169 (hint == kSameWindingConvexPieces_ConvexHint &&
170 target.canDisableBlend() && !target.isDitherState());
171
172 }
173 return false;
174 #endif
175 }
176
requiresStencilPass(const GrDrawTarget * target,const GrPath & path,GrPathFill fill) const177 bool GrDefaultPathRenderer::requiresStencilPass(const GrDrawTarget* target,
178 const GrPath& path,
179 GrPathFill fill) const {
180 return !single_pass_path(*target, path, fill);
181 }
182
onDrawPath(GrDrawTarget * target,GrDrawTarget::StageBitfield stages,const GrPath & path,GrPathFill fill,const GrPoint * translate,bool stencilOnly)183 void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
184 GrDrawTarget::StageBitfield stages,
185 const GrPath& path,
186 GrPathFill fill,
187 const GrPoint* translate,
188 bool stencilOnly) {
189
190 GrDrawTarget::AutoStateRestore asr(target);
191 bool colorWritesWereDisabled = target->isColorWriteDisabled();
192 // face culling doesn't make sense here
193 GrAssert(GrDrawTarget::kBoth_DrawFace == target->getDrawFace());
194
195 GrMatrix viewM = target->getViewMatrix();
196 // In order to tesselate the path we get a bound on how much the matrix can
197 // stretch when mapping to screen coordinates.
198 GrScalar stretch = viewM.getMaxStretch();
199 bool useStretch = stretch > 0;
200 GrScalar tol = GrPathUtils::gTolerance;
201
202 if (!useStretch) {
203 // TODO: deal with perspective in some better way.
204 tol /= 10;
205 } else {
206 tol = GrScalarDiv(tol, stretch);
207 }
208 GrScalar tolSqd = GrMul(tol, tol);
209
210 int subpathCnt;
211 int maxPts = GrPathUtils::worstCasePointCount(path, &subpathCnt, tol);
212
213 GrVertexLayout layout = 0;
214 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
215 if ((1 << s) & stages) {
216 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
217 }
218 }
219
220 // add 4 to hold the bounding rect
221 GrDrawTarget::AutoReleaseGeometry arg(target, layout, maxPts + 4, 0);
222
223 GrPoint* base = (GrPoint*) arg.vertices();
224 GrPoint* vert = base;
225 GrPoint* subpathBase = base;
226
227 GrAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
228
229 // TODO: use primitve restart if available rather than multiple draws
230 GrPrimitiveType type;
231 int passCount = 0;
232 const GrStencilSettings* passes[3];
233 GrDrawTarget::DrawFace drawFace[3];
234 bool reverse = false;
235 bool lastPassIsBounds;
236
237 if (kHairLine_PathFill == fill) {
238 type = kLineStrip_PrimitiveType;
239 passCount = 1;
240 if (stencilOnly) {
241 passes[0] = &gDirectToStencil;
242 } else {
243 passes[0] = NULL;
244 }
245 lastPassIsBounds = false;
246 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
247 } else {
248 type = kTriangleFan_PrimitiveType;
249 if (single_pass_path(*target, path, fill)) {
250 passCount = 1;
251 if (stencilOnly) {
252 passes[0] = &gDirectToStencil;
253 } else {
254 passes[0] = NULL;
255 }
256 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
257 lastPassIsBounds = false;
258 } else {
259 switch (fill) {
260 case kInverseEvenOdd_PathFill:
261 reverse = true;
262 // fallthrough
263 case kEvenOdd_PathFill:
264 passes[0] = &gEOStencilPass;
265 if (stencilOnly) {
266 passCount = 1;
267 lastPassIsBounds = false;
268 } else {
269 passCount = 2;
270 lastPassIsBounds = true;
271 if (reverse) {
272 passes[1] = &gInvEOColorPass;
273 } else {
274 passes[1] = &gEOColorPass;
275 }
276 }
277 drawFace[0] = drawFace[1] = GrDrawTarget::kBoth_DrawFace;
278 break;
279
280 case kInverseWinding_PathFill:
281 reverse = true;
282 // fallthrough
283 case kWinding_PathFill:
284 if (fSeparateStencil) {
285 if (fStencilWrapOps) {
286 passes[0] = &gWindStencilSeparateWithWrap;
287 } else {
288 passes[0] = &gWindStencilSeparateNoWrap;
289 }
290 passCount = 2;
291 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
292 } else {
293 if (fStencilWrapOps) {
294 passes[0] = &gWindSingleStencilWithWrapInc;
295 passes[1] = &gWindSingleStencilWithWrapDec;
296 } else {
297 passes[0] = &gWindSingleStencilNoWrapInc;
298 passes[1] = &gWindSingleStencilNoWrapDec;
299 }
300 // which is cw and which is ccw is arbitrary.
301 drawFace[0] = GrDrawTarget::kCW_DrawFace;
302 drawFace[1] = GrDrawTarget::kCCW_DrawFace;
303 passCount = 3;
304 }
305 if (stencilOnly) {
306 lastPassIsBounds = false;
307 --passCount;
308 } else {
309 lastPassIsBounds = true;
310 drawFace[passCount-1] = GrDrawTarget::kBoth_DrawFace;
311 if (reverse) {
312 passes[passCount-1] = &gInvWindColorPass;
313 } else {
314 passes[passCount-1] = &gWindColorPass;
315 }
316 }
317 break;
318 default:
319 GrAssert(!"Unknown path fill!");
320 return;
321 }
322 }
323 }
324
325 GrPoint pts[4];
326
327 bool first = true;
328 int subpath = 0;
329
330 SkPath::Iter iter(path, false);
331
332 for (;;) {
333 GrPathCmd cmd = (GrPathCmd)iter.next(pts);
334 switch (cmd) {
335 case kMove_PathCmd:
336 if (!first) {
337 subpathVertCount[subpath] = vert-subpathBase;
338 subpathBase = vert;
339 ++subpath;
340 }
341 *vert = pts[0];
342 vert++;
343 break;
344 case kLine_PathCmd:
345 *vert = pts[1];
346 vert++;
347 break;
348 case kQuadratic_PathCmd: {
349 GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
350 tolSqd, &vert,
351 GrPathUtils::quadraticPointCount(pts, tol));
352 break;
353 }
354 case kCubic_PathCmd: {
355 GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
356 tolSqd, &vert,
357 GrPathUtils::cubicPointCount(pts, tol));
358 break;
359 }
360 case kClose_PathCmd:
361 break;
362 case kEnd_PathCmd:
363 subpathVertCount[subpath] = vert-subpathBase;
364 ++subpath; // this could be only in debug
365 goto FINISHED;
366 }
367 first = false;
368 }
369 FINISHED:
370 GrAssert(subpath == subpathCnt);
371 GrAssert((vert - base) <= maxPts);
372
373 if (translate) {
374 int count = vert - base;
375 for (int i = 0; i < count; i++) {
376 base[i].offset(translate->fX, translate->fY);
377 }
378 }
379
380 // if we're stenciling we will follow with a pass that draws
381 // a bounding rect to set the color. We're stenciling when
382 // passCount > 1.
383 const int& boundVertexStart = maxPts;
384 GrPoint* boundsVerts = base + boundVertexStart;
385 if (lastPassIsBounds) {
386 GrRect bounds;
387 if (reverse) {
388 GrAssert(NULL != target->getRenderTarget());
389 // draw over the whole world.
390 bounds.setLTRB(0, 0,
391 GrIntToScalar(target->getRenderTarget()->width()),
392 GrIntToScalar(target->getRenderTarget()->height()));
393 GrMatrix vmi;
394 if (target->getViewInverse(&vmi)) {
395 vmi.mapRect(&bounds);
396 }
397 } else {
398 bounds.setBounds((GrPoint*)base, vert - base);
399 }
400 boundsVerts[0].setRectFan(bounds.fLeft, bounds.fTop, bounds.fRight,
401 bounds.fBottom);
402 }
403
404 for (int p = 0; p < passCount; ++p) {
405 target->setDrawFace(drawFace[p]);
406 if (NULL != passes[p]) {
407 target->setStencil(*passes[p]);
408 }
409
410 if (lastPassIsBounds && (p == passCount-1)) {
411 if (!colorWritesWereDisabled) {
412 target->disableState(GrDrawTarget::kNoColorWrites_StateBit);
413 }
414 target->drawNonIndexed(kTriangleFan_PrimitiveType,
415 boundVertexStart, 4);
416
417 } else {
418 if (passCount > 1) {
419 target->enableState(GrDrawTarget::kNoColorWrites_StateBit);
420 }
421 int baseVertex = 0;
422 for (int sp = 0; sp < subpathCnt; ++sp) {
423 target->drawNonIndexed(type,
424 baseVertex,
425 subpathVertCount[sp]);
426 baseVertex += subpathVertCount[sp];
427 }
428 }
429 }
430 }
431
drawPath(GrDrawTarget * target,GrDrawTarget::StageBitfield stages,const GrPath & path,GrPathFill fill,const GrPoint * translate)432 void GrDefaultPathRenderer::drawPath(GrDrawTarget* target,
433 GrDrawTarget::StageBitfield stages,
434 const GrPath& path,
435 GrPathFill fill,
436 const GrPoint* translate) {
437 this->onDrawPath(target, stages, path, fill, translate, false);
438 }
439
drawPathToStencil(GrDrawTarget * target,const GrPath & path,GrPathFill fill,const GrPoint * translate)440 void GrDefaultPathRenderer::drawPathToStencil(GrDrawTarget* target,
441 const GrPath& path,
442 GrPathFill fill,
443 const GrPoint* translate) {
444 GrAssert(kInverseEvenOdd_PathFill != fill);
445 GrAssert(kInverseWinding_PathFill != fill);
446 this->onDrawPath(target, 0, path, fill, translate, true);
447 }
448