• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
57 class GrGLConicEffect;
58 
59 class GrConicEffect : public GrGeometryProcessor {
60 public:
61     static GrGeometryProcessor* Make(SkArenaAlloc* arena,
62                                      const SkPMColor4f& color,
63                                      const SkMatrix& viewMatrix,
64                                      const GrCaps& caps,
65                                      const SkMatrix& localMatrix,
66                                      bool usesLocalCoords,
67                                      uint8_t coverage = 0xff) {
68         if (!caps.shaderCaps()->shaderDerivativeSupport()) {
69             return nullptr;
70         }
71 
72         return arena->make([&](void* ptr) {
73             return new (ptr) GrConicEffect(color, viewMatrix, coverage, localMatrix,
74                                            usesLocalCoords);
75         });
76     }
77 
78     ~GrConicEffect() override;
79 
name()80     const char* name() const override { return "Conic"; }
81 
82     SkString getShaderDfxInfo() const override;
83 
84     void addToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
85 
86     std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override;
87 
88 private:
89     class Impl;
90 
91     GrConicEffect(const SkPMColor4f&, const SkMatrix& viewMatrix, uint8_t coverage,
92                   const SkMatrix& localMatrix, bool usesLocalCoords);
93 
inPosition()94     inline const Attribute& inPosition() const { return kAttributes[0]; }
inConicCoeffs()95     inline const Attribute& inConicCoeffs() const { return kAttributes[1]; }
96 
97     SkPMColor4f         fColor;
98     SkMatrix            fViewMatrix;
99     SkMatrix            fLocalMatrix;
100     bool                fUsesLocalCoords;
101     uint8_t             fCoverageScale;
102     inline static constexpr Attribute kAttributes[] = {
103         {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType},
104         {"inConicCoeffs", kFloat4_GrVertexAttribType, kHalf4_GrSLType}
105     };
106 
107     GR_DECLARE_GEOMETRY_PROCESSOR_TEST
108 
109     using INHERITED = GrGeometryProcessor;
110 };
111 
112 ///////////////////////////////////////////////////////////////////////////////
113 /**
114  * The output of this effect is a hairline edge for quadratics.
115  * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
116  * two components of the vertex attribute. At the three control points that define
117  * the Quadratic, u, v have the values {0,0}, {1/2, 0}, and {1, 1} respectively.
118  * Coverage for AA is min(0, 1-distance). 3rd & 4th cimponent unused.
119  * Requires shader derivative instruction support.
120  */
121 class GrGLQuadEffect;
122 
123 class GrQuadEffect : public GrGeometryProcessor {
124 public:
125     static GrGeometryProcessor* Make(SkArenaAlloc* arena,
126                                      const SkPMColor4f& color,
127                                      const SkMatrix& viewMatrix,
128                                      const GrCaps& caps,
129                                      const SkMatrix& localMatrix,
130                                      bool usesLocalCoords,
131                                      uint8_t coverage = 0xff) {
132         if (!caps.shaderCaps()->shaderDerivativeSupport()) {
133             return nullptr;
134         }
135 
136         return arena->make([&](void* ptr) {
137             return new (ptr) GrQuadEffect(color, viewMatrix, coverage, localMatrix,
138                                           usesLocalCoords);
139         });
140     }
141 
142     ~GrQuadEffect() override;
143 
name()144     const char* name() const override { return "Quad"; }
145 
146     SkString getShaderDfxInfo() const override;
147 
148     void addToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
149 
150     std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override;
151 
152 private:
153     class Impl;
154 
155     GrQuadEffect(const SkPMColor4f&, const SkMatrix& viewMatrix, uint8_t coverage,
156                  const SkMatrix& localMatrix, bool usesLocalCoords);
157 
inPosition()158     inline const Attribute& inPosition() const { return kAttributes[0]; }
inHairQuadEdge()159     inline const Attribute& inHairQuadEdge() const { return kAttributes[1]; }
160 
161     SkPMColor4f fColor;
162     SkMatrix fViewMatrix;
163     SkMatrix fLocalMatrix;
164     bool fUsesLocalCoords;
165     uint8_t fCoverageScale;
166 
167     inline static constexpr Attribute kAttributes[] = {
168         {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType},
169         {"inHairQuadEdge", kFloat4_GrVertexAttribType, kHalf4_GrSLType}
170     };
171 
172     GR_DECLARE_GEOMETRY_PROCESSOR_TEST
173 
174     using INHERITED = GrGeometryProcessor;
175 };
176 
177 #endif
178