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