blob: 5de7b80b7506f43e3508f6f63412da09265d154b [file] [log] [blame]
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +00001/*
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
skia.committer@gmail.com44a77c82013-08-23 07:01:29 +00009#define GrBezierEffect_DEFINED
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +000010
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +000011#include "GrDrawTargetCaps.h"
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000012#include "GrEffect.h"
13#include "GrVertexEffect.h"
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +000014
15enum GrBezierEdgeType {
16 kFillAA_GrBezierEdgeType,
17 kHairAA_GrBezierEdgeType,
18 kFillNoAA_GrBezierEdgeType,
19};
20
21static inline bool GrBezierEdgeTypeIsFill(const GrBezierEdgeType edgeType) {
22 return (kHairAA_GrBezierEdgeType != edgeType);
23}
24
25static 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 */
69class GrGLConicEffect;
70
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000071class GrConicEffect : public GrVertexEffect {
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +000072public:
73 static GrEffectRef* Create(const GrBezierEdgeType edgeType, const GrDrawTargetCaps& caps) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000074 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));
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +000077 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;
skia.committer@gmail.com44a77c82013-08-23 07:01:29 +000089 } else {
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +000090 gConicFillNoAA->ref();
91 return gConicFillNoAA;
92 }
93 }
94
95 virtual ~GrConicEffect();
96
97 static const char* Name() { return "Conic"; }
98
99 inline bool isAntiAliased() const { return GrBezierEdgeTypeIsAA(fEdgeType); }
100 inline bool isFilled() const { return GrBezierEdgeTypeIsFill(fEdgeType); }
101 inline GrBezierEdgeType getEdgeType() const { return fEdgeType; }
102
103 typedef GrGLConicEffect GLEffect;
104
105 virtual void getConstantColorComponents(GrColor* color,
106 uint32_t* validFlags) const SK_OVERRIDE {
107 *validFlags = 0;
108 }
109
skia.committer@gmail.com44a77c82013-08-23 07:01:29 +0000110 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +0000111
112private:
113 GrConicEffect(GrBezierEdgeType);
114
skia.committer@gmail.com44a77c82013-08-23 07:01:29 +0000115 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +0000116
117 GrBezierEdgeType fEdgeType;
118
119 GR_DECLARE_EFFECT_TEST;
120
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000121 typedef GrVertexEffect INHERITED;
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +0000122};
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 */
133class GrGLQuadEffect;
134
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000135class GrQuadEffect : public GrVertexEffect {
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +0000136public:
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;
skia.committer@gmail.com44a77c82013-08-23 07:01:29 +0000153 } else {
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +0000154 gQuadFillNoAA->ref();
155 return gQuadFillNoAA;
156 }
157 }
158
159 virtual ~GrQuadEffect();
160
161 static const char* Name() { return "Quad"; }
162
163 inline bool isAntiAliased() const { return GrBezierEdgeTypeIsAA(fEdgeType); }
164 inline bool isFilled() const { return GrBezierEdgeTypeIsFill(fEdgeType); }
165 inline GrBezierEdgeType getEdgeType() const { return fEdgeType; }
166
167 typedef GrGLQuadEffect GLEffect;
168
169 virtual void getConstantColorComponents(GrColor* color,
170 uint32_t* validFlags) const SK_OVERRIDE {
171 *validFlags = 0;
172 }
173
skia.committer@gmail.com44a77c82013-08-23 07:01:29 +0000174 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +0000175
176private:
177 GrQuadEffect(GrBezierEdgeType);
178
skia.committer@gmail.com44a77c82013-08-23 07:01:29 +0000179 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +0000180
181 GrBezierEdgeType fEdgeType;
182
183 GR_DECLARE_EFFECT_TEST;
184
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000185 typedef GrVertexEffect INHERITED;
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +0000186};
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 */
199class GrGLCubicEffect;
200
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000201class GrCubicEffect : public GrVertexEffect {
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +0000202public:
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;
skia.committer@gmail.com44a77c82013-08-23 07:01:29 +0000219 } else {
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +0000220 gCubicFillNoAA->ref();
221 return gCubicFillNoAA;
222 }
223 }
224
225 virtual ~GrCubicEffect();
226
227 static const char* Name() { return "Cubic"; }
228
229 inline bool isAntiAliased() const { return GrBezierEdgeTypeIsAA(fEdgeType); }
230 inline bool isFilled() const { return GrBezierEdgeTypeIsFill(fEdgeType); }
231 inline GrBezierEdgeType getEdgeType() const { return fEdgeType; }
232
233 typedef GrGLCubicEffect GLEffect;
234
235 virtual void getConstantColorComponents(GrColor* color,
236 uint32_t* validFlags) const SK_OVERRIDE {
237 *validFlags = 0;
238 }
239
skia.committer@gmail.com44a77c82013-08-23 07:01:29 +0000240 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +0000241
242private:
243 GrCubicEffect(GrBezierEdgeType);
244
skia.committer@gmail.com44a77c82013-08-23 07:01:29 +0000245 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +0000246
247 GrBezierEdgeType fEdgeType;
248
249 GR_DECLARE_EFFECT_TEST;
250
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000251 typedef GrVertexEffect INHERITED;
commit-bot@chromium.org07e1c3f2013-08-22 20:41:15 +0000252};
253
254#endif