• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "GrEffect.h"
13 #include "GrVertexEffect.h"
14 
15 enum GrBezierEdgeType {
16     kFillAA_GrBezierEdgeType,
17     kHairAA_GrBezierEdgeType,
18     kFillNoAA_GrBezierEdgeType,
19 };
20 
GrBezierEdgeTypeIsFill(const GrBezierEdgeType edgeType)21 static inline bool GrBezierEdgeTypeIsFill(const GrBezierEdgeType edgeType) {
22     return (kHairAA_GrBezierEdgeType != edgeType);
23 }
24 
GrBezierEdgeTypeIsAA(const GrBezierEdgeType edgeType)25 static inline bool GrBezierEdgeTypeIsAA(const GrBezierEdgeType edgeType) {
26     return (kFillNoAA_GrBezierEdgeType != edgeType);
27 }
28 
29 /**
30  * Shader is based off of Loop-Blinn Quadratic GPU Rendering
31  * The output of this effect is a hairline edge for conics.
32  * Conics specified by implicit equation K^2 - LM.
33  * K, L, and M, are the first three values of the vertex attribute,
34  * the fourth value is not used. Distance is calculated using a
35  * first order approximation from the taylor series.
36  * Coverage for AA is max(0, 1-distance).
37  *
38  * Test were also run using a second order distance approximation.
39  * There were two versions of the second order approx. The first version
40  * is of roughly the form:
41  * f(q) = |f(p)| - ||f'(p)||*||q-p|| - ||f''(p)||*||q-p||^2.
42  * The second is similar:
43  * f(q) = |f(p)| + ||f'(p)||*||q-p|| + ||f''(p)||*||q-p||^2.
44  * The exact version of the equations can be found in the paper
45  * "Distance Approximations for Rasterizing Implicit Curves" by Gabriel Taubin
46  *
47  * In both versions we solve the quadratic for ||q-p||.
48  * Version 1:
49  * gFM is magnitude of first partials and gFM2 is magnitude of 2nd partials (as derived from paper)
50  * builder->fsCodeAppend("\t\tedgeAlpha = (sqrt(gFM*gFM+4.0*func*gF2M) - gFM)/(2.0*gF2M);\n");
51  * Version 2:
52  * builder->fsCodeAppend("\t\tedgeAlpha = (gFM - sqrt(gFM*gFM-4.0*func*gF2M))/(2.0*gF2M);\n");
53  *
54  * Also note that 2nd partials of k,l,m are zero
55  *
56  * When comparing the two second order approximations to the first order approximations,
57  * the following results were found. Version 1 tends to underestimate the distances, thus it
58  * basically increases all the error that we were already seeing in the first order
59  * approx. So this version is not the one to use. Version 2 has the opposite effect
60  * and tends to overestimate the distances. This is much closer to what we are
61  * looking for. It is able to render ellipses (even thin ones) without the need to chop.
62  * However, it can not handle thin hyperbolas well and thus would still rely on
63  * chopping to tighten the clipping. Another side effect of the overestimating is
64  * that the curves become much thinner and "ropey". If all that was ever rendered
65  * were "not too thin" curves and ellipses then 2nd order may have an advantage since
66  * only one geometry would need to be rendered. However no benches were run comparing
67  * chopped first order and non chopped 2nd order.
68  */
69 class GrGLConicEffect;
70 
71 class GrConicEffect : public GrVertexEffect {
72 public:
Create(const GrBezierEdgeType edgeType,const GrDrawTargetCaps & caps)73     static GrEffectRef* Create(const GrBezierEdgeType edgeType, const GrDrawTargetCaps& caps) {
74         GR_CREATE_STATIC_EFFECT(gConicFillAA, GrConicEffect, (kFillAA_GrBezierEdgeType));
75         GR_CREATE_STATIC_EFFECT(gConicHairAA, GrConicEffect, (kHairAA_GrBezierEdgeType));
76         GR_CREATE_STATIC_EFFECT(gConicFillNoAA, GrConicEffect, (kFillNoAA_GrBezierEdgeType));
77         if (kFillAA_GrBezierEdgeType == edgeType) {
78             if (!caps.shaderDerivativeSupport()) {
79                 return NULL;
80             }
81             gConicFillAA->ref();
82             return gConicFillAA;
83         } else if (kHairAA_GrBezierEdgeType == edgeType) {
84             if (!caps.shaderDerivativeSupport()) {
85                 return NULL;
86             }
87             gConicHairAA->ref();
88             return gConicHairAA;
89         } else {
90             gConicFillNoAA->ref();
91             return gConicFillNoAA;
92         }
93     }
94 
95     virtual ~GrConicEffect();
96 
Name()97     static const char* Name() { return "Conic"; }
98 
isAntiAliased()99     inline bool isAntiAliased() const { return GrBezierEdgeTypeIsAA(fEdgeType); }
isFilled()100     inline bool isFilled() const { return GrBezierEdgeTypeIsFill(fEdgeType); }
getEdgeType()101     inline GrBezierEdgeType getEdgeType() const { return fEdgeType; }
102 
103     typedef GrGLConicEffect GLEffect;
104 
getConstantColorComponents(GrColor * color,uint32_t * validFlags)105     virtual void getConstantColorComponents(GrColor* color,
106                                             uint32_t* validFlags) const SK_OVERRIDE {
107         *validFlags = 0;
108     }
109 
110     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
111 
112 private:
113     GrConicEffect(GrBezierEdgeType);
114 
115     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
116 
117     GrBezierEdgeType fEdgeType;
118 
119     GR_DECLARE_EFFECT_TEST;
120 
121     typedef GrVertexEffect INHERITED;
122 };
123 
124 ///////////////////////////////////////////////////////////////////////////////
125 /**
126  * The output of this effect is a hairline edge for quadratics.
127  * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
128  * two components of the vertex attribute. At the three control points that define
129  * the Quadratic, u, v have the values {0,0}, {1/2, 0}, and {1, 1} respectively.
130  * Coverage for AA is min(0, 1-distance). 3rd & 4th cimponent unused.
131  * Requires shader derivative instruction support.
132  */
133 class GrGLQuadEffect;
134 
135 class GrQuadEffect : public GrVertexEffect {
136 public:
Create(const GrBezierEdgeType edgeType,const GrDrawTargetCaps & caps)137     static GrEffectRef* Create(const GrBezierEdgeType edgeType, const GrDrawTargetCaps& caps) {
138         GR_CREATE_STATIC_EFFECT(gQuadFillAA, GrQuadEffect, (kFillAA_GrBezierEdgeType));
139         GR_CREATE_STATIC_EFFECT(gQuadHairAA, GrQuadEffect, (kHairAA_GrBezierEdgeType));
140         GR_CREATE_STATIC_EFFECT(gQuadFillNoAA, GrQuadEffect, (kFillNoAA_GrBezierEdgeType));
141         if (kFillAA_GrBezierEdgeType == edgeType) {
142             if (!caps.shaderDerivativeSupport()) {
143                 return NULL;
144             }
145             gQuadFillAA->ref();
146             return gQuadFillAA;
147         } else if (kHairAA_GrBezierEdgeType == edgeType) {
148             if (!caps.shaderDerivativeSupport()) {
149                 return NULL;
150             }
151             gQuadHairAA->ref();
152             return gQuadHairAA;
153         } else {
154             gQuadFillNoAA->ref();
155             return gQuadFillNoAA;
156         }
157     }
158 
159     virtual ~GrQuadEffect();
160 
Name()161     static const char* Name() { return "Quad"; }
162 
isAntiAliased()163     inline bool isAntiAliased() const { return GrBezierEdgeTypeIsAA(fEdgeType); }
isFilled()164     inline bool isFilled() const { return GrBezierEdgeTypeIsFill(fEdgeType); }
getEdgeType()165     inline GrBezierEdgeType getEdgeType() const { return fEdgeType; }
166 
167     typedef GrGLQuadEffect GLEffect;
168 
getConstantColorComponents(GrColor * color,uint32_t * validFlags)169     virtual void getConstantColorComponents(GrColor* color,
170                                             uint32_t* validFlags) const SK_OVERRIDE {
171         *validFlags = 0;
172     }
173 
174     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
175 
176 private:
177     GrQuadEffect(GrBezierEdgeType);
178 
179     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
180 
181     GrBezierEdgeType fEdgeType;
182 
183     GR_DECLARE_EFFECT_TEST;
184 
185     typedef GrVertexEffect INHERITED;
186 };
187 
188 //////////////////////////////////////////////////////////////////////////////
189 /**
190  * Shader is based off of "Resolution Independent Curve Rendering using
191  * Programmable Graphics Hardware" by Loop and Blinn.
192  * The output of this effect is a hairline edge for non rational cubics.
193  * Cubics are specified by implicit equation K^3 - LM.
194  * K, L, and M, are the first three values of the vertex attribute,
195  * the fourth value is not used. Distance is calculated using a
196  * first order approximation from the taylor series.
197  * Coverage for AA is max(0, 1-distance).
198  */
199 class GrGLCubicEffect;
200 
201 class GrCubicEffect : public GrVertexEffect {
202 public:
Create(const GrBezierEdgeType edgeType,const GrDrawTargetCaps & caps)203     static GrEffectRef* Create(const GrBezierEdgeType edgeType, const GrDrawTargetCaps& caps) {
204         GR_CREATE_STATIC_EFFECT(gCubicFillAA, GrCubicEffect, (kFillAA_GrBezierEdgeType));
205         GR_CREATE_STATIC_EFFECT(gCubicHairAA, GrCubicEffect, (kHairAA_GrBezierEdgeType));
206         GR_CREATE_STATIC_EFFECT(gCubicFillNoAA, GrCubicEffect, (kFillNoAA_GrBezierEdgeType));
207         if (kFillAA_GrBezierEdgeType == edgeType) {
208             if (!caps.shaderDerivativeSupport()) {
209                 return NULL;
210             }
211             gCubicFillAA->ref();
212             return gCubicFillAA;
213         } else if (kHairAA_GrBezierEdgeType == edgeType) {
214             if (!caps.shaderDerivativeSupport()) {
215                 return NULL;
216             }
217             gCubicHairAA->ref();
218             return gCubicHairAA;
219         } else {
220             gCubicFillNoAA->ref();
221             return gCubicFillNoAA;
222         }
223     }
224 
225     virtual ~GrCubicEffect();
226 
Name()227     static const char* Name() { return "Cubic"; }
228 
isAntiAliased()229     inline bool isAntiAliased() const { return GrBezierEdgeTypeIsAA(fEdgeType); }
isFilled()230     inline bool isFilled() const { return GrBezierEdgeTypeIsFill(fEdgeType); }
getEdgeType()231     inline GrBezierEdgeType getEdgeType() const { return fEdgeType; }
232 
233     typedef GrGLCubicEffect GLEffect;
234 
getConstantColorComponents(GrColor * color,uint32_t * validFlags)235     virtual void getConstantColorComponents(GrColor* color,
236                                             uint32_t* validFlags) const SK_OVERRIDE {
237         *validFlags = 0;
238     }
239 
240     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
241 
242 private:
243     GrCubicEffect(GrBezierEdgeType);
244 
245     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
246 
247     GrBezierEdgeType fEdgeType;
248 
249     GR_DECLARE_EFFECT_TEST;
250 
251     typedef GrVertexEffect INHERITED;
252 };
253 
254 #endif
255