aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/ccpr/GrCCCoverageProcessor.h
blob: e5b6bc11190061fba1b2749d350775445cd663ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
/*
 * Copyright 2017 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef GrCCCoverageProcessor_DEFINED
#define GrCCCoverageProcessor_DEFINED

#include "GrCaps.h"
#include "GrGeometryProcessor.h"
#include "GrPipeline.h"
#include "GrShaderCaps.h"
#include "SkNx.h"
#include "glsl/GrGLSLGeometryProcessor.h"
#include "glsl/GrGLSLVarying.h"

class GrGLSLFPFragmentBuilder;
class GrGLSLVertexGeoBuilder;
class GrMesh;
class GrOpFlushState;

/**
 * This is the geometry processor for the simple convex primitive shapes (triangles and closed,
 * convex bezier curves) from which ccpr paths are composed. The output is a single-channel alpha
 * value, positive for clockwise shapes and negative for counter-clockwise, that indicates coverage.
 *
 * The caller is responsible to draw all primitives as produced by GrCCGeometry into a cleared,
 * floating point, alpha-only render target using SkBlendMode::kPlus. Once all of a path's
 * primitives have been drawn, the render target contains a composite coverage count that can then
 * be used to draw the path (see GrCCPathProcessor).
 *
 * To draw primitives, use appendMesh() and draw() (defined below).
 */
class GrCCCoverageProcessor : public GrGeometryProcessor {
public:
    enum class PrimitiveType {
        kTriangles,
        kWeightedTriangles, // Triangles (from the tessellator) whose winding magnitude > 1.
        kQuadratics,
        kCubics,
        kConics
    };
    static const char* PrimitiveTypeName(PrimitiveType);

    // Defines a single primitive shape with 3 input points (i.e. Triangles and Quadratics).
    // X,Y point values are transposed.
    struct TriPointInstance {
        float fX[3];
        float fY[3];

        void set(const SkPoint[3], const Sk2f& trans);
        void set(const SkPoint&, const SkPoint&, const SkPoint&, const Sk2f& trans);
    };

    // Defines a single primitive shape with 4 input points, or 3 input points plus a "weight"
    // parameter duplicated in both lanes of the 4th input (i.e. Cubics, Conics, and Triangles with
    // a weighted winding number). X,Y point values are transposed.
    struct QuadPointInstance {
        float fX[4];
        float fY[4];

        void set(const SkPoint[4], float dx, float dy);
        void setW(const SkPoint[3], const Sk2f& trans, float w);
        void setW(const SkPoint&, const SkPoint&, const SkPoint&, const Sk2f& trans, float w);
    };

    GrCCCoverageProcessor(GrResourceProvider* rp, PrimitiveType type)
            : INHERITED(kGrCCCoverageProcessor_ClassID)
            , fPrimitiveType(type)
            , fImpl(rp->caps()->shaderCaps()->geometryShaderSupport() ? Impl::kGeometryShader
                                                                      : Impl::kVertexShader) {
        if (Impl::kGeometryShader == fImpl) {
            this->initGS();
        } else {
            this->initVS(rp);
        }
    }

    // GrPrimitiveProcessor overrides.
    const char* name() const override { return PrimitiveTypeName(fPrimitiveType); }
    SkString dumpInfo() const override {
        return SkStringPrintf("%s\n%s", this->name(), this->INHERITED::dumpInfo().c_str());
    }
    void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
    GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;

#ifdef SK_DEBUG
    // Increases the 1/2 pixel AA bloat by a factor of debugBloat.
    void enableDebugBloat(float debugBloat) { fDebugBloat = debugBloat; }
    bool debugBloatEnabled() const { return fDebugBloat > 0; }
    float debugBloat() const { SkASSERT(this->debugBloatEnabled()); return fDebugBloat; }
#endif

    // Appends a GrMesh that will draw the provided instances. The instanceBuffer must be an array
    // of either TriPointInstance or QuadPointInstance, depending on this processor's RendererPass,
    // with coordinates in the desired shape's final atlas-space position.
    void appendMesh(GrBuffer* instanceBuffer, int instanceCount, int baseInstance,
                    SkTArray<GrMesh>* out) const {
        if (Impl::kGeometryShader == fImpl) {
            this->appendGSMesh(instanceBuffer, instanceCount, baseInstance, out);
        } else {
            this->appendVSMesh(instanceBuffer, instanceCount, baseInstance, out);
        }
    }

    void draw(GrOpFlushState*, const GrPipeline&, const SkIRect scissorRects[], const GrMesh[],
              int meshCount, const SkRect& drawBounds) const;

