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 "include/private/GrTypesPriv.h"
12#include "src/core/SkArenaAlloc.h"
13#include "src/gpu/GrCaps.h"
14#include "src/gpu/GrGeometryProcessor.h"
15#include "src/gpu/GrProcessor.h"
16
17/**
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).
25 *
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
34 *
35 * In both versions we solve the quadratic for ||q-p||.
36 * Version 1:
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");
39 * Version 2:
40 * builder->fsCodeAppend("\t\tedgeAlpha = (gFM - sqrt(gFM*gFM-4.0*func*gF2M))/(2.0*gF2M);\n");
41 *
42 * Also note that 2nd partials of k,l,m are zero
43 *
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.
56 */
57class GrGLConicEffect;
58
59class GrConicEffect : public GrGeometryProcessor {
60public:
61 static GrGeometryProcessor* Make(SkArenaAlloc* arena,
62 const SkPMColor4f& color,
63 const SkMatrix& viewMatrix,
64 const GrClipEdgeType edgeType,
65 const GrCaps& caps,
66 const SkMatrix& localMatrix,
67 bool usesLocalCoords,
68 uint8_t coverage = 0xff) {
69 switch (edgeType) {
70 case GrClipEdgeType::kFillAA: // fall through
71 case GrClipEdgeType::kHairlineAA:
72 if (!caps.shaderCaps()->shaderDerivativeSupport()) {
73 return nullptr;
74 }
75 break;
76 case GrClipEdgeType::kFillBW:
77 break;
78 default: // kInverseFillBW or kInverseFillAA
79 return nullptr;
80 }
81
82 return arena->make<GrConicEffect>(color, viewMatrix, coverage, edgeType, localMatrix,
83 usesLocalCoords);
84 }
85
86 ~GrConicEffect() override;
87
88 const char* name() const override { return "Conic"; }
89
90 inline const Attribute& inPosition() const { return kAttributes[0]; }
91 inline const Attribute& inConicCoeffs() const { return kAttributes[1]; }
92 inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
93 inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
94 inline GrClipEdgeType getEdgeType() const { return fEdgeType; }
95 const SkPMColor4f& color() const { return fColor; }
96 const SkMatrix& viewMatrix() const { return fViewMatrix; }
97 const SkMatrix& localMatrix() const { return fLocalMatrix; }
98 bool usesLocalCoords() const { return fUsesLocalCoords; }
99 uint8_t coverageScale() const { return fCoverageScale; }
100
101 void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
102
103 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
104
105private:
106 friend class ::SkArenaAlloc; // for access to ctor
107
108 GrConicEffect(const SkPMColor4f&, const SkMatrix& viewMatrix, uint8_t coverage, GrClipEdgeType,
109 const SkMatrix& localMatrix, bool usesLocalCoords);
110
111 SkPMColor4f fColor;
112 SkMatrix fViewMatrix;
113 SkMatrix fLocalMatrix;
114 bool fUsesLocalCoords;
115 uint8_t fCoverageScale;
116 GrClipEdgeType fEdgeType;
117 static constexpr Attribute kAttributes[] = {
118 {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType},
119 {"inConicCoeffs", kFloat4_GrVertexAttribType, kHalf4_GrSLType}
120 };
121
122 GR_DECLARE_GEOMETRY_PROCESSOR_TEST
123
124 typedef GrGeometryProcessor INHERITED;
125};
126
127///////////////////////////////////////////////////////////////////////////////
128/**
129 * The output of this effect is a hairline edge for quadratics.
130 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
131 * two components of the vertex attribute. At the three control points that define
132 * the Quadratic, u, v have the values {0,0}, {1/2, 0}, and {1, 1} respectively.
133 * Coverage for AA is min(0, 1-distance). 3rd & 4th cimponent unused.
134 * Requires shader derivative instruction support.
135 */
136class GrGLQuadEffect;
137
138class GrQuadEffect : public GrGeometryProcessor {
139public:
140 static GrGeometryProcessor* Make(SkArenaAlloc* arena,
141 const SkPMColor4f& color,
142 const SkMatrix& viewMatrix,
143 const GrClipEdgeType edgeType,
144 const GrCaps& caps,
145 const SkMatrix& localMatrix,
146 bool usesLocalCoords,
147 uint8_t coverage = 0xff) {
148 switch (edgeType) {
149 case GrClipEdgeType::kFillAA: // fall through
150 case GrClipEdgeType::kHairlineAA:
151 if (!caps.shaderCaps()->shaderDerivativeSupport()) {
152 return nullptr;
153 }
154 break;
155 case GrClipEdgeType::kFillBW:
156 break;
157 default: // kInverseFillBW and kInverseFillAA
158 return nullptr;
159 }
160
161 return arena->make<GrQuadEffect>(color, viewMatrix, coverage, edgeType,
162 localMatrix, usesLocalCoords);
163 }
164
165 ~GrQuadEffect() override;
166
167 const char* name() const override { return "Quad"; }
168
169 inline const Attribute& inPosition() const { return kAttributes[0]; }
170 inline const Attribute& inHairQuadEdge() const { return kAttributes[1]; }
171 inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
172 inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
173 inline GrClipEdgeType getEdgeType() const { return fEdgeType; }
174 const SkPMColor4f& color() const { return fColor; }
175 const SkMatrix& viewMatrix() const { return fViewMatrix; }
176 const SkMatrix& localMatrix() const { return fLocalMatrix; }
177 bool usesLocalCoords() const { return fUsesLocalCoords; }
178 uint8_t coverageScale() const { return fCoverageScale; }
179
180 void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
181
182 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
183
184private:
185 friend class ::SkArenaAlloc; // for access to ctor
186
187 GrQuadEffect(const SkPMColor4f&, const SkMatrix& viewMatrix, uint8_t coverage, GrClipEdgeType,
188 const SkMatrix& localMatrix, bool usesLocalCoords);
189
190 SkPMColor4f fColor;
191 SkMatrix fViewMatrix;
192 SkMatrix fLocalMatrix;
193 bool fUsesLocalCoords;
194 uint8_t fCoverageScale;
195 GrClipEdgeType fEdgeType;
196
197 static constexpr Attribute kAttributes[] = {
198 {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType},
199 {"inHairQuadEdge", kFloat4_GrVertexAttribType, kHalf4_GrSLType}
200 };
201
202 GR_DECLARE_GEOMETRY_PROCESSOR_TEST
203
204 typedef GrGeometryProcessor INHERITED;
205};
206
207#endif
208