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 "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    SkASSERT(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    SkASSERT((vert - base) <= maxPts);
319    SkASSERT((idx - idxBase) <= maxIdxs);
320
321    *vertexCnt = static_cast<int>(vert - base);
322    *indexCnt = static_cast<int>(idx - idxBase);
323
324    }
325    return true;
326}
327
328bool GrDefaultPathRenderer::internalDrawPath(const SkPath& path,
329                                             const SkStrokeRec& origStroke,
330                                             GrDrawTarget* target,
331                                             bool stencilOnly) {
332
333    SkMatrix viewM = target->getDrawState().getViewMatrix();
334    SkTCopyOnFirstWrite<SkStrokeRec> stroke(origStroke);
335
336    SkScalar hairlineCoverage;
337    if (IsStrokeHairlineOrEquivalent(*stroke, target->getDrawState().getViewMatrix(),
338                                     &hairlineCoverage)) {
339        uint8_t newCoverage = SkScalarRoundToInt(hairlineCoverage *
340                                                 target->getDrawState().getCoverage());
341        target->drawState()->setCoverage(newCoverage);
342
343        if (!stroke->isHairlineStyle()) {
344            stroke.writable()->setHairlineStyle();
345        }
346    }
347
348    SkScalar tol = SK_Scalar1;
349    tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds());
350
351    int vertexCnt;
352    int indexCnt;
353    GrPrimitiveType primType;
354    GrDrawTarget::AutoReleaseGeometry arg;
355    if (!this->createGeom(path,
356                          *stroke,
357                          tol,
358                          target,
359                          &primType,
360                          &vertexCnt,
361                          &indexCnt,
362                          &arg)) {
363        return false;
364    }
365
366    SkASSERT(NULL != target);
367    GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit);
368    GrDrawState* drawState = target->drawState();
369    bool colorWritesWereDisabled = drawState->isColorWriteDisabled();
370    // face culling doesn't make sense here
371    SkASSERT(GrDrawState::kBoth_DrawFace == drawState->getDrawFace());
372
373    int                         passCount = 0;
374    const GrStencilSettings*    passes[3];
375    GrDrawState::DrawFace       drawFace[3];
376    bool                        reverse = false;
377    bool                        lastPassIsBounds;
378
379    if (stroke->isHairlineStyle()) {
380        passCount = 1;
381        if (stencilOnly) {
382            passes[0] = &gDirectToStencil;
383        } else {
384            passes[0] = NULL;
385        }
386        lastPassIsBounds = false;
387        drawFace[0] = GrDrawState::kBoth_DrawFace;
388    } else {
389        if (single_pass_path(path, *stroke)) {
390            passCount = 1;
391            if (stencilOnly) {
392                passes[0] = &gDirectToStencil;
393            } else {
394                passes[0] = NULL;
395            }
396            drawFace[0] = GrDrawState::kBoth_DrawFace;
397            lastPassIsBounds = false;
398        } else {
399            switch (path.getFillType()) {
400                case SkPath::kInverseEvenOdd_FillType:
401                    reverse = true;
402                    // fallthrough
403                case SkPath::kEvenOdd_FillType:
404                    passes[0] = &gEOStencilPass;
405                    if (stencilOnly) {
406                        passCount = 1;
407                        lastPassIsBounds = false;
408                    } else {
409                        passCount = 2;
410                        lastPassIsBounds = true;
411                        if (reverse) {
412                            passes[1] = &gInvEOColorPass;
413                        } else {
414                            passes[1] = &gEOColorPass;
415                        }
416                    }
417                    drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace;
418                    break;
419
420                case SkPath::kInverseWinding_FillType:
421                    reverse = true;
422                    // fallthrough
423                case SkPath::kWinding_FillType:
424                    if (fSeparateStencil) {
425                        if (fStencilWrapOps) {
426                            passes[0] = &gWindStencilSeparateWithWrap;
427                        } else {
428                            passes[0] = &gWindStencilSeparateNoWrap;
429                        }
430                        passCount = 2;
431                        drawFace[0] = GrDrawState::kBoth_DrawFace;
432                    } else {
433                        if (fStencilWrapOps) {
434                            passes[0] = &gWindSingleStencilWithWrapInc;
435                            passes[1] = &gWindSingleStencilWithWrapDec;
436                        } else {
437                            passes[0] = &gWindSingleStencilNoWrapInc;
438                            passes[1] = &gWindSingleStencilNoWrapDec;
439                        }
440                        // which is cw and which is ccw is arbitrary.
441                        drawFace[0] = GrDrawState::kCW_DrawFace;
442                        drawFace[1] = GrDrawState::kCCW_DrawFace;
443                        passCount = 3;
444                    }
445                    if (stencilOnly) {
446                        lastPassIsBounds = false;
447                        --passCount;
448                    } else {
449                        lastPassIsBounds = true;
450                        drawFace[passCount-1] = GrDrawState::kBoth_DrawFace;
451                        if (reverse) {
452                            passes[passCount-1] = &gInvWindColorPass;
453                        } else {
454                            passes[passCount-1] = &gWindColorPass;
455                        }
456                    }
457                    break;
458                default:
459                    SkDEBUGFAIL("Unknown path fFill!");
460                    return false;
461            }
462        }
463    }
464
465    SkRect devBounds;
466    GetPathDevBounds(path, drawState->getRenderTarget(), viewM, &devBounds);
467
468    for (int p = 0; p < passCount; ++p) {
469        drawState->setDrawFace(drawFace[p]);
470        if (NULL != passes[p]) {
471            *drawState->stencil() = *passes[p];
472        }
473
474        if (lastPassIsBounds && (p == passCount-1)) {
475            if (!colorWritesWereDisabled) {
476                drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
477            }
478            SkRect bounds;
479            GrDrawState::AutoViewMatrixRestore avmr;
480            if (reverse) {
481                SkASSERT(NULL != drawState->getRenderTarget());
482                // draw over the dev bounds (which will be the whole dst surface for inv fill).
483                bounds = devBounds;
484                SkMatrix vmi;
485                // mapRect through persp matrix may not be correct
486                if (!drawState->getViewMatrix().hasPerspective() &&
487                    drawState->getViewInverse(&vmi)) {
488                    vmi.mapRect(&bounds);
489                } else {
490                    avmr.setIdentity(drawState);
491                }
492            } else {
493                bounds = path.getBounds();
494            }
495            GrDrawTarget::AutoGeometryAndStatePush agasp(target, GrDrawTarget::kPreserve_ASRInit);
496            target->drawSimpleRect(bounds, NULL);
497        } else {
498            if (passCount > 1) {
499                drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
500            }
501            if (indexCnt) {
502                target->drawIndexed(primType, 0, 0,
503                                    vertexCnt, indexCnt, &devBounds);
504            } else {
505                target->drawNonIndexed(primType, 0, vertexCnt, &devBounds);
506            }
507        }
508    }
509    return true;
510}
511
512bool GrDefaultPathRenderer::canDrawPath(const SkPath& path,
513                                        const SkStrokeRec& stroke,
514                                        const GrDrawTarget* target,
515                                        bool antiAlias) const {
516    // this class can draw any path with any fill but doesn't do any anti-aliasing.
517
518    return !antiAlias &&
519        (stroke.isFillStyle() ||
520         IsStrokeHairlineOrEquivalent(stroke, target->getDrawState().getViewMatrix(), NULL));
521}
522
523bool GrDefaultPathRenderer::onDrawPath(const SkPath& path,
524                                       const SkStrokeRec& stroke,
525                                       GrDrawTarget* target,
526                                       bool antiAlias) {
527    return this->internalDrawPath(path,
528                                  stroke,
529                                  target,
530                                  false);
531}
532
533void GrDefaultPathRenderer::onStencilPath(const SkPath& path,
534                                          const SkStrokeRec& stroke,
535                                          GrDrawTarget* target) {
536    SkASSERT(SkPath::kInverseEvenOdd_FillType != path.getFillType());
537    SkASSERT(SkPath::kInverseWinding_FillType != path.getFillType());
538    this->internalDrawPath(path, stroke, target, true);
539}
540