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