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