• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
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  */
8 
9 #include "GrDefaultPathRenderer.h"
10 
11 #include "GrContext.h"
12 #include "GrDrawState.h"
13 #include "GrPathUtils.h"
14 #include "SkString.h"
15 #include "SkTrace.h"
16 
17 
GrDefaultPathRenderer(bool separateStencilSupport,bool stencilWrapOpsSupport)18 GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
19                                              bool stencilWrapOpsSupport)
20     : fSeparateStencil(separateStencilSupport)
21     , fStencilWrapOps(stencilWrapOpsSupport) {
22 }
23 
24 
25 ////////////////////////////////////////////////////////////////////////////////
26 // Stencil rules for paths
27 
28 ////// Even/Odd
29 
30 GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass,
31     kInvert_StencilOp,
32     kKeep_StencilOp,
33     kAlwaysIfInClip_StencilFunc,
34     0xffff,
35     0xffff,
36     0xffff);
37 
38 // ok not to check clip b/c stencil pass only wrote inside clip
39 GR_STATIC_CONST_SAME_STENCIL(gEOColorPass,
40     kZero_StencilOp,
41     kZero_StencilOp,
42     kNotEqual_StencilFunc,
43     0xffff,
44     0x0000,
45     0xffff);
46 
47 // have to check clip b/c outside clip will always be zero.
48 GR_STATIC_CONST_SAME_STENCIL(gInvEOColorPass,
49     kZero_StencilOp,
50     kZero_StencilOp,
51     kEqualIfInClip_StencilFunc,
52     0xffff,
53     0x0000,
54     0xffff);
55 
56 ////// Winding
57 
58 // when we have separate stencil we increment front faces / decrement back faces
59 // when we don't have wrap incr and decr we use the stencil test to simulate
60 // them.
61 
62 GR_STATIC_CONST_STENCIL(gWindStencilSeparateWithWrap,
63     kIncWrap_StencilOp,             kDecWrap_StencilOp,
64     kKeep_StencilOp,                kKeep_StencilOp,
65     kAlwaysIfInClip_StencilFunc,    kAlwaysIfInClip_StencilFunc,
66     0xffff,                         0xffff,
67     0xffff,                         0xffff,
68     0xffff,                         0xffff);
69 
70 // if inc'ing the max value, invert to make 0
71 // if dec'ing zero invert to make all ones.
72 // we can't avoid touching the stencil on both passing and
73 // failing, so we can't resctrict ourselves to the clip.
74 GR_STATIC_CONST_STENCIL(gWindStencilSeparateNoWrap,
75     kInvert_StencilOp,              kInvert_StencilOp,
76     kIncClamp_StencilOp,            kDecClamp_StencilOp,
77     kEqual_StencilFunc,             kEqual_StencilFunc,
78     0xffff,                         0xffff,
79     0xffff,                         0x0000,
80     0xffff,                         0xffff);
81 
82 // When there are no separate faces we do two passes to setup the winding rule
83 // stencil. First we draw the front faces and inc, then we draw the back faces
84 // and dec. These are same as the above two split into the incrementing and
85 // decrementing passes.
86 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc,
87     kIncWrap_StencilOp,
88     kKeep_StencilOp,
89     kAlwaysIfInClip_StencilFunc,
90     0xffff,
91     0xffff,
92     0xffff);
93 
94 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec,
95     kDecWrap_StencilOp,
96     kKeep_StencilOp,
97     kAlwaysIfInClip_StencilFunc,
98     0xffff,
99     0xffff,
100     0xffff);
101 
102 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc,
103     kInvert_StencilOp,
104     kIncClamp_StencilOp,
105     kEqual_StencilFunc,
106     0xffff,
107     0xffff,
108     0xffff);
109 
110 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec,
111     kInvert_StencilOp,
112     kDecClamp_StencilOp,
113     kEqual_StencilFunc,
114     0xffff,
115     0x0000,
116     0xffff);
117 
118 // Color passes are the same whether we use the two-sided stencil or two passes
119 
120 GR_STATIC_CONST_SAME_STENCIL(gWindColorPass,
121     kZero_StencilOp,
122     kZero_StencilOp,
123     kNonZeroIfInClip_StencilFunc,
124     0xffff,
125     0x0000,
126     0xffff);
127 
128 GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass,
129     kZero_StencilOp,
130     kZero_StencilOp,
131     kEqualIfInClip_StencilFunc,
132     0xffff,
133     0x0000,
134     0xffff);
135 
136 ////// Normal render to stencil
137 
138 // Sometimes the default path renderer can draw a path directly to the stencil
139 // buffer without having to first resolve the interior / exterior.
140 GR_STATIC_CONST_SAME_STENCIL(gDirectToStencil,
141     kZero_StencilOp,
142     kIncClamp_StencilOp,
143     kAlwaysIfInClip_StencilFunc,
144     0xffff,
145     0x0000,
146     0xffff);
147 
148 ////////////////////////////////////////////////////////////////////////////////
149 // Helpers for drawPath
150 
151 #define STENCIL_OFF     0   // Always disable stencil (even when needed)
152 
single_pass_path(const GrPath & path,GrPathFill fill)153 static inline bool single_pass_path(const GrPath& path, GrPathFill fill) {
154 #if STENCIL_OFF
155     return true;
156 #else
157     if (kEvenOdd_PathFill == fill || kWinding_PathFill == fill) {
158         return path.isConvex();
159     }
160     return false;
161 #endif
162 }
163 
requiresStencilPass(const SkPath & path,GrPathFill fill,const GrDrawTarget * target) const164 bool GrDefaultPathRenderer::requiresStencilPass(const SkPath& path,
165                                                 GrPathFill fill,
166                                                 const GrDrawTarget* target) const {
167     return !single_pass_path(path, fill);
168 }
169 
append_countour_edge_indices(GrPathFill fillType,uint16_t fanCenterIdx,uint16_t edgeV0Idx,uint16_t ** indices)170 static inline void append_countour_edge_indices(GrPathFill fillType,
171                                                 uint16_t fanCenterIdx,
172                                                 uint16_t edgeV0Idx,
173                                                 uint16_t** indices) {
174     // when drawing lines we're appending line segments along
175     // the contour. When applying the other fill rules we're
176     // drawing triangle fans around fanCenterIdx.
177     if (kHairLine_PathFill != fillType) {
178         *((*indices)++) = fanCenterIdx;
179     }
180     *((*indices)++) = edgeV0Idx;
181     *((*indices)++) = edgeV0Idx + 1;
182 }
183 
createGeom(const SkPath & path,GrPathFill fill,const GrVec * translate,GrScalar srcSpaceTol,GrDrawTarget * target,GrDrawState::StageMask stageMask,GrPrimitiveType * primType,int * vertexCnt,int * indexCnt)184 bool GrDefaultPathRenderer::createGeom(const SkPath& path,
185                                        GrPathFill fill,
186                                        const GrVec* translate,
187                                        GrScalar srcSpaceTol,
188                                        GrDrawTarget* target,
189                                        GrDrawState::StageMask stageMask,
190                                        GrPrimitiveType* primType,
191                                        int* vertexCnt,
192                                        int* indexCnt) {
193     {
194     SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
195 
196     GrScalar srcSpaceTolSqd = GrMul(srcSpaceTol, srcSpaceTol);
197     int contourCnt;
198     int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt,
199                                                   srcSpaceTol);
200 
201     if (maxPts <= 0) {
202         return false;
203     }
204     if (maxPts > ((int)SK_MaxU16 + 1)) {
205         GrPrintf("Path not rendered, too many verts (%d)\n", maxPts);
206         return false;
207     }
208 
209     GrVertexLayout layout = 0;
210     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
211         if ((1 << s) & stageMask) {
212             layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
213         }
214     }
215 
216     bool indexed = contourCnt > 1;
217 
218     int maxIdxs = 0;
219     if (kHairLine_PathFill == fill) {
220         if (indexed) {
221             maxIdxs = 2 * maxPts;
222             *primType = kLines_PrimitiveType;
223         } else {
224             *primType = kLineStrip_PrimitiveType;
225         }
226     } else {
227         if (indexed) {
228             maxIdxs = 3 * maxPts;
229             *primType = kTriangles_PrimitiveType;
230         } else {
231             *primType = kTriangleFan_PrimitiveType;
232         }
233     }
234 
235     GrPoint* base;
236     if (!target->reserveVertexSpace(layout, maxPts, (void**)&base)) {
237         return false;
238     }
239     GrAssert(NULL != base);
240     GrPoint* vert = base;
241 
242     uint16_t* idxBase = NULL;
243     uint16_t* idx = NULL;
244     uint16_t subpathIdxStart = 0;
245     if (indexed) {
246         if (!target->reserveIndexSpace(maxIdxs, (void**)&idxBase)) {
247             target->resetVertexSource();
248             return false;
249         }
250         GrAssert(NULL != idxBase);
251         idx = idxBase;
252     }
253 
254     GrPoint pts[4];
255 
256     bool first = true;
257     int subpath = 0;
258 
259     SkPath::Iter iter(path, false);
260 
261     for (;;) {
262         GrPathCmd cmd = (GrPathCmd)iter.next(pts);
263         switch (cmd) {
264             case kMove_PathCmd:
265                 if (!first) {
266                     uint16_t currIdx = (uint16_t) (vert - base);
267                     subpathIdxStart = currIdx;
268                     ++subpath;
269                 }
270                 *vert = pts[0];
271                 vert++;
272                 break;
273             case kLine_PathCmd:
274                 if (indexed) {
275                     uint16_t prevIdx = (uint16_t)(vert - base) - 1;
276                     append_countour_edge_indices(fill, subpathIdxStart,
277                                                  prevIdx, &idx);
278                 }
279                 *(vert++) = pts[1];
280                 break;
281             case kQuadratic_PathCmd: {
282                 // first pt of quad is the pt we ended on in previous step
283                 uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
284                 uint16_t numPts =  (uint16_t)
285                     GrPathUtils::generateQuadraticPoints(
286                             pts[0], pts[1], pts[2],
287                             srcSpaceTolSqd, &vert,
288                             GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
289                 if (indexed) {
290                     for (uint16_t i = 0; i < numPts; ++i) {
291                         append_countour_edge_indices(fill, subpathIdxStart,
292                                                      firstQPtIdx + i, &idx);
293                     }
294                 }
295                 break;
296             }
297             case kCubic_PathCmd: {
298                 // first pt of cubic is the pt we ended on in previous step
299                 uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
300                 uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
301                                 pts[0], pts[1], pts[2], pts[3],
302                                 srcSpaceTolSqd, &vert,
303                                 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
304                 if (indexed) {
305                     for (uint16_t i = 0; i < numPts; ++i) {
306                         append_countour_edge_indices(fill, subpathIdxStart,
307                                                      firstCPtIdx + i, &idx);
308                     }
309                 }
310                 break;
311             }
312             case kClose_PathCmd:
313                 break;
314             case kEnd_PathCmd:
315                 uint16_t currIdx = (uint16_t) (vert - base);
316                 goto FINISHED;
317         }
318         first = false;
319     }
320 FINISHED:
321     GrAssert((vert - base) <= maxPts);
322     GrAssert((idx - idxBase) <= maxIdxs);
323 
324     *vertexCnt = vert - base;
325     *indexCnt = idx - idxBase;
326 
327     if (NULL != translate &&
328         (translate->fX || translate->fY)) {
329         int count = vert - base;
330         for (int i = 0; i < count; i++) {
331             base[i].offset(translate->fX, translate->fY);
332         }
333     }
334     }
335     return true;
336 }
337 
internalDrawPath(const SkPath & path,GrPathFill fill,const GrVec * translate,GrDrawTarget * target,GrDrawState::StageMask stageMask,bool stencilOnly)338 bool GrDefaultPathRenderer::internalDrawPath(const SkPath& path,
339                                              GrPathFill fill,
340                                              const GrVec* translate,
341                                              GrDrawTarget* target,
342                                              GrDrawState::StageMask stageMask,
343                                              bool stencilOnly) {
344 
345     GrMatrix viewM = target->getDrawState().getViewMatrix();
346     GrScalar tol = GR_Scalar1;
347     tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds());
348     GrDrawState* drawState = target->drawState();
349 
350     int vertexCnt;
351     int indexCnt;
352     GrPrimitiveType primType;
353     if (!this->createGeom(path,
354                           fill,
355                           translate,
356                           tol,
357                           target,
358                           stageMask,
359                           &primType,
360                           &vertexCnt,
361                           &indexCnt)) {
362         return false;
363     }
364 
365     GrAssert(NULL != target);
366     GrDrawTarget::AutoStateRestore asr(target);
367     bool colorWritesWereDisabled = drawState->isColorWriteDisabled();
368     // face culling doesn't make sense here
369     GrAssert(GrDrawState::kBoth_DrawFace == drawState->getDrawFace());
370 
371     int                         passCount = 0;
372     const GrStencilSettings*    passes[3];
373     GrDrawState::DrawFace       drawFace[3];
374     bool                        reverse = false;
375     bool                        lastPassIsBounds;
376 
377     if (kHairLine_PathFill == fill) {
378         passCount = 1;
379         if (stencilOnly) {
380             passes[0] = &gDirectToStencil;
381         } else {
382             passes[0] = NULL;
383         }
384         lastPassIsBounds = false;
385         drawFace[0] = GrDrawState::kBoth_DrawFace;
386     } else {
387         if (single_pass_path(path, fill)) {
388             passCount = 1;
389             if (stencilOnly) {
390                 passes[0] = &gDirectToStencil;
391             } else {
392                 passes[0] = NULL;
393             }
394             drawFace[0] = GrDrawState::kBoth_DrawFace;
395             lastPassIsBounds = false;
396         } else {
397             switch (fill) {
398                 case kInverseEvenOdd_PathFill:
399                     reverse = true;
400                     // fallthrough
401                 case kEvenOdd_PathFill:
402                     passes[0] = &gEOStencilPass;
403                     if (stencilOnly) {
404                         passCount = 1;
405                         lastPassIsBounds = false;
406                     } else {
407                         passCount = 2;
408                         lastPassIsBounds = true;
409                         if (reverse) {
410                             passes[1] = &gInvEOColorPass;
411                         } else {
412                             passes[1] = &gEOColorPass;
413                         }
414                     }
415                     drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace;
416                     break;
417 
418                 case kInverseWinding_PathFill:
419                     reverse = true;
420                     // fallthrough
421                 case kWinding_PathFill:
422                     if (fSeparateStencil) {
423                         if (fStencilWrapOps) {
424                             passes[0] = &gWindStencilSeparateWithWrap;
425                         } else {
426                             passes[0] = &gWindStencilSeparateNoWrap;
427                         }
428                         passCount = 2;
429                         drawFace[0] = GrDrawState::kBoth_DrawFace;
430                     } else {
431                         if (fStencilWrapOps) {
432                             passes[0] = &gWindSingleStencilWithWrapInc;
433                             passes[1] = &gWindSingleStencilWithWrapDec;
434                         } else {
435                             passes[0] = &gWindSingleStencilNoWrapInc;
436                             passes[1] = &gWindSingleStencilNoWrapDec;
437                         }
438                         // which is cw and which is ccw is arbitrary.
439                         drawFace[0] = GrDrawState::kCW_DrawFace;
440                         drawFace[1] = GrDrawState::kCCW_DrawFace;
441                         passCount = 3;
442                     }
443                     if (stencilOnly) {
444                         lastPassIsBounds = false;
445                         --passCount;
446                     } else {
447                         lastPassIsBounds = true;
448                         drawFace[passCount-1] = GrDrawState::kBoth_DrawFace;
449                         if (reverse) {
450                             passes[passCount-1] = &gInvWindColorPass;
451                         } else {
452                             passes[passCount-1] = &gWindColorPass;
453                         }
454                     }
455                     break;
456                 default:
457                     GrAssert(!"Unknown path fFill!");
458                     return false;
459             }
460         }
461     }
462 
463     {
464     for (int p = 0; p < passCount; ++p) {
465         drawState->setDrawFace(drawFace[p]);
466         if (NULL != passes[p]) {
467             *drawState->stencil() = *passes[p];
468         }
469 
470         if (lastPassIsBounds && (p == passCount-1)) {
471             if (!colorWritesWereDisabled) {
472                 drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
473             }
474             GrRect bounds;
475             if (reverse) {
476                 GrAssert(NULL != drawState->getRenderTarget());
477                 // draw over the whole world.
478                 bounds.setLTRB(0, 0,
479                                GrIntToScalar(drawState->getRenderTarget()->width()),
480                                GrIntToScalar(drawState->getRenderTarget()->height()));
481                 GrMatrix vmi;
482                 // mapRect through persp matrix may not be correct
483                 if (!drawState->getViewMatrix().hasPerspective() &&
484                     drawState->getViewInverse(&vmi)) {
485                     vmi.mapRect(&bounds);
486                 } else {
487                     if (stageMask) {
488                         if (!drawState->getViewInverse(&vmi)) {
489                             GrPrintf("Could not invert matrix.");
490                             return false;
491                         }
492                         drawState->preConcatSamplerMatrices(stageMask, vmi);
493                     }
494                     drawState->setViewMatrix(GrMatrix::I());
495                 }
496             } else {
497                 bounds = path.getBounds();
498                 if (NULL != translate) {
499                     bounds.offset(*translate);
500                 }
501             }
502             GrDrawTarget::AutoGeometryPush agp(target);
503             target->drawSimpleRect(bounds, NULL, stageMask);
504         } else {
505             if (passCount > 1) {
506                 drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
507             }
508             if (indexCnt) {
509                 target->drawIndexed(primType, 0, 0,
510                                     vertexCnt, indexCnt);
511             } else {
512                 target->drawNonIndexed(primType, 0, vertexCnt);
513             }
514         }
515     }
516     }
517     return true;
518 }
519 
canDrawPath(const SkPath & path,GrPathFill fill,const GrDrawTarget * target,bool antiAlias) const520 bool GrDefaultPathRenderer::canDrawPath(const SkPath& path,
521                                         GrPathFill fill,
522                                         const GrDrawTarget* target,
523                                         bool antiAlias) const {
524     // this class can draw any path with any fill but doesn't do any
525     // anti-aliasing.
526     return !antiAlias;
527 }
528 
onDrawPath(const SkPath & path,GrPathFill fill,const GrVec * translate,GrDrawTarget * target,GrDrawState::StageMask stageMask,bool antiAlias)529 bool GrDefaultPathRenderer::onDrawPath(const SkPath& path,
530                                        GrPathFill fill,
531                                        const GrVec* translate,
532                                        GrDrawTarget* target,
533                                        GrDrawState::StageMask stageMask,
534                                        bool antiAlias) {
535     return this->internalDrawPath(path,
536                                   fill,
537                                   translate,
538                                   target,
539                                   stageMask,
540                                   false);
541 }
542 
drawPathToStencil(const SkPath & path,GrPathFill fill,GrDrawTarget * target)543 void GrDefaultPathRenderer::drawPathToStencil(const SkPath& path,
544                                               GrPathFill fill,
545                                               GrDrawTarget* target) {
546     GrAssert(kInverseEvenOdd_PathFill != fill);
547     GrAssert(kInverseWinding_PathFill != fill);
548     this->internalDrawPath(path, fill, NULL, target, 0, true);
549 }
550