Line data Source code
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 "GrCaps.h"
12 : #include "GrProcessor.h"
13 : #include "GrGeometryProcessor.h"
14 : #include "GrTypesPriv.h"
15 :
16 : /**
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).
24 : *
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
33 : *
34 : * In both versions we solve the quadratic for ||q-p||.
35 : * Version 1:
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");
38 : * Version 2:
39 : * builder->fsCodeAppend("\t\tedgeAlpha = (gFM - sqrt(gFM*gFM-4.0*func*gF2M))/(2.0*gF2M);\n");
40 : *
41 : * Also note that 2nd partials of k,l,m are zero
42 : *
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.
55 : */
56 : class GrGLConicEffect;
57 :
58 : class GrConicEffect : public GrGeometryProcessor {
59 : public:
60 0 : static sk_sp<GrGeometryProcessor> Make(GrColor color,
61 : const SkMatrix& viewMatrix,
62 : const GrPrimitiveEdgeType edgeType,
63 : const GrCaps& caps,
64 : const SkMatrix& localMatrix,
65 : bool usesLocalCoords,
66 : uint8_t coverage = 0xff) {
67 0 : switch (edgeType) {
68 : case kFillAA_GrProcessorEdgeType:
69 0 : if (!caps.shaderCaps()->shaderDerivativeSupport()) {
70 0 : return nullptr;
71 : }
72 : return sk_sp<GrGeometryProcessor>(
73 : new GrConicEffect(color, viewMatrix, coverage, kFillAA_GrProcessorEdgeType,
74 0 : localMatrix, usesLocalCoords));
75 : case kHairlineAA_GrProcessorEdgeType:
76 0 : if (!caps.shaderCaps()->shaderDerivativeSupport()) {
77 0 : return nullptr;
78 : }
79 : return sk_sp<GrGeometryProcessor>(
80 : new GrConicEffect(color, viewMatrix, coverage,
81 : kHairlineAA_GrProcessorEdgeType, localMatrix,
82 0 : usesLocalCoords));
83 : case kFillBW_GrProcessorEdgeType:
84 : return sk_sp<GrGeometryProcessor>(
85 : new GrConicEffect(color, viewMatrix, coverage, kFillBW_GrProcessorEdgeType,
86 0 : localMatrix, usesLocalCoords));
87 : default:
88 0 : return nullptr;
89 : }
90 : }
91 :
92 : ~GrConicEffect() override;
93 :
94 0 : const char* name() const override { return "Conic"; }
95 :
96 0 : inline const Attribute* inPosition() const { return fInPosition; }
97 0 : inline const Attribute* inConicCoeffs() const { return fInConicCoeffs; }
98 0 : inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
99 0 : inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
100 0 : inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
101 0 : GrColor color() const { return fColor; }
102 0 : const SkMatrix& viewMatrix() const { return fViewMatrix; }
103 0 : const SkMatrix& localMatrix() const { return fLocalMatrix; }
104 0 : bool usesLocalCoords() const { return fUsesLocalCoords; }
105 0 : uint8_t coverageScale() const { return fCoverageScale; }
106 :
107 : void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
108 :
109 : GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
110 :
111 : private:
112 : GrConicEffect(GrColor, const SkMatrix& viewMatrix, uint8_t coverage, GrPrimitiveEdgeType,
113 : const SkMatrix& localMatrix, bool usesLocalCoords);
114 :
115 : GrColor fColor;
116 : SkMatrix fViewMatrix;
117 : SkMatrix fLocalMatrix;
118 : bool fUsesLocalCoords;
119 : uint8_t fCoverageScale;
120 : GrPrimitiveEdgeType fEdgeType;
121 : const Attribute* fInPosition;
122 : const Attribute* fInConicCoeffs;
123 :
124 : GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
125 :
126 : typedef GrGeometryProcessor INHERITED;
127 : };
128 :
129 : ///////////////////////////////////////////////////////////////////////////////
130 : /**
131 : * The output of this effect is a hairline edge for quadratics.
132 : * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
133 : * two components of the vertex attribute. At the three control points that define
134 : * the Quadratic, u, v have the values {0,0}, {1/2, 0}, and {1, 1} respectively.
135 : * Coverage for AA is min(0, 1-distance). 3rd & 4th cimponent unused.
136 : * Requires shader derivative instruction support.
137 : */
138 : class GrGLQuadEffect;
139 :
140 : class GrQuadEffect : public GrGeometryProcessor {
141 : public:
142 0 : static sk_sp<GrGeometryProcessor> Make(GrColor color,
143 : const SkMatrix& viewMatrix,
144 : const GrPrimitiveEdgeType edgeType,
145 : const GrCaps& caps,
146 : const SkMatrix& localMatrix,
147 : bool usesLocalCoords,
148 : uint8_t coverage = 0xff) {
149 0 : switch (edgeType) {
150 : case kFillAA_GrProcessorEdgeType:
151 0 : if (!caps.shaderCaps()->shaderDerivativeSupport()) {
152 0 : return nullptr;
153 : }
154 : return sk_sp<GrGeometryProcessor>(
155 : new GrQuadEffect(color, viewMatrix, coverage, kFillAA_GrProcessorEdgeType,
156 0 : localMatrix, usesLocalCoords));
157 : case kHairlineAA_GrProcessorEdgeType:
158 0 : if (!caps.shaderCaps()->shaderDerivativeSupport()) {
159 0 : return nullptr;
160 : }
161 : return sk_sp<GrGeometryProcessor>(
162 : new GrQuadEffect(color, viewMatrix, coverage,
163 : kHairlineAA_GrProcessorEdgeType, localMatrix,
164 0 : usesLocalCoords));
165 : case kFillBW_GrProcessorEdgeType:
166 : return sk_sp<GrGeometryProcessor>(
167 : new GrQuadEffect(color, viewMatrix, coverage, kFillBW_GrProcessorEdgeType,
168 0 : localMatrix, usesLocalCoords));
169 : default:
170 0 : return nullptr;
171 : }
172 : }
173 :
174 : ~GrQuadEffect() override;
175 :
176 0 : const char* name() const override { return "Quad"; }
177 :
178 0 : inline const Attribute* inPosition() const { return fInPosition; }
179 0 : inline const Attribute* inHairQuadEdge() const { return fInHairQuadEdge; }
180 0 : inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
181 0 : inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
182 0 : inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
183 0 : GrColor color() const { return fColor; }
184 0 : const SkMatrix& viewMatrix() const { return fViewMatrix; }
185 0 : const SkMatrix& localMatrix() const { return fLocalMatrix; }
186 0 : bool usesLocalCoords() const { return fUsesLocalCoords; }
187 0 : uint8_t coverageScale() const { return fCoverageScale; }
188 :
189 : void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
190 :
191 : GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
192 :
193 : private:
194 : GrQuadEffect(GrColor, const SkMatrix& viewMatrix, uint8_t coverage, GrPrimitiveEdgeType,
195 : const SkMatrix& localMatrix, bool usesLocalCoords);
196 :
197 : GrColor fColor;
198 : SkMatrix fViewMatrix;
199 : SkMatrix fLocalMatrix;
200 : bool fUsesLocalCoords;
201 : uint8_t fCoverageScale;
202 : GrPrimitiveEdgeType fEdgeType;
203 : const Attribute* fInPosition;
204 : const Attribute* fInHairQuadEdge;
205 :
206 : GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
207 :
208 : typedef GrGeometryProcessor INHERITED;
209 : };
210 :
211 : //////////////////////////////////////////////////////////////////////////////
212 : /**
213 : * Shader is based off of "Resolution Independent Curve Rendering using
214 : * Programmable Graphics Hardware" by Loop and Blinn.
215 : * The output of this effect is a hairline edge for non rational cubics.
216 : * Cubics are specified by implicit equation K^3 - LM.
217 : * K, L, and M, are the first three values of the vertex attribute,
218 : * the fourth value is not used. Distance is calculated using a
219 : * first order approximation from the taylor series.
220 : * Coverage for AA is max(0, 1-distance).
221 : */
222 : class GrGLCubicEffect;
223 :
224 : class GrCubicEffect : public GrGeometryProcessor {
225 : public:
226 0 : static sk_sp<GrGeometryProcessor> Make(GrColor color,
227 : const SkMatrix& viewMatrix,
228 : const GrPrimitiveEdgeType edgeType,
229 : const GrCaps& caps) {
230 0 : switch (edgeType) {
231 : case kFillAA_GrProcessorEdgeType:
232 0 : if (!caps.shaderCaps()->shaderDerivativeSupport()) {
233 0 : return nullptr;
234 : }
235 : return sk_sp<GrGeometryProcessor>(
236 0 : new GrCubicEffect(color, viewMatrix, kFillAA_GrProcessorEdgeType));
237 : case kHairlineAA_GrProcessorEdgeType:
238 0 : if (!caps.shaderCaps()->shaderDerivativeSupport()) {
239 0 : return nullptr;
240 : }
241 : return sk_sp<GrGeometryProcessor>(
242 0 : new GrCubicEffect(color, viewMatrix, kHairlineAA_GrProcessorEdgeType));
243 : case kFillBW_GrProcessorEdgeType:
244 : return sk_sp<GrGeometryProcessor>(
245 0 : new GrCubicEffect(color, viewMatrix, kFillBW_GrProcessorEdgeType));
246 : default:
247 0 : return nullptr;
248 : }
249 : }
250 :
251 : ~GrCubicEffect() override;
252 :
253 0 : const char* name() const override { return "Cubic"; }
254 :
255 0 : inline const Attribute* inPosition() const { return fInPosition; }
256 0 : inline const Attribute* inCubicCoeffs() const { return fInCubicCoeffs; }
257 0 : inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
258 0 : inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
259 0 : inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
260 0 : GrColor color() const { return fColor; }
261 0 : bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
262 0 : const SkMatrix& viewMatrix() const { return fViewMatrix; }
263 :
264 : void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
265 :
266 : GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
267 :
268 : private:
269 : GrCubicEffect(GrColor, const SkMatrix& viewMatrix, GrPrimitiveEdgeType);
270 :
271 : GrColor fColor;
272 : SkMatrix fViewMatrix;
273 : GrPrimitiveEdgeType fEdgeType;
274 : const Attribute* fInPosition;
275 : const Attribute* fInCubicCoeffs;
276 :
277 : GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
278 :
279 : typedef GrGeometryProcessor INHERITED;
280 : };
281 :
282 : #endif
|