1/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef GrProcessorAnalysis_DEFINED
9#define GrProcessorAnalysis_DEFINED
10
11#include "GrColor.h"
12
13class GrDrawOp;
14class GrFragmentProcessor;
15class GrPrimitiveProcessor;
16
17class GrProcessorAnalysisColor {
18public:
19    enum class Opaque {
20        kNo,
21        kYes,
22    };
23
24    constexpr GrProcessorAnalysisColor(Opaque opaque = Opaque::kNo)
25            : fFlags(opaque == Opaque::kYes ? kIsOpaque_Flag : 0), fColor(0) {}
26
27    GrProcessorAnalysisColor(GrColor color) { this->setToConstant(color); }
28
29    void setToConstant(GrColor color) {
30        fColor = color;
31        if (GrColorIsOpaque(color)) {
32            fFlags = kColorIsKnown_Flag | kIsOpaque_Flag;
33        } else {
34            fFlags = kColorIsKnown_Flag;
35        }
36    }
37
38    void setToUnknown() { fFlags = 0; }
39
40    void setToUnknownOpaque() { fFlags = kIsOpaque_Flag; }
41
42    bool isOpaque() const { return SkToBool(kIsOpaque_Flag & fFlags); }
43
44    bool isConstant(GrColor* color = nullptr) const {
45        if (kColorIsKnown_Flag & fFlags) {
46            if (color) {
47                *color = fColor;
48            }
49            return true;
50        }
51        return false;
52    }
53
54    bool operator==(const GrProcessorAnalysisColor& that) const {
55        if (fFlags != that.fFlags) {
56            return false;
57        }
58        return (kColorIsKnown_Flag & fFlags) ? fColor == that.fColor : true;
59    }
60
61    /** The returned value reflects the common properties of the two inputs. */
62    static GrProcessorAnalysisColor Combine(const GrProcessorAnalysisColor& a,
63                                            const GrProcessorAnalysisColor& b) {
64        GrProcessorAnalysisColor result;
65        uint32_t commonFlags = a.fFlags & b.fFlags;
66        if ((kColorIsKnown_Flag & commonFlags) && a.fColor == b.fColor) {
67            result.fColor = a.fColor;
68            result.fFlags = a.fFlags;
69        } else if (kIsOpaque_Flag & commonFlags) {
70            result.fFlags = kIsOpaque_Flag;
71        }
72        return result;
73    }
74
75private:
76    enum Flags {
77        kColorIsKnown_Flag = 0x1,
78        kIsOpaque_Flag = 0x2,
79    };
80    uint32_t fFlags;
81    GrColor fColor;
82};
83
84enum class GrProcessorAnalysisCoverage { kNone, kSingleChannel, kLCD };
85
86/**
87 * GrColorFragmentProcessorAnalysis gathers invariant data from a set of color fragment processor.
88 * It is used to recognize optimizations that can simplify the generated shader or make blending
89 * more effecient.
90 */
91class GrColorFragmentProcessorAnalysis {
92public:
93    GrColorFragmentProcessorAnalysis() = delete;
94
95    GrColorFragmentProcessorAnalysis(const GrProcessorAnalysisColor& input,
96                                     const GrFragmentProcessor* const* processors,
97                                     int cnt);
98
99    bool isOpaque() const { return fIsOpaque; }
100
101    /**
102     * Are all the fragment processors compatible with conflating coverage with color prior to the
103     * the first fragment processor. This result assumes that processors that should be eliminated
104     * as indicated by initialProcessorsToEliminate() are in fact eliminated.
105     */
106    bool allProcessorsCompatibleWithCoverageAsAlpha() const {
107        return fCompatibleWithCoverageAsAlpha;
108    }
109
110    /**
111     * Do any of the fragment processors require local coords. This result assumes that
112     * processors that should be eliminated as indicated by initialProcessorsToEliminate() are in
113     * fact eliminated.
114     */
115    bool usesLocalCoords() const { return fUsesLocalCoords; }
116
117    /**
118     * If we detected that the result after the first N processors is a known color then we
119     * eliminate those N processors and replace the GrDrawOp's color input to the GrPipeline with
120     * the known output of the Nth processor, so that the Nth+1 fragment processor (or the XP if
121     * there are only N processors) sees its expected input. If this returns 0 then there are no
122     * processors to eliminate.
123     */
124    int initialProcessorsToEliminate(GrColor* newPipelineInputColor) const {
125        if (fProcessorsToEliminate > 0) {
126            *newPipelineInputColor = fLastKnownOutputColor.toGrColor();
127        }
128        return fProcessorsToEliminate;
129    }
130
131    int initialProcessorsToEliminate(GrColor4f* newPipelineInputColor) const {
132        if (fProcessorsToEliminate > 0) {
133            *newPipelineInputColor = fLastKnownOutputColor;
134        }
135        return fProcessorsToEliminate;
136    }
137
138    /**
139     * Provides known information about the last processor's output color.
140     */
141    GrProcessorAnalysisColor outputColor() const {
142        if (fKnowOutputColor) {
143            return fLastKnownOutputColor.toGrColor();
144        }
145        return fIsOpaque ? GrProcessorAnalysisColor::Opaque::kYes
146                         : GrProcessorAnalysisColor::Opaque::kNo;
147    }
148
149private:
150    bool fIsOpaque;
151    bool fCompatibleWithCoverageAsAlpha;
152    bool fUsesLocalCoords;
153    bool fKnowOutputColor;
154    int fProcessorsToEliminate;
155    GrColor4f fLastKnownOutputColor;
156};
157
158#endif
159