• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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