aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/ccpr/GrCCPRCoverageProcessor.h
blob: 8120136fad69c315c83b13086163fed0251a187f (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
/*
 * 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 GrCCPRCoverageProcessor_DEFINED
#define GrCCPRCoverageProcessor_DEFINED

#include "GrGeometryProcessor.h"
#include "glsl/GrGLSLGeometryProcessor.h"
#include "glsl/GrGLSLVarying.h"

class GrGLSLFragmentBuilder;

/**
 * This is the geometry processor for the simple convex primitive shapes (triangles and closed curve
 * segments) from which ccpr paths are composed. The output is a single-channel alpha value,
 * positive for clockwise primitives and negative for counter-clockwise, that indicates coverage.
 *
 * The caller is responsible to render all modes for all applicable primitives 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 GrCCPRPathProcessor).
 *
 * Caller provides the primitives' (x,y) points in an fp32x2 (RG) texel buffer, and an instance
 * buffer with a single int32x4 attrib (for triangles) or int32x2 (for curves) defined below. There
 * are no vertex attribs.
 *
 * Draw calls are instanced, with one vertex per bezier point (3 for triangles). They use the
 * corresponding GrPrimitiveType as defined below.
 */
class GrCCPRCoverageProcessor : public GrGeometryProcessor {
public:
    // Use top-left to avoid a uniform access in the fragment shader.
    static constexpr GrSurfaceOrigin kAtlasOrigin = kTopLeft_GrSurfaceOrigin;

    static constexpr GrPrimitiveType kTrianglesGrPrimitiveType = GrPrimitiveType::kTriangles;
    static constexpr GrPrimitiveType kQuadraticsGrPrimitiveType = GrPrimitiveType::kTriangles;
    static constexpr GrPrimitiveType kCubicsGrPrimitiveType = GrPrimitiveType::kLinesAdjacency;

    struct TriangleInstance {
        int32_t fPt0Idx;
        int32_t fPt1Idx;
        int32_t fPt2Idx;
        int32_t fPackedAtlasOffset; // (offsetY << 16) | (offsetX & 0xffff)
    };

    GR_STATIC_ASSERT(4 * 4 == sizeof(TriangleInstance));

    struct CurveInstance {
        int32_t fPtsIdx;
        int32_t fPackedAtlasOffset; // (offsetY << 16) | (offsetX & 0xffff)
    };

    GR_STATIC_ASSERT(2 * 4 == sizeof(CurveInstance));

    enum class Mode {
        // Triangles.
        kTriangleHulls,
        kTriangleEdges,
        kCombinedTriangleHullsAndEdges,
        kTriangleCorners,

        // Quadratics.
        kQuadraticHulls,
        kQuadraticCorners,

        // Cubics.
        kSerpentineHulls,
        kLoopHulls,
        kSerpentineCorners,
        kLoopCorners
    };
    static constexpr GrVertexAttribType InstanceArrayFormat(Mode mode) {
        return mode < Mode::kQuadraticHulls ? kVec4i_GrVertexAttribType : kVec2i_GrVertexAttribType;
    }
    static const char* GetProcessorName(Mode);

    GrCCPRCoverageProcessor(Mode, GrBuffer* pointsBuffer);

    const char* instanceAttrib() const { return fInstanceAttrib.fName; }
    int atlasOffsetIdx() const {
        return kVec4i_GrVertexAttribType == InstanceArrayFormat(fMode) ? 3 : 1;
    }
    const char* name() const override { return GetProcessorName(fMode); }
    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 and outputs color instead of
    // coverage (coverage=+1 -> green, coverage=0 -> black, coverage=-1 -> red).
    void enableDebugVisualizations(float debugBloat) { fDebugBloat = debugBloat; }
    bool debugVisualizationsEnabled() const { return fDebugBloat > 0; }
    float debugBloat() const { SkASSERT(this->debugVisualizationsEnabled()); return fDebugBloat; }

    static void Validate(GrRenderTargetProxy* atlasProxy);
#endif

    class PrimitiveProcessor;

private:
    const Mode          fMode;
    const Attribute&    fInstanceAttrib;
    BufferAccess        fPointsBufferAccess;
    SkDEBUGCODE(float   fDebugBloat = false;)

    typedef GrGeometryProcessor INHERITED;
};

/**
 * This class represents the actual SKSL implementation for the various primitives and modes of
 * GrCCPRCoverageProcessor.
 */
class GrCCPRCoverageProcessor::PrimitiveProcessor : public GrGLSLGeometryProcessor {
protected:
    // 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;

    // Specifies how the fragment shader should calculate sk_FragColor.a.
    enum class CoverageType {
        kOne, // Output +1 all around, modulated by wind.
        kInterpolated, // Interpolate the coverage values that the geometry shader associates with
                       // each point, modulated by wind.
        kShader // Call emitShaderCoverage and let the subclass decide, then a modulate by wind.
    };

    PrimitiveProcessor(CoverageType coverageType)
            : fCoverageType(coverageType)
            , fGeomWind("wind", kHalf_GrSLType, GrShaderVar::kNonArray, kLow_GrSLPrecision)
            , fFragWind(kHalf_GrSLType)
            , fFragCoverageTimesWind(kHalf_GrSLType) {}

    // Called before generating shader code. Subclass should add its custom varyings to the handler
    // and update its corresponding internal member variables.
    virtual void resetVaryings(GrGLSLVaryingHandler*) {}

    // Here the subclass fetches its vertex from the texel buffer, translates by atlasOffset, and
    // sets "fPositionVar" in the GrGPArgs.
    virtual void onEmitVertexShader(const GrCCPRCoverageProcessor&, GrGLSLVertexBuilder*,
                                    const TexelBufferHandle& pointsBuffer, const char* atlasOffset,
                                    const char* rtAdjust, GrGPArgs*) const = 0;

    // Here the subclass determines the winding direction of its primitive. It must write a value of
    // either -1, 0, or +1 to "outputWind" (e.g. "sign(area)"). Fractional values are not valid.
    virtual void emitWind(GrGLSLGeometryBuilder*, const char* rtAdjust,
                          const char* outputWind) const = 0;

    // This is where the subclass generates the actual geometry to be rasterized by hardware:
    //
    //   emitVertexFn(point1, coverage);
    //   emitVertexFn(point2, coverage);
    //   ...
    //   EndPrimitive();
    //
    // Generally a subclass will want to use emitHullGeometry and/or emitEdgeGeometry rather than
    // calling emitVertexFn directly.
    //
    // Subclass must also call GrGLSLGeometryBuilder::configure.
    virtual void onEmitGeometryShader(GrGLSLGeometryBuilder*, const char* emitVertexFn,
                                      const char* wind, const char* rtAdjust) const = 0;

    // This is a hook to inject code in the geometry shader's "emitVertex" function. Subclass
    // should use this to write values to its custom varyings.
    // NOTE: even flat varyings should be rewritten at each vertex.
    virtual void emitPerVertexGeometryCode(SkString* fnBody, const char* position,
                                           const char* coverage, const char* wind) const {}

    // Called when the subclass has selected CoverageType::kShader. Primitives should produce
    // coverage values between +0..1. Base class modulates the sign for wind.
    // TODO: subclasses might have good spots to stuff the winding information without burning a
    // whole new varying slot. Consider requiring them to generate the correct coverage sign.
    virtual void emitShaderCoverage(GrGLSLFragmentBuilder*, const char* outputCoverage) const {
        SK_ABORT("Shader coverage not implemented when using CoverageType::kShader.");
    }

    // Emits one wedge of the conservative raster hull of a convex polygon. The complete hull has
    // one wedge for each side of the polygon (i.e. call this N times, generally from different
    // geometry shader invocations). Coverage is +1 all around.
    //
    // Logically, the conservative raster hull is equivalent to the convex hull of pixel-size boxes
    // centered on the vertices.
    //
    // Geometry shader must be configured to output triangle strips.
    //
    // Returns the maximum number of vertices that will be emitted.
    int emitHullGeometry(GrGLSLGeometryBuilder*, const char* emitVertexFn, const char* polygonPts,
                         int numSides, const char* wedgeIdx, const char* midpoint = nullptr) const;

    // Emits the conservative raster of an edge (i.e. convex hull of two pixel-size boxes centered
    // on the endpoints). Coverage is -1 on the outside border of the edge geometry and 0 on the
    // inside. This effectively converts a jagged conservative raster edge into a smooth antialiased
    // edge when using CoverageType::kInterpolated.
    //
    // If the subclass has already called emitEdgeDistanceEquation, then provide the distance
    // equation. Otherwise this function will call emitEdgeDistanceEquation implicitly.
    //
    // Geometry shader must be configured to output triangle strips.
    //
    // Returns the maximum number of vertices that will be emitted.
    int emitEdgeGeometry(GrGLSLGeometryBuilder*, const char* emitVertexFn, const char* leftPt,
                         const char* rightPt, const char* distanceEquation = nullptr) const;

    // 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 (see emitEdgeGeometry).
    void emitEdgeDistanceEquation(GrGLSLGeometryBuilder*, const char* leftPt, const char* rightPt,
                                  const char* outputDistanceEquation) const;

    // Emits the conservative raster of a single point (i.e. pixel-size box centered on the point).
    // Coverage is +1 all around.
    //
    // Geometry shader must be configured to output triangle strips.
    //
    // Returns the number of vertices that were emitted.
    int emitCornerGeometry(GrGLSLGeometryBuilder*, const char* emitVertexFn, const char* pt) const;

    // Defines a global float2 array that contains MSAA sample locations as offsets from pixel
    // center. Subclasses can use this for software multisampling.
    //
    // Returns the number of samples.
    int defineSoftSampleLocations(GrGLSLFragmentBuilder*, const char* samplesName) const;

private:
    void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
                 FPCoordTransformIter&& transformIter) final {
        this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
    }

    void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final;

    void emitVertexShader(const GrCCPRCoverageProcessor&, GrGLSLVertexBuilder*,
                          const TexelBufferHandle& pointsBuffer, const char* rtAdjust,
                          GrGPArgs* gpArgs) const;
    void emitGeometryShader(const GrCCPRCoverageProcessor&, GrGLSLGeometryBuilder*,
                            const char* rtAdjust) const;
    void emitCoverage(const GrCCPRCoverageProcessor&, GrGLSLFragmentBuilder*,
                      const char* outputColor, const char* outputCoverage) const;

    const CoverageType   fCoverageType;
    GrShaderVar          fGeomWind;
    GrGLSLGeoToFrag      fFragWind;
    GrGLSLGeoToFrag      fFragCoverageTimesWind;

    typedef GrGLSLGeometryProcessor INHERITED;
};

#endif