    // The Shader provides code to calculate each pixel's coverage in a RenderPass. It also
    // provides details about shape-specific geometry.
    class Shader {
    public:
        // Called before generating geometry. Subclasses may set up internal member variables during
        // this time that will be needed during onEmitVaryings (e.g. transformation matrices).
        //
        // If the 'outHull4' parameter is provided, and there are not 4 input points, the subclass
        // is required to fill it with the name of a 4-point hull around which the Impl can generate
        // its geometry. If it is left unchanged, the Impl will use the regular input points.
        virtual void emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* wind,
                                   const char** outHull4 = nullptr) const {
            SkASSERT(!outHull4);
        }

        void emitVaryings(GrGLSLVaryingHandler* varyingHandler, GrGLSLVarying::Scope scope,
                          SkString* code, const char* position, const char* coverage,
                          const char* cornerCoverage) {
            SkASSERT(GrGLSLVarying::Scope::kVertToGeo != scope);
            this->onEmitVaryings(varyingHandler, scope, code, position, coverage, cornerCoverage);
        }

        void emitFragmentCode(const GrCCCoverageProcessor&, GrGLSLFPFragmentBuilder*,
                              const char* skOutputColor, const char* skOutputCoverage) const;

        // Calculates the winding direction of the input points (+1, -1, or 0). Wind for extremely
        // thin triangles gets rounded to zero.
        static void CalcWind(const GrCCCoverageProcessor&, GrGLSLVertexGeoBuilder*, const char* pts,
                             const char* outputWind);

        // Defines an equation ("dot(float3(pt, 1), distance_equation)") that is -1 on the outside
        // border of a conservative raster edge and 0 on the inside. 'leftPt' and 'rightPt' must be
        // ordered clockwise.
        static void EmitEdgeDistanceEquation(GrGLSLVertexGeoBuilder*, const char* leftPt,
                                             const char* rightPt,
                                             const char* outputDistanceEquation);

        // Calculates an edge's coverage at a conservative raster vertex. The edge is defined by two
        // clockwise-ordered points, 'leftPt' and 'rightPt'. 'rasterVertexDir' is a pair of +/-1
        // values that point in the direction of conservative raster bloat, starting from an
        // endpoint.
        //
        // Coverage values ramp from -1 (completely outside the edge) to 0 (completely inside).
        static void CalcEdgeCoverageAtBloatVertex(GrGLSLVertexGeoBuilder*, const char* leftPt,
                                                  const char* rightPt, const char* rasterVertexDir,
                                                  const char* outputCoverage);

        // Calculates an edge's coverage at two conservative raster vertices.
        // (See CalcEdgeCoverageAtBloatVertex).
        static void CalcEdgeCoveragesAtBloatVertices(GrGLSLVertexGeoBuilder*, const char* leftPt,
                                                     const char* rightPt, const char* bloatDir1,
                                                     const char* bloatDir2,
                                                     const char* outputCoverages);

        // Corner boxes require an additional "attenuation" varying that is multiplied by the
        // regular (linearly-interpolated) coverage. This function calculates the attenuation value
        // to use in the single, outermost vertex. The remaining three vertices of the corner box
        // all use an attenuation value of 1.
        static void CalcCornerAttenuation(GrGLSLVertexGeoBuilder*, const char* leftDir,
                                          const char* rightDir, const char* outputAttenuation);

        virtual ~Shader() {}

    protected:
        // Here the subclass adds its internal varyings to the handler and produces code to
        // initialize those varyings from a given position and coverage values.
        //
        // NOTE: the coverage values are signed appropriately for wind.
        //       'coverage' will only be +1 or -1 on curves.
        virtual void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code,
                                    const char* position, const char* coverage,
                                    const char* cornerCoverage) = 0;

        // Emits the fragment code that calculates a pixel's signed coverage value.
        virtual void onEmitFragmentCode(GrGLSLFPFragmentBuilder*,
                                        const char* outputCoverage) const = 0;

        // Returns the name of a Shader's internal varying at the point where where its value is
        // assigned. This is intended to work whether called for a vertex or a geometry shader.
        const char* OutName(const GrGLSLVarying& varying) const {
            using Scope = GrGLSLVarying::Scope;
            SkASSERT(Scope::kVertToGeo != varying.scope());
            return Scope::kGeoToFrag == varying.scope() ? varying.gsOut() : varying.vsOut();
        }

        // Our friendship with GrGLSLShaderBuilder does not propogate to subclasses.
        inline static SkString& AccessCodeString(GrGLSLShaderBuilder* s) { return s->code(); }
    };

