b0039e955f7c76ca5ab169105c2e546a88769a71
[platform/upstream/libSkiaSharp.git] / src / gpu / effects / GrBezierEffect.h
1 /*
2  * Copyright 2013 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 GrBezierEffect_DEFINED
9 #define GrBezierEffect_DEFINED
10
11 #include "GrDrawTargetCaps.h"
12 #include "GrProcessor.h"
13 #include "GrGeometryProcessor.h"
14 #include "GrInvariantOutput.h"
15 #include "GrTypesPriv.h"
16
17 /**
18  * Shader is based off of Loop-Blinn Quadratic GPU Rendering
19  * The output of this effect is a hairline edge for conics.
20  * Conics specified by implicit equation K^2 - LM.
21  * K, L, and M, are the first three values of the vertex attribute,
22  * the fourth value is not used. Distance is calculated using a
23  * first order approximation from the taylor series.
24  * Coverage for AA is max(0, 1-distance).
25  *
26  * Test were also run using a second order distance approximation.
27  * There were two versions of the second order approx. The first version
28  * is of roughly the form:
29  * f(q) = |f(p)| - ||f'(p)||*||q-p|| - ||f''(p)||*||q-p||^2.
30  * The second is similar:
31  * f(q) = |f(p)| + ||f'(p)||*||q-p|| + ||f''(p)||*||q-p||^2.
32  * The exact version of the equations can be found in the paper
33  * "Distance Approximations for Rasterizing Implicit Curves" by Gabriel Taubin
34  *
35  * In both versions we solve the quadratic for ||q-p||.
36  * Version 1:
37  * gFM is magnitude of first partials and gFM2 is magnitude of 2nd partials (as derived from paper)
38  * builder->fsCodeAppend("\t\tedgeAlpha = (sqrt(gFM*gFM+4.0*func*gF2M) - gFM)/(2.0*gF2M);\n");
39  * Version 2:
40  * builder->fsCodeAppend("\t\tedgeAlpha = (gFM - sqrt(gFM*gFM-4.0*func*gF2M))/(2.0*gF2M);\n");
41  *
42  * Also note that 2nd partials of k,l,m are zero
43  *
44  * When comparing the two second order approximations to the first order approximations,
45  * the following results were found. Version 1 tends to underestimate the distances, thus it
46  * basically increases all the error that we were already seeing in the first order
47  * approx. So this version is not the one to use. Version 2 has the opposite effect
48  * and tends to overestimate the distances. This is much closer to what we are
49  * looking for. It is able to render ellipses (even thin ones) without the need to chop.
50  * However, it can not handle thin hyperbolas well and thus would still rely on
51  * chopping to tighten the clipping. Another side effect of the overestimating is
52  * that the curves become much thinner and "ropey". If all that was ever rendered
53  * were "not too thin" curves and ellipses then 2nd order may have an advantage since
54  * only one geometry would need to be rendered. However no benches were run comparing
55  * chopped first order and non chopped 2nd order.
56  */
57 class GrGLConicEffect;
58
59 class GrConicEffect : public GrGeometryProcessor {
60 public:
61     static GrGeometryProcessor* Create(GrColor color,
62                                        const SkMatrix& viewMatrix,
63                                        const GrPrimitiveEdgeType edgeType,
64                                        const GrDrawTargetCaps& caps,
65                                        const SkMatrix& localMatrix,
66                                        uint8_t coverage = 0xff) {
67         switch (edgeType) {
68             case kFillAA_GrProcessorEdgeType:
69                 if (!caps.shaderDerivativeSupport()) {
70                     return NULL;
71                 }
72                 return SkNEW_ARGS(GrConicEffect, (color, viewMatrix, coverage,
73                                                   kFillAA_GrProcessorEdgeType,
74                                                   localMatrix));
75             case kHairlineAA_GrProcessorEdgeType:
76                 if (!caps.shaderDerivativeSupport()) {
77                     return NULL;
78                 }
79                 return SkNEW_ARGS(GrConicEffect, (color, viewMatrix, coverage,
80                                                   kHairlineAA_GrProcessorEdgeType,
81                                                   localMatrix));
82             case kFillBW_GrProcessorEdgeType:
83                 return SkNEW_ARGS(GrConicEffect, (color, viewMatrix, coverage,
84                                                   kFillBW_GrProcessorEdgeType,
85                                                   localMatrix));
86             default:
87                 return NULL;
88         }
89     }
90
91     virtual ~GrConicEffect();
92
93     const char* name() const SK_OVERRIDE { return "Conic"; }
94
95     inline const Attribute* inPosition() const { return fInPosition; }
96     inline const Attribute* inConicCoeffs() const { return fInConicCoeffs; }
97     inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
98     inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
99     inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
100
101     virtual void getGLProcessorKey(const GrBatchTracker& bt,
102                                    const GrGLCaps& caps,
103                                    GrProcessorKeyBuilder* b) const SK_OVERRIDE;
104
105     virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
106                                                      const GrGLCaps&) const SK_OVERRIDE;
107
108     void initBatchTracker(GrBatchTracker*, const GrPipelineInfo&) const SK_OVERRIDE;
109     bool onCanMakeEqual(const GrBatchTracker&,
110                         const GrGeometryProcessor&,
111                         const GrBatchTracker&) const SK_OVERRIDE;
112
113 private:
114     GrConicEffect(GrColor, const SkMatrix& viewMatrix, uint8_t coverage, GrPrimitiveEdgeType,
115                   const SkMatrix& localMatrix);
116
117     bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
118
119     void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
120         out->setUnknownSingleComponent();
121     }
122
123     uint8_t               fCoverageScale;
124     GrPrimitiveEdgeType   fEdgeType;
125     const Attribute*    fInPosition;
126     const Attribute*    fInConicCoeffs;
127
128     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
129
130     typedef GrGeometryProcessor INHERITED;
131 };
132
133 ///////////////////////////////////////////////////////////////////////////////
134 /**
135  * The output of this effect is a hairline edge for quadratics.
136  * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
137  * two components of the vertex attribute. At the three control points that define
138  * the Quadratic, u, v have the values {0,0}, {1/2, 0}, and {1, 1} respectively.
139  * Coverage for AA is min(0, 1-distance). 3rd & 4th cimponent unused.
140  * Requires shader derivative instruction support.
141  */
142 class GrGLQuadEffect;
143
144 class GrQuadEffect : public GrGeometryProcessor {
145 public:
146     static GrGeometryProcessor* Create(GrColor color,
147                                        const SkMatrix& viewMatrix,
148                                        const GrPrimitiveEdgeType edgeType,
149                                        const GrDrawTargetCaps& caps,
150                                        const SkMatrix& localMatrix,
151                                        uint8_t coverage = 0xff) {
152         switch (edgeType) {
153             case kFillAA_GrProcessorEdgeType:
154                 if (!caps.shaderDerivativeSupport()) {
155                     return NULL;
156                 }
157                 return SkNEW_ARGS(GrQuadEffect, (color, viewMatrix, coverage,
158                                                  kFillAA_GrProcessorEdgeType,
159                                                  localMatrix));
160             case kHairlineAA_GrProcessorEdgeType:
161                 if (!caps.shaderDerivativeSupport()) {
162                     return NULL;
163                 }
164                 return SkNEW_ARGS(GrQuadEffect, (color, viewMatrix, coverage,
165                                                  kHairlineAA_GrProcessorEdgeType,
166                                                  localMatrix));
167             case kFillBW_GrProcessorEdgeType:
168                 return SkNEW_ARGS(GrQuadEffect, (color, viewMatrix, coverage,
169                                                  kFillBW_GrProcessorEdgeType,
170                                                  localMatrix));
171             default:
172                 return NULL;
173         }
174     }
175
176     virtual ~GrQuadEffect();
177
178     const char* name() const SK_OVERRIDE { return "Quad"; }
179
180     inline const Attribute* inPosition() const { return fInPosition; }
181     inline const Attribute* inHairQuadEdge() const { return fInHairQuadEdge; }
182     inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
183     inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
184     inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
185
186     virtual void getGLProcessorKey(const GrBatchTracker& bt,
187                                    const GrGLCaps& caps,
188                                    GrProcessorKeyBuilder* b) const SK_OVERRIDE;
189
190     virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
191                                                      const GrGLCaps&) const SK_OVERRIDE;
192
193     void initBatchTracker(GrBatchTracker*, const GrPipelineInfo&) const SK_OVERRIDE;
194     bool onCanMakeEqual(const GrBatchTracker&,
195                         const GrGeometryProcessor&,
196                         const GrBatchTracker&) const SK_OVERRIDE;
197
198 private:
199     GrQuadEffect(GrColor, const SkMatrix& viewMatrix, uint8_t coverage, GrPrimitiveEdgeType,
200                  const SkMatrix& localMatrix);
201
202     bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
203
204     void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
205         out->setUnknownSingleComponent();
206     }
207
208     uint8_t               fCoverageScale;
209     GrPrimitiveEdgeType   fEdgeType;
210     const Attribute*    fInPosition;
211     const Attribute*    fInHairQuadEdge;
212
213     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
214
215     typedef GrGeometryProcessor INHERITED;
216 };
217
218 //////////////////////////////////////////////////////////////////////////////
219 /**
220  * Shader is based off of "Resolution Independent Curve Rendering using
221  * Programmable Graphics Hardware" by Loop and Blinn.
222  * The output of this effect is a hairline edge for non rational cubics.
223  * Cubics are specified by implicit equation K^3 - LM.
224  * K, L, and M, are the first three values of the vertex attribute,
225  * the fourth value is not used. Distance is calculated using a
226  * first order approximation from the taylor series.
227  * Coverage for AA is max(0, 1-distance).
228  */
229 class GrGLCubicEffect;
230
231 class GrCubicEffect : public GrGeometryProcessor {
232 public:
233     static GrGeometryProcessor* Create(GrColor color,
234                                        const SkMatrix& viewMatrix,
235                                        const GrPrimitiveEdgeType edgeType,
236                                        const GrDrawTargetCaps& caps) {
237         switch (edgeType) {
238             case kFillAA_GrProcessorEdgeType:
239                 if (!caps.shaderDerivativeSupport()) {
240                     return NULL;
241                 }
242                 return SkNEW_ARGS(GrCubicEffect, (color, viewMatrix, kFillAA_GrProcessorEdgeType));
243             case kHairlineAA_GrProcessorEdgeType:
244                 if (!caps.shaderDerivativeSupport()) {
245                     return NULL;
246                 }
247                 return SkNEW_ARGS(GrCubicEffect, (color, viewMatrix,
248                                                   kHairlineAA_GrProcessorEdgeType));
249             case kFillBW_GrProcessorEdgeType:
250                 return SkNEW_ARGS(GrCubicEffect, (color, viewMatrix,
251                                                   kFillBW_GrProcessorEdgeType));
252             default:
253                 return NULL;
254         }
255     }
256
257     virtual ~GrCubicEffect();
258
259     const char* name() const SK_OVERRIDE { return "Cubic"; }
260
261     inline const Attribute* inPosition() const { return fInPosition; }
262     inline const Attribute* inCubicCoeffs() const { return fInCubicCoeffs; }
263     inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
264     inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
265     inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
266
267     virtual void getGLProcessorKey(const GrBatchTracker& bt,
268                                    const GrGLCaps& caps,
269                                    GrProcessorKeyBuilder* b) const SK_OVERRIDE;
270
271     virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
272                                                      const GrGLCaps&) const SK_OVERRIDE;
273
274     void initBatchTracker(GrBatchTracker*, const GrPipelineInfo&) const SK_OVERRIDE;
275     bool onCanMakeEqual(const GrBatchTracker&,
276                         const GrGeometryProcessor&,
277                         const GrBatchTracker&) const SK_OVERRIDE;
278
279 private:
280     GrCubicEffect(GrColor, const SkMatrix& viewMatrix, GrPrimitiveEdgeType);
281
282     bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
283
284     void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
285         out->setUnknownSingleComponent();
286     }
287
288     GrPrimitiveEdgeType   fEdgeType;
289     const Attribute*    fInPosition;
290     const Attribute*    fInCubicCoeffs;
291
292     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
293
294     typedef GrGeometryProcessor INHERITED;
295 };
296
297 #endif