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 "GrDrawState.h"
12#include "GrPathUtils.h"
13#include "SkString.h"
14#include "SkStrokeRec.h"
15#include "SkTLazy.h"
16#include "SkTraceEvent.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    SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol);
200    int contourCnt;
201    int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt,
202                                                  srcSpaceTol);
203
204    if (maxPts <= 0) {
205        return false;
206    }
207    if (maxPts > ((int)SK_MaxU16 + 1)) {
208        GrPrintf("Path not rendered, too many verts (%d)\n", maxPts);
209        return false;
210    }
211
212    bool indexed = contourCnt > 1;
213
214    const bool isHairline = stroke.isHairlineStyle();
215
216    int maxIdxs = 0;
217    if (isHairline) {
218        if (indexed) {
219            maxIdxs = 2 * maxPts;
220            *primType = kLines_GrPrimitiveType;
221        } else {
222            *primType = kLineStrip_GrPrimitiveType;
223        }
224    } else {
225        if (indexed) {
226            maxIdxs = 3 * maxPts;
227            *primType = kTriangles_GrPrimitiveType;
228        } else {
229            *primType = kTriangleFan_GrPrimitiveType;
230        }
231    }
232
233    target->drawState()->setDefaultVertexAttribs();
234    if (!arg->set(target, maxPts, maxIdxs)) {
235        return false;
236    }
237
238    uint16_t* idxBase = reinterpret_cast<uint16_t*>(arg->indices());
239    uint16_t* idx = idxBase;
240    uint16_t subpathIdxStart = 0;
241
242    SkPoint* base = reinterpret_cast<SkPoint*>(arg->vertices());
243    SkASSERT(NULL != base);
244    SkPoint* vert = base;
245
246    SkPoint pts[4];
247
248    bool first = true;
249    int subpath = 0;
250
251    SkPath::Iter iter(path, false);
252
253    for (;;) {
254        SkPath::Verb verb = iter.next(pts);
255        switch (verb) {
256            case SkPath::kConic_Verb:
257                SkASSERT(0);
258                break;
259            case SkPath::kMove_Verb:
260                if (!first) {
261                    uint16_t currIdx = (uint16_t) (vert - base);
262                    subpathIdxStart = currIdx;
263                    ++subpath;
264                }
265                *vert = pts[0];
266                vert++;
267                break;
268            case SkPath::kLine_Verb:
269                if (indexed) {
270                    uint16_t prevIdx = (uint16_t)(vert - base) - 1;
271                    append_countour_edge_indices(isHairline, subpathIdxStart,
272                                                 prevIdx, &idx);
273                }
274                *(vert++) = pts[1];
275                break;
276            case SkPath::kQuad_Verb: {
277                // first pt of quad is the pt we ended on in previous step
278                uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
279                uint16_t numPts =  (uint16_t)
280                    GrPathUtils::generateQuadraticPoints(
281                            pts[0], pts[1], pts[2],
282                            srcSpaceTolSqd, &vert,
283                            GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
284                if (indexed) {
285                    for (uint16_t i = 0; i < numPts; ++i) {
286                        append_countour_edge_indices(isHairline, subpathIdxStart,
287                                                     firstQPtIdx + i, &idx);
288                    }
289                }
290                break;
291            }
292            case SkPath::kCubic_Verb: {
293                // first pt of cubic is the pt we ended on in previous step
294                uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
295                uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
296                                pts[0], pts[1], pts[2], pts[3],
297                                srcSpaceTolSqd, &vert,
298                                GrPathUtils::cubicPointCount(pts, srcSpaceTol));
299                if (indexed) {
300                    for (uint16_t i = 0; i < numPts; ++i) {
301                        append_countour_edge_indices(isHairline, subpathIdxStart,
302                                                     firstCPtIdx + i, &idx);
303                    }
304                }
305                break;
306            }
307            case SkPath::kClose_Verb:
308                break;
309            case SkPath::kDone_Verb:
310             // uint16_t currIdx = (uint16_t) (vert - base);
311                goto FINISHED;
312        }
313        first = false;
314    }
315FINISHED:
316    SkASSERT((vert - base) <= maxPts);
317    SkASSERT((idx - idxBase) <= maxIdxs);
318
319    *vertexCnt = static_cast<int>(vert - base);
320    *indexCnt = static_cast<int>(idx - idxBase);
321
322    }
323    return true;
324}
325
326bool GrDefaultPathRenderer::internalDrawPath(const SkPath& path,
327                                             const SkStrokeRec& origStroke,
328                                             GrDrawTarget* target,
329                                             bool stencilOnly) {
330
331    SkMatrix viewM = target->getDrawState().getViewMatrix();
332    SkTCopyOnFirstWrite<SkStrokeRec> stroke(origStroke);
333
334    SkScalar hairlineCoverage;
335    if (IsStrokeHairlineOrEquivalent(*stroke, target->getDrawState().getViewMatrix(),
336                                     &hairlineCoverage)) {
337        uint8_t newCoverage = SkScalarRoundToInt(hairlineCoverage *
338                                                 target->getDrawState().getCoverage());
339        target->drawState()->setCoverage(newCoverage);
340
341        if (!stroke->isHairlineStyle()) {
342            stroke.writable()->setHairlineStyle();
343        }
344    }
345
346    SkScalar tol = SK_Scalar1;
347    tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds());
348
349    int vertexCnt;
350    int indexCnt;
351    GrPrimitiveType primType;
352    GrDrawTarget::AutoReleaseGeometry arg;
353    if (!this->createGeom(path,
354                          *stroke,
355                          tol,
356                          target,
357                          &primType,
358                          &vertexCnt,
359                          &indexCnt,
360                          &arg)) {
361        return false;
362    }
363
364    SkASSERT(NULL != target);
365    GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit);
366    GrDrawState* drawState = target->drawState();
367    bool colorWritesWereDisabled = drawState->isColorWriteDisabled();
368    // face culling doesn't make sense here
369    SkASSERT(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 (stroke->isHairlineStyle()) {
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, *stroke)) {
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 (path.getFillType()) {
398                case SkPath::kInverseEvenOdd_FillType:
399                    reverse = true;
400                    // fallthrough
401                case SkPath::kEvenOdd_FillType:
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 SkPath::kInverseWinding_FillType:
419                    reverse = true;
420                    // fallthrough
421                case SkPath::kWinding_FillType:
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                    SkDEBUGFAIL("Unknown path fFill!");
458                    return false;
459            }
460        }
461    }
462
463    SkRect devBounds;
464    GetPathDevBounds(path, drawState->getRenderTarget(), viewM, &devBounds);
465
466    for (int p = 0; p < passCount; ++p) {
467        drawState->setDrawFace(drawFace[p]);
468        if (NULL != passes[p]) {
469            *drawState->stencil() = *passes[p];
470        }
471
472        if (lastPassIsBounds && (p == passCount-1)) {
473            if (!colorWritesWereDisabled) {
474                drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
475            }
476            SkRect bounds;
477            GrDrawState::AutoViewMatrixRestore avmr;
478            if (reverse) {
479                SkASSERT(NULL != drawState->getRenderTarget());
480                // draw over the dev bounds (which will be the whole dst surface for inv fill).
481                bounds = devBounds;
482                SkMatrix vmi;
483                // mapRect through persp matrix may not be correct
484                if (!drawState->getViewMatrix().hasPerspective() &&
485                    drawState->getViewInverse(&vmi)) {
486                    vmi.mapRect(&bounds);
487                } else {
488                    avmr.setIdentity(drawState);
489                }
490            } else {
491                bounds = path.getBounds();
492            }
493            GrDrawTarget::AutoGeometryAndStatePush agasp(target, GrDrawTarget::kPreserve_ASRInit);
494            target->drawSimpleRect(bounds, NULL);
495        } else {
496            if (passCount > 1) {
497                drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
498            }
499            if (indexCnt) {
500                target->drawIndexed(primType, 0, 0,
501                                    vertexCnt, indexCnt, &devBounds);
502            } else {
503                target->drawNonIndexed(primType, 0, vertexCnt, &devBounds);
504            }
505        }
506    }
507    return true;
508}
509
510bool GrDefaultPathRenderer::canDrawPath(const SkPath& path,
511                                        const SkStrokeRec& stroke,
512                                        const GrDrawTarget* target,
513                                        bool antiAlias) const {
514    // this class can draw any path with any fill but doesn't do any anti-aliasing.
515
516    return !antiAlias &&
517        (stroke.isFillStyle() ||
518         IsStrokeHairlineOrEquivalent(stroke, target->getDrawState().getViewMatrix(), NULL));
519}
520
521bool GrDefaultPathRenderer::onDrawPath(const SkPath& path,
522                                       const SkStrokeRec& stroke,
523                                       GrDrawTarget* target,
524                                       bool antiAlias) {
525    return this->internalDrawPath(path,
526                                  stroke,
527                                  target,
528                                  false);
529}
530
531void GrDefaultPathRenderer::onStencilPath(const SkPath& path,
532                                          const SkStrokeRec& stroke,
533                                          GrDrawTarget* target) {
534    SkASSERT(SkPath::kInverseEvenOdd_FillType != path.getFillType());
535    SkASSERT(SkPath::kInverseWinding_FillType != path.getFillType());
536    this->internalDrawPath(path, stroke, target, true);
537}
538