aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrProcessorAnalysis.h
blob: ad56ab4e2d99ec385abbbad249a24bb4f36c8726 (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
/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef GrProcessorAnalysis_DEFINED
#define GrProcessorAnalysis_DEFINED

#include "GrColor.h"

class GrDrawOp;
class GrFragmentProcessor;
class GrPrimitiveProcessor;

class GrProcessorAnalysisColor {
public:
    enum class Opaque {
        kNo,
        kYes,
    };

    GrProcessorAnalysisColor(Opaque opaque = Opaque::kNo)
            : fFlags(opaque == Opaque::kYes ? kIsOpaque_Flag : 0) {}

    GrProcessorAnalysisColor(GrColor color) { this->setToConstant(color); }

    void setToConstant(GrColor color) {
        fColor = color;
        if (GrColorIsOpaque(color)) {
            fFlags = kColorIsKnown_Flag | kIsOpaque_Flag;
        } else {
            fFlags = kColorIsKnown_Flag;
        }
    }

    void setToUnknown() { fFlags = 0; }

    void setToUnknownOpaque() { fFlags = kIsOpaque_Flag; }

    bool isOpaque() const { return SkToBool(kIsOpaque_Flag & fFlags); }

    bool isConstant(GrColor* color = nullptr) const {
        if (kColorIsKnown_Flag & fFlags) {
            if (color) {
                *color = fColor;
            }
            return true;
        }
        return false;
    }

    bool operator==(const GrProcessorAnalysisColor& that) const {
        if (fFlags != that.fFlags) {
            return false;
        }
        return (kColorIsKnown_Flag & fFlags) ? fColor == that.fColor : true;
    }

    /** The returned value reflects the common properties of the two inputs. */
    static GrProcessorAnalysisColor Combine(const GrProcessorAnalysisColor& a,
                                            const GrProcessorAnalysisColor& b) {
        GrProcessorAnalysisColor result;
        uint32_t commonFlags = a.fFlags & b.fFlags;
        if ((kColorIsKnown_Flag & commonFlags) && a.fColor == b.fColor) {
            result.fColor = a.fColor;
            result.fFlags = a.fFlags;
        } else if (kIsOpaque_Flag & commonFlags) {
            result.fFlags = kIsOpaque_Flag;
        }
        return result;
    }

private:
    enum Flags {
        kColorIsKnown_Flag = 0x1,
        kIsOpaque_Flag = 0x2,
    };
    uint32_t fFlags;
    GrColor fColor;
};

enum class GrProcessorAnalysisCoverage { kNone, kSingleChannel, kLCD };

/**
 * GrColorFragmentProcessorAnalysis gathers invariant data from a set of color fragment processor.
 * It is used to recognize optimizations that can simplify the generated shader or make blending
 * more effecient.
 */
class GrColorFragmentProcessorAnalysis {
public:
    GrColorFragmentProcessorAnalysis() = default;

    GrColorFragmentProcessorAnalysis(const GrProcessorAnalysisColor& input)
            : GrColorFragmentProcessorAnalysis() {
        fAllProcessorsCompatibleWithCoverageAsAlpha = true;
        fIsOpaque = input.isOpaque();
        GrColor color;
        if (input.isConstant(&color)) {
            fLastKnownOutputColor = GrColor4f::FromGrColor(color);
            fProcessorsVisitedWithKnownOutput = 0;
        }
    }

    void reset(const GrProcessorAnalysisColor& input) {
        *this = GrColorFragmentProcessorAnalysis(input);
    }

    /**
     * Runs through a series of processors and updates calculated values. This can be called
     * repeatedly for cases when the sequence of processors is not in a contiguous array.
     */
    void analyzeProcessors(const GrFragmentProcessor* const* processors, int cnt);

    bool isOpaque() const { return fIsOpaque; }

    /**
     * Are all the fragment processors compatible with conflating coverage with color prior to the
     * the first fragment processor. This result does not consider processors that should be
     * eliminated as indicated by initialProcessorsToEliminate().
     */
    bool allProcessorsCompatibleWithCoverageAsAlpha() const {
        return fAllProcessorsCompatibleWithCoverageAsAlpha;
    }

    /**
     * Do any of the fragment processors require local coords. This result does not consider
     * processors that should be eliminated as indicated by initialProcessorsToEliminate().
     */
    bool usesLocalCoords() const { return fUsesLocalCoords; }

    /**
     * If we detected that the result after the first N processors is a known color then we
     * eliminate those N processors and replace the GrDrawOp's color input to the GrPipeline with
     * the known output of the Nth processor, so that the Nth+1 fragment processor (or the XP if
     * there are only N processors) sees its expected input. If this returns 0 then there are no
     * processors to eliminate.
     */
    int initialProcessorsToEliminate(GrColor* newPipelineInputColor) const {
        if (fProcessorsVisitedWithKnownOutput > 0) {
            *newPipelineInputColor = fLastKnownOutputColor.toGrColor();
        }
        return SkTMax(0, fProcessorsVisitedWithKnownOutput);
    }

    int initialProcessorsToEliminate(GrColor4f* newPipelineInputColor) const {
        if (fProcessorsVisitedWithKnownOutput > 0) {
            *newPipelineInputColor = fLastKnownOutputColor;
        }
        return SkTMax(0, fProcessorsVisitedWithKnownOutput);
    }

    GrProcessorAnalysisColor outputColor() const {
        if (fProcessorsVisitedWithKnownOutput != fTotalProcessorsVisited) {
            return GrProcessorAnalysisColor(fIsOpaque ? GrProcessorAnalysisColor::Opaque::kYes
                                                      : GrProcessorAnalysisColor::Opaque::kNo);
        }
        return GrProcessorAnalysisColor(fLastKnownOutputColor.toGrColor());
    }

private:
    int fTotalProcessorsVisited = 0;
    // negative one means even the color is unknown before adding the first processor.
    int fProcessorsVisitedWithKnownOutput = -1;
    bool fIsOpaque = false;
    bool fAllProcessorsCompatibleWithCoverageAsAlpha = true;
    bool fUsesLocalCoords = false;
    GrColor4f fLastKnownOutputColor;
};

#endif