aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/ccpr/GrCCPRCoverageOp.h
blob: 80b4cf97448dc8792af27664a0a85271d31e19c1 (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
/*
 * 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 GrCCPRCoverageOp_DEFINED
#define GrCCPRCoverageOp_DEFINED

#include "GrMesh.h"
#include "SkRect.h"
#include "SkRefCnt.h"
#include "ccpr/GrCCPRCoverageProcessor.h"
#include "ccpr/GrCCPRGeometry.h"
#include "ops/GrDrawOp.h"

class GrCCPRCoverageOp;
class GrOnFlushResourceProvider;
class SkMatrix;
class SkPath;

/**
 * This class produces GrCCPRCoverageOps 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 flush the currently saved paths to a GrCCPRCoverageOp by calling emitOp, and
 * retrieve all emitted ops after calling 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;

    GrCCPRCoverageOpsBuilder(int maxTotalPaths, int numSkPoints, int numSkVerbs)
            : fPathsInfo(maxTotalPaths)
            , fGeometry(numSkPoints, numSkVerbs)
            , fTallies{PrimitiveTallies(), PrimitiveTallies()}
            , fScissorBatches(maxTotalPaths) {}

    ~GrCCPRCoverageOpsBuilder() {
        // Enforce the contract that the client always calls saveParsedPath or discardParsedPath.
        SkASSERT(!fParsingPath);
    }

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

    // Commits the currently-parsed path from staging to the next Op, and specifies whether the mask
    // should be rendered with a scissor clip in effect. Accepts an optional post-device-space
    // translate for placement in an atlas.
    void saveParsedPath(ScissorMode, const SkIRect& clippedDevIBounds,
                        int16_t atlasOffsetX, int16_t atlasOffsetY);
    void discardParsedPath();

    // Flushes all currently-saved paths internally to a GrCCPRCoverageOp.
    //
    // 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.
    void emitOp(SkISize drawBounds);

    // Builds GPU buffers and returns the list of GrCCPRCoverageOps as specified by calls to emitOp.
    bool finalize(GrOnFlushResourceProvider*, SkTArray<std::unique_ptr<GrCCPRCoverageOp>>*);

private:
    using PrimitiveTallies = GrCCPRGeometry::PrimitiveTallies;

    // Every kBeginPath verb has a corresponding PathInfo entry.
    struct PathInfo {
        ScissorMode   fScissorMode;
        int32_t       fPackedAtlasOffset; // (offsetY << 16) | (offsetX & 0xffff)
        std::unique_ptr<GrCCPRCoverageOp>  fTerminatingOp;
    };

    // Every PathInfo with a mode of kScissored has a corresponding ScissorBatch.
    struct ScissorBatch {
        PrimitiveTallies   fInstanceCounts;
        SkIRect            fScissor;
    };

    void endContourIfNeeded(bool insideContour);

    // Staging area for the path being parsed.
    SkDEBUGCODE(int                    fParsingPath = false);
    int                                fCurrPathPointsIdx;
    int                                fCurrPathVerbsIdx;
    PrimitiveTallies                   fCurrPathTallies;

    SkSTArray<32, PathInfo, true>      fPathsInfo;

    GrCCPRGeometry                     fGeometry;

    PrimitiveTallies                   fTallies[kNumScissorModes];
    SkTArray<ScissorBatch, true>       fScissorBatches;

    std::unique_ptr<GrCCPRCoverageOp>  fTerminatingOp;

    friend class GrCCPRCoverageOp; // For ScissorBatch.
};

/**
 * This Op renders coverage count masks and atlases. Create it using GrCCPRCoverageOpsBuilder.
 */
class GrCCPRCoverageOp : public GrDrawOp {
public:
    DEFINE_OP_CLASS_ID

    // GrDrawOp interface.
    const char* name() const override { return "GrCCPRCoverageOp"; }
    FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
    RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,
                                GrPixelConfigIsClamped) override {
        return RequiresDstTexture::kNo;
    }
    bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
    void onPrepare(GrOpFlushState*) override {}
    void onExecute(GrOpFlushState*) override;

private:
    static constexpr int kNumScissorModes = GrCCPRCoverageOpsBuilder::kNumScissorModes;
    using PrimitiveTallies = GrCCPRGeometry::PrimitiveTallies;
    using ScissorBatch = GrCCPRCoverageOpsBuilder::ScissorBatch;

    GrCCPRCoverageOp(SkTArray<ScissorBatch, true>&& scissorBatches, const SkISize& drawBounds)
        : INHERITED(ClassID())
        , fScissorBatches(std::move(scissorBatches))
        , fDrawBounds(drawBounds) {
        this->setBounds(SkRect::MakeIWH(fDrawBounds.width(), fDrawBounds.height()),
                        GrOp::HasAABloat::kNo, GrOp::IsZeroArea::kNo);
    }

    void setBuffers(sk_sp<GrBuffer> pointsBuffer, sk_sp<GrBuffer> instanceBuffer,
                    const PrimitiveTallies baseInstances[kNumScissorModes],
                    const PrimitiveTallies endInstances[kNumScissorModes]);

    void drawMaskPrimitives(GrOpFlushState*, const GrPipeline&,
                            const GrCCPRCoverageProcessor::RenderPass, GrPrimitiveType,
                            int vertexCount, int PrimitiveTallies::* instanceType) const;

    sk_sp<GrBuffer>                      fPointsBuffer;
    sk_sp<GrBuffer>                      fInstanceBuffer;
    PrimitiveTallies                     fBaseInstances[kNumScissorModes];
    PrimitiveTallies                     fInstanceCounts[kNumScissorModes];
    const SkTArray<ScissorBatch, true>   fScissorBatches;
    const SkISize                        fDrawBounds;

    mutable SkTArray<GrMesh>                     fMeshesScratchBuffer;
    mutable SkTArray<GrPipeline::DynamicState>   fDynamicStatesScratchBuffer;

    friend class GrCCPRCoverageOpsBuilder;

    typedef GrDrawOp INHERITED;
};

#endif