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 
19 class SkPath;
20 
21 struct 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  */
30 class SK_API GrPathRenderer : public SkRefCnt {
31 public:
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      */
getStencilSupport(const SkPath & path,const GrStrokeInfo & stroke)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 
validateCanDrawPathArgs91         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      */
canDrawPath(const CanDrawPathArgs & args)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 
validateDrawPathArgs134         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      */
drawPath(const DrawPathArgs & args)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 
validateStencilPathArgs187         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      */
stencilPath(const StencilPathArgs & args)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).
IsStrokeHairlineOrEquivalent(const GrStrokeInfo & stroke,const SkMatrix & matrix,SkScalar * outCoverage)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 
227 protected:
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.
GetPathDevBounds(const SkPath & path,const GrSurface * device,const SkMatrix & matrix,SkRect * bounds)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 
244 private:
245     /**
246      * Subclass overrides if it has any limitations of stenciling support.
247      */
onGetStencilSupport(const SkPath &,const GrStrokeInfo &)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      */
onStencilPath(const StencilPathArgs & args)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