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 #ifndef GrPathRenderer_DEFINED
9 #define GrPathRenderer_DEFINED
10 
11 #include "GrTypesPriv.h"
12 #include "SkTArray.h"
13 #include "SkRefCnt.h"
14 
15 class GrCaps;
16 class GrClip;
17 class GrContext;
18 class GrFixedClip;
19 class GrHardClip;
20 class GrPaint;
21 class GrRenderTargetContext;
22 class GrShape;
23 class GrStyle;
24 struct GrUserStencilSettings;
25 struct SkIRect;
26 class SkMatrix;
27 class SkPath;
28 
29 /**
30  *  Base class for drawing paths into a GrOpList.
31  */
32 class SK_API GrPathRenderer : public SkRefCnt {
33 public:
34     GrPathRenderer();
35 
36     /**
37      * A caller may wish to use a path renderer to draw a path into the stencil buffer. However,
38      * the path renderer itself may require use of the stencil buffer. Also a path renderer may
39      * use a GrProcessor coverage stage that sets coverage to zero to eliminate pixels that are
40      * covered by bounding geometry but outside the path. These exterior pixels would still be
41      * rendered into the stencil.
42      *
43      * A GrPathRenderer can provide three levels of support for stenciling paths:
44      * 1) kNoRestriction: This is the most general. The caller passes a GrPaint and calls drawPath().
45      *                    The path is rendered exactly as the draw state indicates including support
46      *                    for simultaneous color and stenciling with arbitrary stenciling rules.
47      *                    Pixels partially covered by AA paths are affected by the stencil settings.
48      * 2) kStencilOnly: The path renderer cannot apply arbitrary stencil rules nor shade and stencil
49      *                  simultaneously. The path renderer does support the stencilPath() function
50      *                  which performs no color writes and writes a non-zero stencil value to pixels
51      *                  covered by the path.
52      * 3) kNoSupport: This path renderer cannot be used to stencil the path.
53      */
54     enum StencilSupport {
55         kNoSupport_StencilSupport,
56         kStencilOnly_StencilSupport,
57         kNoRestriction_StencilSupport,
58     };
59 
60     /**
61      * This function is to get the stencil support for a particular path. The path's fill must
62      * not be an inverse type. The path will always be filled and not stroked.
63      *
64      * @param shape   the shape that will be drawn. Must be simple fill styled and non-inverse
65      *                filled.
66      */
67     StencilSupport getStencilSupport(const GrShape& shape) const;
68 
69     enum class CanDrawPath {
70         kNo,
71         kAsBackup, // i.e. This renderer is better than SW fallback if no others can draw the path.
72         kYes
73     };
74 
75     struct CanDrawPathArgs {
76         SkDEBUGCODE(CanDrawPathArgs() { memset(this, 0, sizeof(*this)); }) // For validation.
77 
78         const GrCaps*               fCaps;
79         const SkIRect*              fClipConservativeBounds;
80         const SkMatrix*             fViewMatrix;
81         const GrShape*              fShape;
82         GrAAType                    fAAType;
83         bool                        fTargetIsWrappedVkSecondaryCB;
84 
85         // This is only used by GrStencilAndCoverPathRenderer
86         bool                        fHasUserStencilSettings;
87 
88 #ifdef SK_DEBUG
89         void validate() const {
90             SkASSERT(fCaps);
91             SkASSERT(fClipConservativeBounds);
92             SkASSERT(fViewMatrix);
93             SkASSERT(fShape);
94         }
95 #endif
96     };
97 
98     /**
99      * Returns how well this path renderer is able to render the given path. Returning kNo or
100      * kAsBackup allows the caller to keep searching for a better path renderer. This function is
101      * called when searching for the best path renderer to draw a path.
102      */
103     CanDrawPath canDrawPath(const CanDrawPathArgs& args) const {
104         SkDEBUGCODE(args.validate();)
105         return this->onCanDrawPath(args);
106     }
107 
108     struct DrawPathArgs {
109         GrContext*                   fContext;
110         GrPaint&&                    fPaint;
111         const GrUserStencilSettings* fUserStencilSettings;
112         GrRenderTargetContext*       fRenderTargetContext;
113         const GrClip*                fClip;
114         const SkIRect*               fClipConservativeBounds;
115         const SkMatrix*              fViewMatrix;
116         const GrShape*               fShape;
117         GrAAType                     fAAType;
118         bool                         fGammaCorrect;
119 #ifdef SK_DEBUG
120         void validate() const {
121             SkASSERT(fContext);
122             SkASSERT(fUserStencilSettings);
123             SkASSERT(fRenderTargetContext);
124             SkASSERT(fClip);
125             SkASSERT(fClipConservativeBounds);
126             SkASSERT(fViewMatrix);
127             SkASSERT(fShape);
128         }
129 #endif
130     };
131 
132     /**
133      * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then
134      * the subclass must respect the stencil settings.
135      */
136     bool drawPath(const DrawPathArgs& args);
137     /**
138      * Args to stencilPath(). fAAType cannot be kCoverage.
139      */
140     struct StencilPathArgs {
141         SkDEBUGCODE(StencilPathArgs() { memset(this, 0, sizeof(*this)); }) // For validation.
142 
143         GrContext*             fContext;
144         GrRenderTargetContext* fRenderTargetContext;
145         const GrHardClip*      fClip;
146         const SkIRect*         fClipConservativeBounds;
147         const SkMatrix*        fViewMatrix;
148         GrAAType               fAAType;
149         const GrShape*         fShape;
150 
151         SkDEBUGCODE(void validate() const);
152     };
153 
154     /**
155      * Draws the path to the stencil buffer. Assume the writable stencil bits are already
156      * initialized to zero. The pixels inside the path will have non-zero stencil values afterwards.
157      */
158     void stencilPath(const StencilPathArgs& args) {
159         SkDEBUGCODE(args.validate();)
160         SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(*args.fShape));
161         this->onStencilPath(args);
162     }
163 
164     // Helper for determining if we can treat a thin stroke as a hairline w/ coverage.
165     // If we can, we draw lots faster (raster device does this same test).
166     static bool IsStrokeHairlineOrEquivalent(const GrStyle&, const SkMatrix&,
167                                              SkScalar* outCoverage);
168 
169 protected:
170     // Helper for getting the device bounds of a path. Inverse filled paths will have bounds set
171     // by devSize. Non-inverse path bounds will not necessarily be clipped to devSize.
172     static void GetPathDevBounds(const SkPath& path,
173                                  int devW,
174                                  int devH,
175                                  const SkMatrix& matrix,
176                                  SkRect* bounds);
177 
178 private:
179     /**
180      * Subclass overrides if it has any limitations of stenciling support.
181      */
182     virtual StencilSupport onGetStencilSupport(const GrShape&) const {
183         return kNoRestriction_StencilSupport;
184     }
185 
186     /**
187      * Subclass implementation of drawPath()
188      */
189     virtual bool onDrawPath(const DrawPathArgs& args) = 0;
190 
191     /**
192      * Subclass implementation of canDrawPath()
193      */
194     virtual CanDrawPath onCanDrawPath(const CanDrawPathArgs& args) const = 0;
195 
196     /**
197      * Subclass implementation of stencilPath(). Subclass must override iff it ever returns
198      * kStencilOnly in onGetStencilSupport().
199      */
200     virtual void onStencilPath(const StencilPathArgs&);
201 
202     typedef SkRefCnt INHERITED;
203 };
204 
205 #endif
206