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 "GrInvariantOutput.h"
15 #include "GrTypesPriv.h"
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).
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
35 * In both versions we solve the quadratic for ||q-p||.
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");
40 * builder->fsCodeAppend("\t\tedgeAlpha = (gFM - sqrt(gFM*gFM-4.0*func*gF2M))/(2.0*gF2M);\n");
42 * Also note that 2nd partials of k,l,m are zero
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.
57 class GrGLConicEffect;
59 class GrConicEffect : public GrGeometryProcessor {
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) {
68 case kFillAA_GrProcessorEdgeType:
69 if (!caps.shaderDerivativeSupport()) {
72 return SkNEW_ARGS(GrConicEffect, (color, viewMatrix, coverage,
73 kFillAA_GrProcessorEdgeType,
75 case kHairlineAA_GrProcessorEdgeType:
76 if (!caps.shaderDerivativeSupport()) {
79 return SkNEW_ARGS(GrConicEffect, (color, viewMatrix, coverage,
80 kHairlineAA_GrProcessorEdgeType,
82 case kFillBW_GrProcessorEdgeType:
83 return SkNEW_ARGS(GrConicEffect, (color, viewMatrix, coverage,
84 kFillBW_GrProcessorEdgeType,
91 virtual ~GrConicEffect();
93 const char* name() const SK_OVERRIDE { return "Conic"; }
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; }
101 virtual void getGLProcessorKey(const GrBatchTracker& bt,
102 const GrGLCaps& caps,
103 GrProcessorKeyBuilder* b) const SK_OVERRIDE;
105 virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
106 const GrGLCaps&) const SK_OVERRIDE;
108 void initBatchTracker(GrBatchTracker*, const GrPipelineInfo&) const SK_OVERRIDE;
109 bool onCanMakeEqual(const GrBatchTracker&,
110 const GrGeometryProcessor&,
111 const GrBatchTracker&) const SK_OVERRIDE;
114 GrConicEffect(GrColor, const SkMatrix& viewMatrix, uint8_t coverage, GrPrimitiveEdgeType,
115 const SkMatrix& localMatrix);
117 bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
119 void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
120 out->setUnknownSingleComponent();
123 uint8_t fCoverageScale;
124 GrPrimitiveEdgeType fEdgeType;
125 const Attribute* fInPosition;
126 const Attribute* fInConicCoeffs;
128 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
130 typedef GrGeometryProcessor INHERITED;
133 ///////////////////////////////////////////////////////////////////////////////
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.
142 class GrGLQuadEffect;
144 class GrQuadEffect : public GrGeometryProcessor {
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) {
153 case kFillAA_GrProcessorEdgeType:
154 if (!caps.shaderDerivativeSupport()) {
157 return SkNEW_ARGS(GrQuadEffect, (color, viewMatrix, coverage,
158 kFillAA_GrProcessorEdgeType,
160 case kHairlineAA_GrProcessorEdgeType:
161 if (!caps.shaderDerivativeSupport()) {
164 return SkNEW_ARGS(GrQuadEffect, (color, viewMatrix, coverage,
165 kHairlineAA_GrProcessorEdgeType,
167 case kFillBW_GrProcessorEdgeType:
168 return SkNEW_ARGS(GrQuadEffect, (color, viewMatrix, coverage,
169 kFillBW_GrProcessorEdgeType,
176 virtual ~GrQuadEffect();
178 const char* name() const SK_OVERRIDE { return "Quad"; }
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; }
186 virtual void getGLProcessorKey(const GrBatchTracker& bt,
187 const GrGLCaps& caps,
188 GrProcessorKeyBuilder* b) const SK_OVERRIDE;
190 virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
191 const GrGLCaps&) const SK_OVERRIDE;
193 void initBatchTracker(GrBatchTracker*, const GrPipelineInfo&) const SK_OVERRIDE;
194 bool onCanMakeEqual(const GrBatchTracker&,
195 const GrGeometryProcessor&,
196 const GrBatchTracker&) const SK_OVERRIDE;
199 GrQuadEffect(GrColor, const SkMatrix& viewMatrix, uint8_t coverage, GrPrimitiveEdgeType,
200 const SkMatrix& localMatrix);
202 bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
204 void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
205 out->setUnknownSingleComponent();
208 uint8_t fCoverageScale;
209 GrPrimitiveEdgeType fEdgeType;
210 const Attribute* fInPosition;
211 const Attribute* fInHairQuadEdge;
213 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
215 typedef GrGeometryProcessor INHERITED;
218 //////////////////////////////////////////////////////////////////////////////
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).
229 class GrGLCubicEffect;
231 class GrCubicEffect : public GrGeometryProcessor {
233 static GrGeometryProcessor* Create(GrColor color,
234 const SkMatrix& viewMatrix,
235 const GrPrimitiveEdgeType edgeType,
236 const GrDrawTargetCaps& caps) {
238 case kFillAA_GrProcessorEdgeType:
239 if (!caps.shaderDerivativeSupport()) {
242 return SkNEW_ARGS(GrCubicEffect, (color, viewMatrix, kFillAA_GrProcessorEdgeType));
243 case kHairlineAA_GrProcessorEdgeType:
244 if (!caps.shaderDerivativeSupport()) {
247 return SkNEW_ARGS(GrCubicEffect, (color, viewMatrix,
248 kHairlineAA_GrProcessorEdgeType));
249 case kFillBW_GrProcessorEdgeType:
250 return SkNEW_ARGS(GrCubicEffect, (color, viewMatrix,
251 kFillBW_GrProcessorEdgeType));
257 virtual ~GrCubicEffect();
259 const char* name() const SK_OVERRIDE { return "Cubic"; }
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; }
267 virtual void getGLProcessorKey(const GrBatchTracker& bt,
268 const GrGLCaps& caps,
269 GrProcessorKeyBuilder* b) const SK_OVERRIDE;
271 virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
272 const GrGLCaps&) const SK_OVERRIDE;
274 void initBatchTracker(GrBatchTracker*, const GrPipelineInfo&) const SK_OVERRIDE;
275 bool onCanMakeEqual(const GrBatchTracker&,
276 const GrGeometryProcessor&,
277 const GrBatchTracker&) const SK_OVERRIDE;
280 GrCubicEffect(GrColor, const SkMatrix& viewMatrix, GrPrimitiveEdgeType);
282 bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
284 void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
285 out->setUnknownSingleComponent();
288 GrPrimitiveEdgeType fEdgeType;
289 const Attribute* fInPosition;
290 const Attribute* fInCubicCoeffs;
292 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
294 typedef GrGeometryProcessor INHERITED;