aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/ccpr/GrCCPRCoverageOpsBuilder.h
blob: 92d0203e8fa6b0bb2612edbb36b2879f163646e7 (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
/*
 * 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 GrCCPRCoverageOpsBuilder_DEFINED
#define GrCCPRCoverageOpsBuilder_DEFINED

#include "GrBuffer.h"
#include "SkRefCnt.h"
#include "SkRect.h"
#include "ccpr/GrCCPRCoverageProcessor.h"

class GrCCPRCoverageOp;
class GrDrawOp;
class GrOnFlushResourceProvider;
class GrResourceProvider;
class SkMatrix;
class SkPath;
struct SkDCubic;
enum class SkCubicType;

/**
 * This class produces GrDrawOps that render coverage count masks and atlases. A path is added to
 * the current op in two steps:
 *
 *   1) parsePath(ScissorMode, viewMatrix, path, &devBounds, &devBounds45);
 *
 *   <client decides where to put the mask within an atlas, if wanted>
 *
 *   2) saveParsedPath(offsetX, offsetY, clipBounds);
 *
 * The client can then produce a GrDrawOp for all currently saved paths by calling either
 * createIntermediateOp() or finalize().
 */
class GrCCPRCoverageOpsBuilder {
public:
    // Indicates whether a path should enforce a scissor clip when rendering its mask. (Specified
    // as an int because these values get used directly as indices into arrays.)
    enum class ScissorMode : int {
        kNonScissored = 0,
        kScissored = 1
    };
    static constexpr int kNumScissorModes = 2;

    struct MaxPrimitives {
        int fMaxTriangles = 0;
        int fMaxQuadratics = 0;
        int fMaxCubics = 0;

        void operator+=(const MaxPrimitives&);
        int sum() const;
    };

    struct MaxBufferItems {
        int             fMaxFanPoints = 0;
        int             fMaxControlPoints = 0;
        MaxPrimitives   fMaxPrimitives[kNumScissorModes];
        int             fMaxPaths = 0;

        void operator+=(const MaxBufferItems&);
        void countPathItems(ScissorMode, const SkPath&);
    };

    GrCCPRCoverageOpsBuilder() : fScissorBatches(512) {
        SkDEBUGCODE(fPointsData = nullptr;)
        SkDEBUGCODE(fInstanceData = nullptr;)
    }

    bool init(GrOnFlushResourceProvider*, const MaxBufferItems&);

    // Parses an SkPath into a temporary staging area. The path will not yet be included in the next
    // Op until there is a matching call to saveParsedPath.
    //
    // Returns two tight bounding boxes: device space and "45 degree" (| 1 -1 | * devCoords) space.
    //                                                                 | 1  1 |
    void parsePath(ScissorMode, const SkMatrix&, const SkPath&, SkRect* devBounds,
                   SkRect* devBounds45);

    // Commits the currently-parsed path from the staging area to the GPU buffers and next Op.
    // Accepts an optional post-device-space translate for placement in an atlas.
    void saveParsedPath(const SkIRect& clippedDevIBounds,
                        int16_t atlasOffsetX, int16_t atlasOffsetY);

    // Flushes all currently-saved paths to a GrDrawOp and leaves the GPU buffers open to accept
    // new paths (e.g. for when an atlas runs out of space).
    // NOTE: if there is a parsed path in the staging area, it will not be included. But the client
    // may still call saveParsedPath to include it in a future Op.
    std::unique_ptr<GrDrawOp> SK_WARN_UNUSED_RESULT createIntermediateOp(SkISize drawBounds);

    // Flushes the remaining saved paths to a final GrDrawOp and closes off the GPU buffers. This
    // must be called before attempting to draw any Ops produced by this class.
    std::unique_ptr<GrDrawOp> SK_WARN_UNUSED_RESULT finalize(SkISize drawBounds);

    class CoverageOp;
    class AccumulatingViewMatrix;

private:
    using PrimitiveInstance = GrCCPRCoverageProcessor::PrimitiveInstance;

    struct PrimitiveTallies {
        int fTriangles;
        int fQuadratics;
        int fSerpentines;
        int fLoops;

        PrimitiveTallies operator+(const PrimitiveTallies&) const;
        PrimitiveTallies operator-(const PrimitiveTallies&) const;
        int sum() const;
    };

    struct ScissorBatch {
        PrimitiveTallies   fInstanceCounts;
        SkIRect            fScissor;
    };

    void startContour(AccumulatingViewMatrix&, const SkPoint& anchorPoint);
    void fanTo(AccumulatingViewMatrix&, const SkPoint& pt);
    void quadraticTo(AccumulatingViewMatrix&, const SkPoint P[3]);
    void cubicTo(AccumulatingViewMatrix&, const SkPoint P[4]);
    void emitCubicSegment(AccumulatingViewMatrix&, SkCubicType, const SkDCubic&,
                          const SkPoint& ts0, const SkPoint& ts1);
    void closeContour();
    void emitHierarchicalFan(int32_t indices[], int count);
    SkDEBUGCODE(void validate();)

    ScissorMode              fCurrScissorMode;
    PrimitiveTallies         fCurrPathIndices;
    int32_t                  fCurrContourStartIdx;
    SkPoint                  fCurrPathSpaceAnchorPoint;

    sk_sp<GrBuffer>          fPointsBuffer;
    SkPoint*                 fPointsData;
    int32_t                  fFanPtsIdx;
    int32_t                  fControlPtsIdx;
    SkDEBUGCODE(int          fMaxFanPoints;)
    SkDEBUGCODE(int          fMaxControlPoints;)

    sk_sp<GrBuffer>          fInstanceBuffer;
    PrimitiveInstance*       fInstanceData;
    PrimitiveTallies         fBaseInstances[kNumScissorModes];
    PrimitiveTallies         fInstanceIndices[kNumScissorModes];

    SkTArray<ScissorBatch>   fScissorBatches;
};

inline void GrCCPRCoverageOpsBuilder::MaxBufferItems::operator+=(const MaxBufferItems& b) {
    fMaxFanPoints += b.fMaxFanPoints;
    fMaxControlPoints += b.fMaxControlPoints;
    fMaxPrimitives[0] += b.fMaxPrimitives[0];
    fMaxPrimitives[1] += b.fMaxPrimitives[1];
    fMaxPaths += b.fMaxPaths;
}

inline void GrCCPRCoverageOpsBuilder::MaxPrimitives::operator+=(const MaxPrimitives& b) {
    fMaxTriangles += b.fMaxTriangles;
    fMaxQuadratics += b.fMaxQuadratics;
    fMaxCubics += b.fMaxCubics;
}

inline int GrCCPRCoverageOpsBuilder::MaxPrimitives::sum() const {
    return fMaxTriangles + fMaxQuadratics + fMaxCubics;
}

#endif