GrDefaultPathRenderer.cpp revision 2f2d1306ec2bc6604e1ad7815473668cb8e0a1f8
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::kMove_Verb:
259                if (!first) {
260                    uint16_t currIdx = (uint16_t) (vert - base);
261                    subpathIdxStart = currIdx;
262                    ++subpath;
263                }
264                *vert = pts[0];
265                vert++;
266                break;
267            case SkPath::kLine_Verb:
268                if (indexed) {
269                    uint16_t prevIdx = (uint16_t)(vert - base) - 1;
270                    append_countour_edge_indices(isHairline, subpathIdxStart,
271                                                 prevIdx, &idx);
272                }
273                *(vert++) = pts[1];
274                break;
275            case SkPath::kQuad_Verb: {
276                // first pt of quad is the pt we ended on in previous step
277                uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
278                uint16_t numPts =  (uint16_t)
279                    GrPathUtils::generateQuadraticPoints(
280                            pts[0], pts[1], pts[2],
281                            srcSpaceTolSqd, &vert,
282                            GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
283                if (indexed) {
284                    for (uint16_t i = 0; i < numPts; ++i) {
285                        append_countour_edge_indices(isHairline, subpathIdxStart,
286                                                     firstQPtIdx + i, &idx);
287                    }
288                }
289                break;
290            }
291            case SkPath::kCubic_Verb: {
292                // first pt of cubic is the pt we ended on in previous step
293                uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
294                uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
295                                pts[0], pts[1], pts[2], pts[3],
296                                srcSpaceTolSqd, &vert,
297                                GrPathUtils::cubicPointCount(pts, srcSpaceTol));
298                if (indexed) {
299                    for (uint16_t i = 0; i < numPts; ++i) {
300                        append_countour_edge_indices(isHairline, subpathIdxStart,
301                                                     firstCPtIdx + i, &idx);
302                    }
303                }
304                break;
305            }
306            case SkPath::kClose_Verb:
307                break;
308            case SkPath::kDone_Verb:
309             // uint16_t currIdx = (uint16_t) (vert - base);
310                goto FINISHED;
311        }
312        first = false;
313    }
314FINISHED:
315    GrAssert((vert - base) <= maxPts);
316    GrAssert((idx - idxBase) <= maxIdxs);
317
318    *vertexCnt = vert - base;
319    *indexCnt = idx - idxBase;
320
321    }
322    return true;
323}
324
325bool GrDefaultPathRenderer::internalDrawPath(const SkPath& path,
326                                             const SkStrokeRec& stroke,
327                                             GrDrawTarget* target,
328                                             bool stencilOnly) {
329
330    SkMatrix viewM = target->getDrawState().getViewMatrix();
331    SkScalar tol = SK_Scalar1;
332    tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds());
333
334    int vertexCnt;
335    int indexCnt;
336    GrPrimitiveType primType;
337    GrDrawTarget::AutoReleaseGeometry arg;
338    if (!this->createGeom(path,
339                          stroke,
340                          tol,
341                          target,
342                          &primType,
343                          &vertexCnt,
344                          &indexCnt,
345                          &arg)) {
346        return false;
347    }
348
349    GrAssert(NULL != target);
350    GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit);
351    GrDrawState* drawState = target->drawState();
352    bool colorWritesWereDisabled = drawState->isColorWriteDisabled();
353    // face culling doesn't make sense here
354    GrAssert(GrDrawState::kBoth_DrawFace == drawState->getDrawFace());
355
356    int                         passCount = 0;
357    const GrStencilSettings*    passes[3];
358    GrDrawState::DrawFace       drawFace[3];
359    bool                        reverse = false;
360    bool                        lastPassIsBounds;
361
362    if (stroke.isHairlineStyle()) {
363        passCount = 1;
364        if (stencilOnly) {
365            passes[0] = &gDirectToStencil;
366        } else {
367            passes[0] = NULL;
368        }
369        lastPassIsBounds = false;
370        drawFace[0] = GrDrawState::kBoth_DrawFace;
371    } else {
372        if (single_pass_path(path, stroke)) {
373            passCount = 1;
374            if (stencilOnly) {
375                passes[0] = &gDirectToStencil;
376            } else {
377                passes[0] = NULL;
378            }
379            drawFace[0] = GrDrawState::kBoth_DrawFace;
380            lastPassIsBounds = false;
381        } else {
382            switch (path.getFillType()) {
383                case SkPath::kInverseEvenOdd_FillType:
384                    reverse = true;
385                    // fallthrough
386                case SkPath::kEvenOdd_FillType:
387                    passes[0] = &gEOStencilPass;
388                    if (stencilOnly) {
389                        passCount = 1;
390                        lastPassIsBounds = false;
391                    } else {
392                        passCount = 2;
393                        lastPassIsBounds = true;
394                        if (reverse) {
395                            passes[1] = &gInvEOColorPass;
396                        } else {
397                            passes[1] = &gEOColorPass;
398                        }
399                    }
400                    drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace;
401                    break;
402
403                case SkPath::kInverseWinding_FillType:
404                    reverse = true;
405                    // fallthrough
406                case SkPath::kWinding_FillType:
407                    if (fSeparateStencil) {
408                        if (fStencilWrapOps) {
409                            passes[0] = &gWindStencilSeparateWithWrap;
410                        } else {
411                            passes[0] = &gWindStencilSeparateNoWrap;
412                        }
413                        passCount = 2;
414                        drawFace[0] = GrDrawState::kBoth_DrawFace;
415                    } else {
416                        if (fStencilWrapOps) {
417                            passes[0] = &gWindSingleStencilWithWrapInc;
418                            passes[1] = &gWindSingleStencilWithWrapDec;
419                        } else {
420                            passes[0] = &gWindSingleStencilNoWrapInc;
421                            passes[1] = &gWindSingleStencilNoWrapDec;
422                        }
423                        // which is cw and which is ccw is arbitrary.
424                        drawFace[0] = GrDrawState::kCW_DrawFace;
425                        drawFace[1] = GrDrawState::kCCW_DrawFace;
426                        passCount = 3;
427                    }
428                    if (stencilOnly) {
429                        lastPassIsBounds = false;
430                        --passCount;
431                    } else {
432                        lastPassIsBounds = true;
433                        drawFace[passCount-1] = GrDrawState::kBoth_DrawFace;
434                        if (reverse) {
435                            passes[passCount-1] = &gInvWindColorPass;
436                        } else {
437                            passes[passCount-1] = &gWindColorPass;
438                        }
439                    }
440                    break;
441                default:
442                    GrAssert(!"Unknown path fFill!");
443                    return false;
444            }
445        }
446    }
447
448    SkRect devBounds;
449    GetPathDevBounds(path, drawState->getRenderTarget(), viewM, &devBounds);
450
451    for (int p = 0; p < passCount; ++p) {
452        drawState->setDrawFace(drawFace[p]);
453        if (NULL != passes[p]) {
454            *drawState->stencil() = *passes[p];
455        }
456
457        if (lastPassIsBounds && (p == passCount-1)) {
458            if (!colorWritesWereDisabled) {
459                drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
460            }
461            GrRect bounds;
462            GrDrawState::AutoDeviceCoordDraw adcd;
463            if (reverse) {
464                GrAssert(NULL != drawState->getRenderTarget());
465                // draw over the dev bounds (which will be the whole dst surface for inv fill).
466                bounds = devBounds;
467                SkMatrix vmi;
468                // mapRect through persp matrix may not be correct
469                if (!drawState->getViewMatrix().hasPerspective() &&
470                    drawState->getViewInverse(&vmi)) {
471                    vmi.mapRect(&bounds);
472                } else {
473                    adcd.set(drawState);
474                }
475            } else {
476                bounds = path.getBounds();
477            }
478            GrDrawTarget::AutoGeometryAndStatePush agasp(target, GrDrawTarget::kPreserve_ASRInit);
479            target->drawSimpleRect(bounds, NULL);
480        } else {
481            if (passCount > 1) {
482                drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
483            }
484            if (indexCnt) {
485                target->drawIndexed(primType, 0, 0,
486                                    vertexCnt, indexCnt, &devBounds);
487            } else {
488                target->drawNonIndexed(primType, 0, vertexCnt, &devBounds);
489            }
490        }
491    }
492    return true;
493}
494
495bool GrDefaultPathRenderer::canDrawPath(const SkPath& path,
496                                        const SkStrokeRec& stroke,
497                                        const GrDrawTarget* target,
498                                        bool antiAlias) const {
499    // this class can draw any path with any fill but doesn't do any anti-aliasing.
500    return (stroke.isFillStyle() || stroke.isHairlineStyle()) && !antiAlias;
501}
502
503bool GrDefaultPathRenderer::onDrawPath(const SkPath& path,
504                                       const SkStrokeRec& stroke,
505                                       GrDrawTarget* target,
506                                       bool antiAlias) {
507    return this->internalDrawPath(path,
508                                  stroke,
509                                  target,
510                                  false);
511}
512
513void GrDefaultPathRenderer::onStencilPath(const SkPath& path,
514                                          const SkStrokeRec& stroke,
515                                          GrDrawTarget* target) {
516    GrAssert(SkPath::kInverseEvenOdd_FillType != path.getFillType());
517    GrAssert(SkPath::kInverseWinding_FillType != path.getFillType());
518    this->internalDrawPath(path, stroke, target, true);
519}
520