aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrProcessorSet.h
blob: bfad769a1881fd5ea877f3ae8d72a13a3a8aee29 (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
/*
 * 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 GrProcessorSet_DEFINED
#define GrProcessorSet_DEFINED

#include "GrFragmentProcessor.h"
#include "GrPaint.h"
#include "GrPipelineAnalysis.h"
#include "SkTemplates.h"

class GrAppliedClip;
class GrXPFactory;

class GrProcessorSet : private SkNoncopyable {
public:
    GrProcessorSet(GrPaint&& paint);

    ~GrProcessorSet();

    /**
     * If an op is recorded with this processor set then this must be called to ensure pending
     * reads and writes are propagated to resources referred to by the processors. Otherwise,
     * data hazards may occur.
     */
    void makePendingExecution();
    bool isPendingExecution() const { return SkToBool(kPendingExecution_Flag & fFlags); }

    int numColorFragmentProcessors() const { return fColorFragmentProcessorCnt; }
    int numCoverageFragmentProcessors() const {
        return this->numFragmentProcessors() - fColorFragmentProcessorCnt;
    }
    int numFragmentProcessors() const {
        return fFragmentProcessors.count() - fFragmentProcessorOffset;
    }

    const GrFragmentProcessor* colorFragmentProcessor(int idx) const {
        SkASSERT(idx < fColorFragmentProcessorCnt);
        return fFragmentProcessors[idx + fFragmentProcessorOffset];
    }
    const GrFragmentProcessor* coverageFragmentProcessor(int idx) const {
        return fFragmentProcessors[idx + fColorFragmentProcessorCnt + fFragmentProcessorOffset];
    }

    const GrXPFactory* xpFactory() const { return fXPFactory; }

    bool usesDistanceVectorField() const { return SkToBool(fFlags & kUseDistanceVectorField_Flag); }
    bool disableOutputConversionToSRGB() const {
        return SkToBool(fFlags & kDisableOutputConversionToSRGB_Flag);
    }
    bool allowSRGBInputs() const { return SkToBool(fFlags & kAllowSRGBInputs_Flag); }

    bool operator==(const GrProcessorSet& that) const;
    bool operator!=(const GrProcessorSet& that) const { return !(*this == that); }

    /**
     * This is used to track analysis of color and coverage values through the fragment processors.
     */
    class FragmentProcessorAnalysis {
    public:
        /**
         * This constructor allows an op to record its initial color in a FragmentProcessorAnalysis
         * member and then run analysis later when the analysis inputs are available. If the
         * analysis produces color fragment processor elimination then the input color is replaced
         * by the expected input to the first non-eliminated processor. Otherwise, the original
         * input color is preserved. The only reason to use this is to save space on the op by not
         * separately storing the initial color.
         */
        explicit FragmentProcessorAnalysis(GrColor initialColor) : FragmentProcessorAnalysis() {
            fInputColor = initialColor;
            fValidInputColor = true;
        }

        FragmentProcessorAnalysis()
                : fIsInitializedWithProcessorSet(false)
                , fCompatibleWithCoverageAsAlpha(true)
                , fValidInputColor(false)
                , fOutputCoverageType(static_cast<unsigned>(GrPipelineAnalysisCoverage::kNone))
                , fOutputColorType(static_cast<unsigned>(ColorType::kUnknown))
                , fInitialColorProcessorsToEliminate(0) {}

        // This version is used by a unit test that assumes no clip, no processors, and no PLS.
        FragmentProcessorAnalysis(const GrPipelineAnalysisColor&, GrPipelineAnalysisCoverage,
                                  const GrCaps&);

        void init(const GrPipelineAnalysisColor&, GrPipelineAnalysisCoverage, const GrProcessorSet&,
                  const GrAppliedClip*, const GrCaps&);

        bool isInitializedWithProcessorSet() const { return fIsInitializedWithProcessorSet; }

        /**
         * If the return is greater than or equal to zero then 'newInputColor' should be used as the
         * input color to the GrPipeline derived from this processor set, replacing the GrDrawOp's
         * initial color. If the return is less than zero then newInputColor has not been
         * modified and no modification need be made to the pipeline's input color by the op.
         */
        int getInputColorOverrideAndColorProcessorEliminationCount(GrColor* newInputColor) const {
            if (fValidInputColor) {
                *newInputColor = fInputColor;
                return fInitialColorProcessorsToEliminate;
            }
            SkASSERT(!fInitialColorProcessorsToEliminate);
            return -1;
        }

        /**
         * Valid if initialProcessorsToEliminate returns true or this analysis was initialized with
         * a known color via constructor or init(). If color fragment processors are eliminated then
         * this returns the expected input to the first non-eliminated processors. Otherwise it is
         * the color passed to the constructor or init().
         */
        GrColor inputColor() const {
            SkASSERT(fValidInputColor);
            return fInputColor;
        }

        bool usesLocalCoords() const { return fUsesLocalCoords; }
        bool isCompatibleWithCoverageAsAlpha() const { return fCompatibleWithCoverageAsAlpha; }
        bool isOutputColorOpaque() const {
            return ColorType::kOpaque == this->outputColorType() ||
                   ColorType::kOpaqueConstant == this->outputColorType();
        }
        bool hasKnownOutputColor(GrColor* color = nullptr) const {
            bool constant = ColorType::kConstant == this->outputColorType() ||
                            ColorType::kOpaqueConstant == this->outputColorType();
            if (constant && color) {
                *color = fKnownOutputColor;
            }
            return constant;
        }
        GrPipelineAnalysisCoverage outputCoverageType() const {
            return static_cast<GrPipelineAnalysisCoverage>(fOutputCoverageType);
        }
        bool hasCoverage() const {
            return this->outputCoverageType() != GrPipelineAnalysisCoverage::kNone;
        }

    private:
        enum class ColorType : unsigned { kUnknown, kOpaqueConstant, kConstant, kOpaque };

        ColorType outputColorType() const { return static_cast<ColorType>(fOutputColorType); }

        void internalInit(const GrPipelineAnalysisColor&, const GrPipelineAnalysisCoverage,
                          const GrProcessorSet&, const GrFragmentProcessor* clipFP, const GrCaps&);

        // MSVS 2015 won't pack a bool with an unsigned.
        using PackedBool = unsigned;

        PackedBool fIsInitializedWithProcessorSet : 1;
        PackedBool fUsesLocalCoords : 1;
        PackedBool fCompatibleWithCoverageAsAlpha : 1;
        PackedBool fValidInputColor : 1;
        unsigned fOutputCoverageType : 2;
        unsigned fOutputColorType : 2;
        unsigned fInitialColorProcessorsToEliminate : 32 - 8;

        GrColor fInputColor;
        GrColor fKnownOutputColor;

        friend class GrProcessorSet;
    };
    GR_STATIC_ASSERT(sizeof(FragmentProcessorAnalysis) == 2 * sizeof(GrColor) + sizeof(uint32_t));

    void analyzeAndEliminateFragmentProcessors(FragmentProcessorAnalysis*,
                                               const GrPipelineAnalysisColor& colorInput,
                                               const GrPipelineAnalysisCoverage coverageInput,
                                               const GrAppliedClip*, const GrCaps&);

private:
    // This absurdly large limit allows FragmentProcessorAnalysis and this to pack fields together.
    static constexpr int kMaxColorProcessors = UINT8_MAX;

    enum Flags : uint16_t {
        kUseDistanceVectorField_Flag = 0x1,
        kDisableOutputConversionToSRGB_Flag = 0x2,
        kAllowSRGBInputs_Flag = 0x4,
        kPendingExecution_Flag = 0x8
    };

    const GrXPFactory* fXPFactory = nullptr;
    SkAutoSTArray<4, const GrFragmentProcessor*> fFragmentProcessors;
    uint8_t fColorFragmentProcessorCnt;
    uint8_t fFragmentProcessorOffset = 0;
    uint8_t fFlags;
};

#endif