Coverage Report

Created: 2024-05-20 07:14

/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