2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #ifndef GrBezierEffect_DEFINED
9 #define GrBezierEffect_DEFINED
11 #include "GrDrawTargetCaps.h"
12 #include "GrProcessor.h"
13 #include "GrGeometryProcessor.h"
14 #include "GrTypesPriv.h"
17 * Shader is based off of Loop-Blinn Quadratic GPU Rendering
18 * The output of this effect is a hairline edge for conics.
19 * Conics specified by implicit equation K^2 - LM.
20 * K, L, and M, are the first three values of the vertex attribute,
21 * the fourth value is not used. Distance is calculated using a
22 * first order approximation from the taylor series.
23 * Coverage for AA is max(0, 1-distance).
25 * Test were also run using a second order distance approximation.
26 * There were two versions of the second order approx. The first version
27 * is of roughly the form:
28 * f(q) = |f(p)| - ||f'(p)||*||q-p|| - ||f''(p)||*||q-p||^2.
29 * The second is similar:
30 * f(q) = |f(p)| + ||f'(p)||*||q-p|| + ||f''(p)||*||q-p||^2.
31 * The exact version of the equations can be found in the paper
32 * "Distance Approximations for Rasterizing Implicit Curves" by Gabriel Taubin
34 * In both versions we solve the quadratic for ||q-p||.
36 * gFM is magnitude of first partials and gFM2 is magnitude of 2nd partials (as derived from paper)
37 * builder->fsCodeAppend("\t\tedgeAlpha = (sqrt(gFM*gFM+4.0*func*gF2M) - gFM)/(2.0*gF2M);\n");
39 * builder->fsCodeAppend("\t\tedgeAlpha = (gFM - sqrt(gFM*gFM-4.0*func*gF2M))/(2.0*gF2M);\n");
41 * Also note that 2nd partials of k,l,m are zero
43 * When comparing the two second order approximations to the first order approximations,
44 * the following results were found. Version 1 tends to underestimate the distances, thus it
45 * basically increases all the error that we were already seeing in the first order
46 * approx. So this version is not the one to use. Version 2 has the opposite effect
47 * and tends to overestimate the distances. This is much closer to what we are
48 * looking for. It is able to render ellipses (even thin ones) without the need to chop.
49 * However, it can not handle thin hyperbolas well and thus would still rely on
50 * chopping to tighten the clipping. Another side effect of the overestimating is
51 * that the curves become much thinner and "ropey". If all that was ever rendered
52 * were "not too thin" curves and ellipses then 2nd order may have an advantage since
53 * only one geometry would need to be rendered. However no benches were run comparing
54 * chopped first order and non chopped 2nd order.
56 class GrGLConicEffect;
58 class GrConicEffect : public GrGeometryProcessor {
60 static GrGeometryProcessor* Create(const GrPrimitiveEdgeType edgeType,
61 const GrDrawTargetCaps& caps) {
62 GR_CREATE_STATIC_PROCESSOR(gConicFillAA, GrConicEffect, (kFillAA_GrProcessorEdgeType));
63 GR_CREATE_STATIC_PROCESSOR(gConicHairAA, GrConicEffect, (kHairlineAA_GrProcessorEdgeType));
64 GR_CREATE_STATIC_PROCESSOR(gConicFillBW, GrConicEffect, (kFillBW_GrProcessorEdgeType));
66 case kFillAA_GrProcessorEdgeType:
67 if (!caps.shaderDerivativeSupport()) {
72 case kHairlineAA_GrProcessorEdgeType:
73 if (!caps.shaderDerivativeSupport()) {
78 case kFillBW_GrProcessorEdgeType:
86 virtual ~GrConicEffect();
88 static const char* Name() { return "Conic"; }
90 inline const GrShaderVar& inConicCoeffs() const { return fInConicCoeffs; }
91 inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
92 inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
93 inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
95 typedef GrGLConicEffect GLProcessor;
97 virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE;
100 GrConicEffect(GrPrimitiveEdgeType);
102 virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
104 virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
105 inout->mulByUnknownAlpha();
108 GrPrimitiveEdgeType fEdgeType;
109 const GrShaderVar& fInConicCoeffs;
111 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
113 typedef GrGeometryProcessor INHERITED;
116 ///////////////////////////////////////////////////////////////////////////////
118 * The output of this effect is a hairline edge for quadratics.
119 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
120 * two components of the vertex attribute. At the three control points that define
121 * the Quadratic, u, v have the values {0,0}, {1/2, 0}, and {1, 1} respectively.
122 * Coverage for AA is min(0, 1-distance). 3rd & 4th cimponent unused.
123 * Requires shader derivative instruction support.
125 class GrGLQuadEffect;
127 class GrQuadEffect : public GrGeometryProcessor {
129 static GrGeometryProcessor* Create(const GrPrimitiveEdgeType edgeType,
130 const GrDrawTargetCaps& caps) {
131 GR_CREATE_STATIC_PROCESSOR(gQuadFillAA, GrQuadEffect, (kFillAA_GrProcessorEdgeType));
132 GR_CREATE_STATIC_PROCESSOR(gQuadHairAA, GrQuadEffect, (kHairlineAA_GrProcessorEdgeType));
133 GR_CREATE_STATIC_PROCESSOR(gQuadFillBW, GrQuadEffect, (kFillBW_GrProcessorEdgeType));
135 case kFillAA_GrProcessorEdgeType:
136 if (!caps.shaderDerivativeSupport()) {
141 case kHairlineAA_GrProcessorEdgeType:
142 if (!caps.shaderDerivativeSupport()) {
147 case kFillBW_GrProcessorEdgeType:
155 virtual ~GrQuadEffect();
157 static const char* Name() { return "Quad"; }
159 inline const GrShaderVar& inHairQuadEdge() const { return fInHairQuadEdge; }
160 inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
161 inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
162 inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
164 typedef GrGLQuadEffect GLProcessor;
166 virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE;
169 GrQuadEffect(GrPrimitiveEdgeType);
171 virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
173 virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
174 inout->mulByUnknownAlpha();
177 GrPrimitiveEdgeType fEdgeType;
178 const GrShaderVar& fInHairQuadEdge;
180 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
182 typedef GrGeometryProcessor INHERITED;
185 //////////////////////////////////////////////////////////////////////////////
187 * Shader is based off of "Resolution Independent Curve Rendering using
188 * Programmable Graphics Hardware" by Loop and Blinn.
189 * The output of this effect is a hairline edge for non rational cubics.
190 * Cubics are specified by implicit equation K^3 - LM.
191 * K, L, and M, are the first three values of the vertex attribute,
192 * the fourth value is not used. Distance is calculated using a
193 * first order approximation from the taylor series.
194 * Coverage for AA is max(0, 1-distance).
196 class GrGLCubicEffect;
198 class GrCubicEffect : public GrGeometryProcessor {
200 static GrGeometryProcessor* Create(const GrPrimitiveEdgeType edgeType,
201 const GrDrawTargetCaps& caps) {
202 GR_CREATE_STATIC_PROCESSOR(gCubicFillAA, GrCubicEffect, (kFillAA_GrProcessorEdgeType));
203 GR_CREATE_STATIC_PROCESSOR(gCubicHairAA, GrCubicEffect, (kHairlineAA_GrProcessorEdgeType));
204 GR_CREATE_STATIC_PROCESSOR(gCubicFillBW, GrCubicEffect, (kFillBW_GrProcessorEdgeType));
206 case kFillAA_GrProcessorEdgeType:
207 if (!caps.shaderDerivativeSupport()) {
212 case kHairlineAA_GrProcessorEdgeType:
213 if (!caps.shaderDerivativeSupport()) {
218 case kFillBW_GrProcessorEdgeType:
226 virtual ~GrCubicEffect();
228 static const char* Name() { return "Cubic"; }
230 inline const GrShaderVar& inCubicCoeffs() const { return fInCubicCoeffs; }
231 inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
232 inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
233 inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
235 typedef GrGLCubicEffect GLProcessor;
237 virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE;
240 GrCubicEffect(GrPrimitiveEdgeType);
242 virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
244 virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
245 inout->mulByUnknownAlpha();
248 GrPrimitiveEdgeType fEdgeType;
249 const GrShaderVar& fInCubicCoeffs;
251 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
253 typedef GrGeometryProcessor INHERITED;