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#ifndef GrPathRenderer_DEFINED
10#define GrPathRenderer_DEFINED
11
12#include "GrDrawTarget.h"
13#include "GrStencil.h"
14#include "GrStrokeInfo.h"
15
16#include "SkDrawProcs.h"
17#include "SkTArray.h"
18
19class SkPath;
20
21struct GrPoint;
22
23/**
24 *  Base class for drawing paths into a GrDrawTarget.
25 *
26 *  Derived classes can use stages GrPaint::kTotalStages through GrPipelineBuilder::kNumStages-1.
27 *  The stages before GrPaint::kTotalStages are reserved for setting up the draw (i.e., textures and
28 *  filter masks).
29 */
30class SK_API GrPathRenderer : public SkRefCnt {
31public:
32    GrPathRenderer();
33
34    /**
35     * A caller may wish to use a path renderer to draw a path into the stencil buffer. However,
36     * the path renderer itself may require use of the stencil buffer. Also a path renderer may
37     * use a GrProcessor coverage stage that sets coverage to zero to eliminate pixels that are
38     * covered by bounding geometry but outside the path. These exterior pixels would still be
39     * rendered into the stencil.
40     *
41     * A GrPathRenderer can provide three levels of support for stenciling paths:
42     * 1) kNoRestriction: This is the most general. The caller sets up the GrPipelineBuilder on the target
43     *                    and calls drawPath(). The path is rendered exactly as the draw state
44     *                    indicates including support for simultaneous color and stenciling with
45     *                    arbitrary stenciling rules. Pixels partially covered by AA paths are
46     *                    affected by the stencil settings.
47     * 2) kStencilOnly: The path renderer cannot apply arbitrary stencil rules nor shade and stencil
48     *                  simultaneously. The path renderer does support the stencilPath() function
49     *                  which performs no color writes and writes a non-zero stencil value to pixels
50     *                  covered by the path.
51     * 3) kNoSupport: This path renderer cannot be used to stencil the path.
52     */
53    enum StencilSupport {
54        kNoSupport_StencilSupport,
55        kStencilOnly_StencilSupport,
56        kNoRestriction_StencilSupport,
57    };
58
59    /**
60     * This function is to get the stencil support for a particular path. The path's fill must
61     * not be an inverse type.
62     *
63     * @param path      the path that will be drawn
64     * @param stroke    the stroke information (width, join, cap).
65     */
66    StencilSupport getStencilSupport(const SkPath& path, const GrStrokeInfo& stroke) const {
67        SkASSERT(!path.isInverseFillType());
68        return this->onGetStencilSupport(path, stroke);
69    }
70
71    /** Args to canDrawPath()
72     *
73     * fShaderCaps       The shader caps
74     * fPipelineBuilder  The pipelineBuilder
75     * fViewMatrix       The viewMatrix
76     * fPath             The path to draw
77     * fStroke           The stroke information (width, join, cap)
78     * fAntiAlias        True if anti-aliasing is required.
79     */
80    struct CanDrawPathArgs {
81        const GrShaderCaps*         fShaderCaps;
82        const SkMatrix*             fViewMatrix;
83        const SkPath*               fPath;
84        const GrStrokeInfo*         fStroke;
85        bool                        fAntiAlias;
86
87        // These next two are only used by GrStencilAndCoverPathRenderer
88        bool                        fIsStencilDisabled;
89        bool                        fIsStencilBufferMSAA;
90
91        void validate() const {
92            SkASSERT(fShaderCaps);
93            SkASSERT(fViewMatrix);
94            SkASSERT(fPath);
95            SkASSERT(fStroke);
96            SkASSERT(!fPath->isEmpty());
97        }
98    };
99
100    /**
101     * Returns true if this path renderer is able to render the path. Returning false allows the
102     * caller to fallback to another path renderer This function is called when searching for a path
103     * renderer capable of rendering a path.
104     *
105     * @return  true if the path can be drawn by this object, false otherwise.
106     */
107    bool canDrawPath(const CanDrawPathArgs& args) const {
108        SkDEBUGCODE(args.validate();)
109        return this->onCanDrawPath(args);
110    }
111
112    /**
113     * Args to drawPath()
114     *
115     * fTarget                The target that the path will be rendered to
116     * fResourceProvider      The resource provider for creating gpu resources to render the path
117     * fPipelineBuilder       The pipelineBuilder
118     * fColor                 Color to render with
119     * fViewMatrix            The viewMatrix
120     * fPath                  the path to draw.
121     * fStroke                the stroke information (width, join, cap)
122     * fAntiAlias             true if anti-aliasing is required.
123     */
124    struct DrawPathArgs {
125        GrDrawTarget*               fTarget;
126        GrResourceProvider*         fResourceProvider;
127        GrPipelineBuilder*          fPipelineBuilder;
128        GrColor                     fColor;
129        const SkMatrix*             fViewMatrix;
130        const SkPath*               fPath;
131        const GrStrokeInfo*         fStroke;
132        bool                        fAntiAlias;
133
134        void validate() const {
135            SkASSERT(fTarget);
136            SkASSERT(fResourceProvider);
137            SkASSERT(fPipelineBuilder);
138            SkASSERT(fViewMatrix);
139            SkASSERT(fPath);
140            SkASSERT(fStroke);
141            SkASSERT(!fPath->isEmpty());
142        }
143    };
144
145    /**
146     * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then
147     * the subclass must respect the stencil settings of the GrPipelineBuilder.
148     */
149    bool drawPath(const DrawPathArgs& args) {
150        SkDEBUGCODE(args.validate();)
151#ifdef SK_DEBUG
152        CanDrawPathArgs canArgs;
153        canArgs.fShaderCaps = args.fTarget->caps()->shaderCaps();
154        canArgs.fViewMatrix = args.fViewMatrix;
155        canArgs.fPath = args.fPath;
156        canArgs.fStroke = args.fStroke;
157        canArgs.fAntiAlias = args.fAntiAlias;
158
159        canArgs.fIsStencilDisabled = args.fPipelineBuilder->getStencil().isDisabled();
160        canArgs.fIsStencilBufferMSAA =
161                          args.fPipelineBuilder->getRenderTarget()->isStencilBufferMultisampled();
162        SkASSERT(this->canDrawPath(canArgs));
163        SkASSERT(args.fPipelineBuilder->getStencil().isDisabled() ||
164                 kNoRestriction_StencilSupport == this->getStencilSupport(*args.fPath,
165                                                                          *args.fStroke));
166#endif
167        return this->onDrawPath(args);
168    }
169
170    /* Args to stencilPath().
171     *
172     * fTarget                The target that the path will be rendered to.
173     * fResourceProvider      The resource provider for creating gpu resources to render the path
174     * fPipelineBuilder       The pipeline builder.
175     * fViewMatrix            Matrix applied to the path.
176     * fPath                  The path to draw.
177     * fStroke                The stroke information (width, join, cap)
178     */
179    struct StencilPathArgs {
180        GrDrawTarget*       fTarget;
181        GrResourceProvider* fResourceProvider;
182        GrPipelineBuilder*  fPipelineBuilder;
183        const SkMatrix*     fViewMatrix;
184        const SkPath*       fPath;
185        const GrStrokeInfo* fStroke;
186
187        void validate() const {
188            SkASSERT(fTarget);
189            SkASSERT(fResourceProvider);
190            SkASSERT(fPipelineBuilder);
191            SkASSERT(fViewMatrix);
192            SkASSERT(fPath);
193            SkASSERT(fStroke);
194            SkASSERT(!fPath->isEmpty());
195        }
196    };
197
198    /**
199     * Draws the path to the stencil buffer. Assume the writable stencil bits are already
200     * initialized to zero. The pixels inside the path will have non-zero stencil values afterwards.
201     *
202     */
203    void stencilPath(const StencilPathArgs& args) {
204        SkDEBUGCODE(args.validate();)
205        SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(*args.fPath, *args.fStroke));
206
207        this->onStencilPath(args);
208    }
209
210    // Helper for determining if we can treat a thin stroke as a hairline w/ coverage.
211    // If we can, we draw lots faster (raster device does this same test).
212    static bool IsStrokeHairlineOrEquivalent(const GrStrokeInfo& stroke, const SkMatrix& matrix,
213                                             SkScalar* outCoverage) {
214        if (stroke.isDashed()) {
215            return false;
216        }
217        if (stroke.isHairlineStyle()) {
218            if (outCoverage) {
219                *outCoverage = SK_Scalar1;
220            }
221            return true;
222        }
223        return stroke.getStyle() == SkStrokeRec::kStroke_Style &&
224            SkDrawTreatAAStrokeAsHairline(stroke.getWidth(), matrix, outCoverage);
225    }
226
227protected:
228    // Helper for getting the device bounds of a path. Inverse filled paths will have bounds set
229    // by devSize. Non-inverse path bounds will not necessarily be clipped to devSize.
230    static void GetPathDevBounds(const SkPath& path,
231                                 int devW,
232                                 int devH,
233                                 const SkMatrix& matrix,
234                                 SkRect* bounds);
235
236    // Helper version that gets the dev width and height from a GrSurface.
237    static void GetPathDevBounds(const SkPath& path,
238                                 const GrSurface* device,
239                                 const SkMatrix& matrix,
240                                 SkRect* bounds) {
241        GetPathDevBounds(path, device->width(), device->height(), matrix, bounds);
242    }
243
244private:
245    /**
246     * Subclass overrides if it has any limitations of stenciling support.
247     */
248    virtual StencilSupport onGetStencilSupport(const SkPath&, const GrStrokeInfo&) const {
249        return kNoRestriction_StencilSupport;
250    }
251
252    /**
253     * Subclass implementation of drawPath()
254     */
255    virtual bool onDrawPath(const DrawPathArgs& args) = 0;
256
257    /**
258     * Subclass implementation of canDrawPath()
259     */
260    virtual bool onCanDrawPath(const CanDrawPathArgs& args) const = 0;
261
262    /**
263     * Subclass implementation of stencilPath(). Subclass must override iff it ever returns
264     * kStencilOnly in onGetStencilSupport().
265     */
266    virtual void onStencilPath(const StencilPathArgs& args) {
267        GR_STATIC_CONST_SAME_STENCIL(kIncrementStencil,
268                                     kReplace_StencilOp,
269                                     kReplace_StencilOp,
270                                     kAlways_StencilFunc,
271                                     0xffff,
272                                     0xffff,
273                                     0xffff);
274        args.fPipelineBuilder->setStencil(kIncrementStencil);
275        args.fPipelineBuilder->setDisableColorXPFactory();
276        DrawPathArgs drawArgs;
277        drawArgs.fTarget = args.fTarget;
278        drawArgs.fResourceProvider = args.fResourceProvider;
279        drawArgs.fPipelineBuilder = args.fPipelineBuilder;
280        drawArgs.fColor = 0xFFFFFFFF;
281        drawArgs.fViewMatrix = args.fViewMatrix;
282        drawArgs.fPath = args.fPath;
283        drawArgs.fStroke = args.fStroke;
284        drawArgs.fAntiAlias = false;
285        this->drawPath(drawArgs);
286    }
287
288
289    typedef SkRefCnt INHERITED;
290};
291
292#endif
293