private:
    class GSImpl;
    class GSTriangleHullImpl;
    class GSCurveHullImpl;
    class GSCornerImpl;
    class VSImpl;
    class TriangleShader;

    // Slightly undershoot a bloat radius of 0.5 so vertices that fall on integer boundaries don't
    // accidentally bleed into neighbor pixels.
    static constexpr float kAABloatRadius = 0.491111f;

    // Number of bezier points for curves, or 3 for triangles.
    int numInputPoints() const { return PrimitiveType::kCubics == fPrimitiveType ? 4 : 3; }

    bool isTriangles() const {
        return PrimitiveType::kTriangles == fPrimitiveType ||
               PrimitiveType::kWeightedTriangles == fPrimitiveType;
    }

    int hasInputWeight() const {
        return PrimitiveType::kWeightedTriangles == fPrimitiveType ||
               PrimitiveType::kConics == fPrimitiveType;
    }

    enum class Impl : bool {
        kGeometryShader,
        kVertexShader
    };

    // Geometry shader backend draws primitives in two subpasses.
    enum class GSSubpass : bool {
        kHulls,
        kCorners
    };

    GrCCCoverageProcessor(const GrCCCoverageProcessor& proc, GSSubpass subpass)
            : INHERITED(kGrCCCoverageProcessor_ClassID)
            , fPrimitiveType(proc.fPrimitiveType)
            , fImpl(Impl::kGeometryShader)
            SkDEBUGCODE(, fDebugBloat(proc.fDebugBloat))
            , fGSSubpass(subpass) {
        SkASSERT(Impl::kGeometryShader == proc.fImpl);
        this->initGS();
    }

    void initGS();
    void initVS(GrResourceProvider*);

    const Attribute& onVertexAttribute(int i) const override { return fVertexAttribute; }

    const Attribute& onInstanceAttribute(int i) const override {
        SkASSERT(fImpl == Impl::kVertexShader);
        return fInstanceAttributes[i];
    }

    void appendGSMesh(GrBuffer* instanceBuffer, int instanceCount, int baseInstance,
                      SkTArray<GrMesh>* out) const;
    void appendVSMesh(GrBuffer* instanceBuffer, int instanceCount, int baseInstance,
                      SkTArray<GrMesh>* out) const;

    GrGLSLPrimitiveProcessor* createGSImpl(std::unique_ptr<Shader>) const;
    GrGLSLPrimitiveProcessor* createVSImpl(std::unique_ptr<Shader>) const;
    // The type and meaning of this attribute depends on whether we're using VSImpl or GSImpl.
    Attribute fVertexAttribute;

    const PrimitiveType fPrimitiveType;
    const Impl fImpl;
    SkDEBUGCODE(float fDebugBloat = 0);

    // Used by GSImpl.
    const GSSubpass fGSSubpass = GSSubpass::kHulls;

    // Used by VSImpl.
    Attribute fInstanceAttributes[2];
    sk_sp<const GrBuffer> fVSVertexBuffer;
    sk_sp<const GrBuffer> fVSIndexBuffer;
    int fVSNumIndicesPerInstance;
    GrPrimitiveType fVSTriangleType;

    typedef GrGeometryProcessor INHERITED;
};

inline const char* GrCCCoverageProcessor::PrimitiveTypeName(PrimitiveType type) {
    switch (type) {
        case PrimitiveType::kTriangles: return "kTriangles";
        case PrimitiveType::kWeightedTriangles: return "kWeightedTriangles";
        case PrimitiveType::kQuadratics: return "kQuadratics";
        case PrimitiveType::kCubics: return "kCubics";
        case PrimitiveType::kConics: return "kConics";
    }
    SK_ABORT("Invalid PrimitiveType");
    return "";
}

inline void GrCCCoverageProcessor::TriPointInstance::set(const SkPoint p[3], const Sk2f& trans) {
    this->set(p[0], p[1], p[2], trans);
}

inline void GrCCCoverageProcessor::TriPointInstance::set(const SkPoint& p0, const SkPoint& p1,
                                                         const SkPoint& p2, const Sk2f& trans) {
    Sk2f P0 = Sk2f::Load(&p0) + trans;
    Sk2f P1 = Sk2f::Load(&p1) + trans;
    Sk2f P2 = Sk2f::Load(&p2) + trans;
    Sk2f::Store3(this, P0, P1, P2);
}

inline void GrCCCoverageProcessor::QuadPointInstance::set(const SkPoint p[4], float dx, float dy) {
    Sk4f X,Y;
    Sk4f::Load2(p, &X, &Y);
    (X + dx).store(&fX);
    (Y + dy).store(&fY);
}

inline void GrCCCoverageProcessor::QuadPointInstance::setW(const SkPoint p[3], const Sk2f& trans,
                                                           float w) {
    this->setW(p[0], p[1], p[2], trans, w);
}

inline void GrCCCoverageProcessor::QuadPointInstance::setW(const SkPoint& p0, const SkPoint& p1,
                                                           const SkPoint& p2, const Sk2f& trans,
                                                           float w) {
    Sk2f P0 = Sk2f::Load(&p0) + trans;
    Sk2f P1 = Sk2f::Load(&p1) + trans;
    Sk2f P2 = Sk2f::Load(&p2) + trans;
    Sk2f W = Sk2f(w);
    Sk2f::Store4(this, P0, P1, P2, W);
}

#endif