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