• 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/gpu/ganesh/GrTypesPriv.h"
12 #include "src/base/SkArenaAlloc.h"
13 #include "src/gpu/ganesh/GrCaps.h"
14 #include "src/gpu/ganesh/GrGeometryProcessor.h"
15 #include "src/gpu/ganesh/GrProcessor.h"
16 #include "src/gpu/ganesh/GrProcessorUnitTest.h"
17 
18 /**
19  * Shader is based off of Loop-Blinn Quadratic GPU Rendering
20  * The output of this effect is a hairline edge for conics.
21  * Conics specified by implicit equation K^2 - LM.
22  * K, L, and M, are the first three values of the vertex attribute,
23  * the fourth value is not used. Distance is calculated using a
24  * first order approximation from the taylor series.
25  * Coverage for AA is max(0, 1-distance).
26  *
27  * Test were also run using a second order distance approximation.
28  * There were two versions of the second order approx. The first version
29  * is of roughly the form:
30  * f(q) = |f(p)| - ||f'(p)||*||q-p|| - ||f''(p)||*||q-p||^2.
31  * The second is similar:
32  * f(q) = |f(p)| + ||f'(p)||*||q-p|| + ||f''(p)||*||q-p||^2.
33  * The exact version of the equations can be found in the paper
34  * "Distance Approximations for Rasterizing Implicit Curves" by Gabriel Taubin
35  *
36  * In both versions we solve the quadratic for ||q-p||.
37  * Version 1:
38  * gFM is magnitude of first partials and gFM2 is magnitude of 2nd partials (as derived from paper)
39  * builder->fsCodeAppend("\t\tedgeAlpha = (sqrt(gFM*gFM+4.0*func*gF2M) - gFM)/(2.0*gF2M);\n");
40  * Version 2:
41  * builder->fsCodeAppend("\t\tedgeAlpha = (gFM - sqrt(gFM*gFM-4.0*func*gF2M))/(2.0*gF2M);\n");
42  *
43  * Also note that 2nd partials of k,l,m are zero
44  *
45  * When comparing the two second order approximations to the first order approximations,
46  * the following results were found. Version 1 tends to underestimate the distances, thus it
47  * basically increases all the error that we were already seeing in the first order
48  * approx. So this version is not the one to use. Version 2 has the opposite effect
49  * and tends to overestimate the distances. This is much closer to what we are
50  * looking for. It is able to render ellipses (even thin ones) without the need to chop.
51  * However, it can not handle thin hyperbolas well and thus would still rely on
52  * chopping to tighten the clipping. Another side effect of the overestimating is
53  * that the curves become much thinner and "ropey". If all that was ever rendered
54  * were "not too thin" curves and ellipses then 2nd order may have an advantage since
55  * only one geometry would need to be rendered. However no benches were run comparing
56  * chopped first order and non chopped 2nd order.
57  */
58 class GrGLConicEffect;
59 
60 class GrConicEffect : public GrGeometryProcessor {
61 public:
62     static GrGeometryProcessor* Make(SkArenaAlloc* arena,
63                                      const SkPMColor4f& color,
64                                      const SkMatrix& viewMatrix,
65                                      const GrCaps& caps,
66                                      const SkMatrix& localMatrix,
67                                      bool usesLocalCoords,
68                                      uint8_t coverage = 0xff) {
69         if (!caps.shaderCaps()->fShaderDerivativeSupport) {
70             return nullptr;
71         }
72 
73         return arena->make([&](void* ptr) {
74             return new (ptr) GrConicEffect(color, viewMatrix, coverage, localMatrix,
75                                            usesLocalCoords);
76         });
77     }
78 
79     ~GrConicEffect() override;
80 
name()81     const char* name() const override { return "Conic"; }
82 
83     void addToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const override;
84 
85     std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override;
86 
87 private:
88     class Impl;
89 
90     GrConicEffect(const SkPMColor4f&, const SkMatrix& viewMatrix, uint8_t coverage,
91                   const SkMatrix& localMatrix, bool usesLocalCoords);
92 
inPosition()93     inline const Attribute& inPosition() const { return kAttributes[0]; }
inConicCoeffs()94     inline const Attribute& inConicCoeffs() const { return kAttributes[1]; }
95 
96     SkPMColor4f         fColor;
97     SkMatrix            fViewMatrix;
98     SkMatrix            fLocalMatrix;
99     bool                fUsesLocalCoords;
100     uint8_t             fCoverageScale;
101     inline static constexpr Attribute kAttributes[] = {
102         {"inPosition", kFloat2_GrVertexAttribType, SkSLType::kFloat2},
103         {"inConicCoeffs", kFloat4_GrVertexAttribType, SkSLType::kHalf4}
104     };
105 
106     GR_DECLARE_GEOMETRY_PROCESSOR_TEST
107 
108     using INHERITED = GrGeometryProcessor;
109 };
110 
111 ///////////////////////////////////////////////////////////////////////////////
112 /**
113  * The output of this effect is a hairline edge for quadratics.
114  * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
115  * two components of the vertex attribute. At the three control points that define
116  * the Quadratic, u, v have the values {0,0}, {1/2, 0}, and {1, 1} respectively.
117  * Coverage for AA is min(0, 1-distance). 3rd & 4th cimponent unused.
118  * Requires shader derivative instruction support.
119  */
120 class GrGLQuadEffect;
121 
122 class GrQuadEffect : public GrGeometryProcessor {
123 public:
124     static GrGeometryProcessor* Make(SkArenaAlloc* arena,
125                                      const SkPMColor4f& color,
126                                      const SkMatrix& viewMatrix,
127                                      const GrCaps& caps,
128                                      const SkMatrix& localMatrix,
129                                      bool usesLocalCoords,
130                                      uint8_t coverage = 0xff) {
131         if (!caps.shaderCaps()->fShaderDerivativeSupport) {
132             return nullptr;
133         }
134 
135         return arena->make([&](void* ptr) {
136             return new (ptr) GrQuadEffect(color, viewMatrix, coverage, localMatrix,
137                                           usesLocalCoords);
138         });
139     }
140 
141     ~GrQuadEffect() override;
142 
name()143     const char* name() const override { return "Quad"; }
144 
145     void addToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const override;
146 
147     std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override;
148 
149 private:
150     class Impl;
151 
152     GrQuadEffect(const SkPMColor4f&, const SkMatrix& viewMatrix, uint8_t coverage,
153                  const SkMatrix& localMatrix, bool usesLocalCoords);
154 
inPosition()155     inline const Attribute& inPosition() const { return kAttributes[0]; }
inHairQuadEdge()156     inline const Attribute& inHairQuadEdge() const { return kAttributes[1]; }
157 
158     SkPMColor4f fColor;
159     SkMatrix fViewMatrix;
160     SkMatrix fLocalMatrix;
161     bool fUsesLocalCoords;
162     uint8_t fCoverageScale;
163 
164     inline static constexpr Attribute kAttributes[] = {
165         {"inPosition", kFloat2_GrVertexAttribType, SkSLType::kFloat2},
166         {"inHairQuadEdge", kFloat4_GrVertexAttribType, SkSLType::kHalf4}
167     };
168 
169     GR_DECLARE_GEOMETRY_PROCESSOR_TEST
170 
171     using INHERITED = GrGeometryProcessor;
172 };
173 
174 #endif
175