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