1 /*
2  * Copyright 2017 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 GrProcessorSet_DEFINED
9 #define GrProcessorSet_DEFINED
10 
11 #include "GrFragmentProcessor.h"
12 #include "GrPaint.h"
13 #include "GrPipelineAnalysis.h"
14 #include "SkTemplates.h"
15 
16 class GrAppliedClip;
17 class GrXPFactory;
18 
19 class GrProcessorSet : private SkNoncopyable {
20 public:
21     GrProcessorSet(GrPaint&& paint);
22 
23     ~GrProcessorSet();
24 
25     /**
26      * If an op is recorded with this processor set then this must be called to ensure pending
27      * reads and writes are propagated to resources referred to by the processors. Otherwise,
28      * data hazards may occur.
29      */
30     void makePendingExecution();
isPendingExecution()31     bool isPendingExecution() const { return SkToBool(kPendingExecution_Flag & fFlags); }
32 
numColorFragmentProcessors()33     int numColorFragmentProcessors() const { return fColorFragmentProcessorCnt; }
numCoverageFragmentProcessors()34     int numCoverageFragmentProcessors() const {
35         return this->numFragmentProcessors() - fColorFragmentProcessorCnt;
36     }
numFragmentProcessors()37     int numFragmentProcessors() const {
38         return fFragmentProcessors.count() - fFragmentProcessorOffset;
39     }
40 
colorFragmentProcessor(int idx)41     const GrFragmentProcessor* colorFragmentProcessor(int idx) const {
42         SkASSERT(idx < fColorFragmentProcessorCnt);
43         return fFragmentProcessors[idx + fFragmentProcessorOffset];
44     }
coverageFragmentProcessor(int idx)45     const GrFragmentProcessor* coverageFragmentProcessor(int idx) const {
46         return fFragmentProcessors[idx + fColorFragmentProcessorCnt + fFragmentProcessorOffset];
47     }
48 
xpFactory()49     const GrXPFactory* xpFactory() const { return fXPFactory; }
50 
usesDistanceVectorField()51     bool usesDistanceVectorField() const { return SkToBool(fFlags & kUseDistanceVectorField_Flag); }
disableOutputConversionToSRGB()52     bool disableOutputConversionToSRGB() const {
53         return SkToBool(fFlags & kDisableOutputConversionToSRGB_Flag);
54     }
allowSRGBInputs()55     bool allowSRGBInputs() const { return SkToBool(fFlags & kAllowSRGBInputs_Flag); }
56 
57     bool operator==(const GrProcessorSet& that) const;
58     bool operator!=(const GrProcessorSet& that) const { return !(*this == that); }
59 
60     /**
61      * This is used to track analysis of color and coverage values through the fragment processors.
62      */
63     class FragmentProcessorAnalysis {
64     public:
65         /**
66          * This constructor allows an op to record its initial color in a FragmentProcessorAnalysis
67          * member and then run analysis later when the analysis inputs are available. If the
68          * analysis produces color fragment processor elimination then the input color is replaced
69          * by the expected input to the first non-eliminated processor. Otherwise, the original
70          * input color is preserved. The only reason to use this is to save space on the op by not
71          * separately storing the initial color.
72          */
FragmentProcessorAnalysis(GrColor initialColor)73         explicit FragmentProcessorAnalysis(GrColor initialColor) : FragmentProcessorAnalysis() {
74             fInputColor = initialColor;
75             fValidInputColor = true;
76         }
77 
FragmentProcessorAnalysis()78         FragmentProcessorAnalysis()
79                 : fIsInitializedWithProcessorSet(false)
80                 , fCompatibleWithCoverageAsAlpha(true)
81                 , fValidInputColor(false)
82                 , fOutputCoverageType(static_cast<unsigned>(GrPipelineAnalysisCoverage::kNone))
83                 , fOutputColorType(static_cast<unsigned>(ColorType::kUnknown))
84                 , fInitialColorProcessorsToEliminate(0) {}
85 
86         // This version is used by a unit test that assumes no clip, no processors, and no PLS.
87         FragmentProcessorAnalysis(const GrPipelineAnalysisColor&, GrPipelineAnalysisCoverage,
88                                   const GrCaps&);
89 
90         void init(const GrPipelineAnalysisColor&, GrPipelineAnalysisCoverage, const GrProcessorSet&,
91                   const GrAppliedClip*, const GrCaps&);
92 
isInitializedWithProcessorSet()93         bool isInitializedWithProcessorSet() const { return fIsInitializedWithProcessorSet; }
94 
95         /**
96          * If the return is greater than or equal to zero then 'newInputColor' should be used as the
97          * input color to the GrPipeline derived from this processor set, replacing the GrDrawOp's
98          * initial color. If the return is less than zero then newInputColor has not been
99          * modified and no modification need be made to the pipeline's input color by the op.
100          */
getInputColorOverrideAndColorProcessorEliminationCount(GrColor * newInputColor)101         int getInputColorOverrideAndColorProcessorEliminationCount(GrColor* newInputColor) const {
102             if (fValidInputColor) {
103                 *newInputColor = fInputColor;
104                 return fInitialColorProcessorsToEliminate;
105             }
106             SkASSERT(!fInitialColorProcessorsToEliminate);
107             return -1;
108         }
109 
110         /**
111          * Valid if initialProcessorsToEliminate returns true or this analysis was initialized with
112          * a known color via constructor or init(). If color fragment processors are eliminated then
113          * this returns the expected input to the first non-eliminated processors. Otherwise it is
114          * the color passed to the constructor or init().
115          */
inputColor()116         GrColor inputColor() const {
117             SkASSERT(fValidInputColor);
118             return fInputColor;
119         }
120 
usesLocalCoords()121         bool usesLocalCoords() const { return fUsesLocalCoords; }
isCompatibleWithCoverageAsAlpha()122         bool isCompatibleWithCoverageAsAlpha() const { return fCompatibleWithCoverageAsAlpha; }
isOutputColorOpaque()123         bool isOutputColorOpaque() const {
124             return ColorType::kOpaque == this->outputColorType() ||
125                    ColorType::kOpaqueConstant == this->outputColorType();
126         }
127         bool hasKnownOutputColor(GrColor* color = nullptr) const {
128             bool constant = ColorType::kConstant == this->outputColorType() ||
129                             ColorType::kOpaqueConstant == this->outputColorType();
130             if (constant && color) {
131                 *color = fKnownOutputColor;
132             }
133             return constant;
134         }
outputCoverageType()135         GrPipelineAnalysisCoverage outputCoverageType() const {
136             return static_cast<GrPipelineAnalysisCoverage>(fOutputCoverageType);
137         }
hasCoverage()138         bool hasCoverage() const {
139             return this->outputCoverageType() != GrPipelineAnalysisCoverage::kNone;
140         }
141 
142     private:
143         enum class ColorType : unsigned { kUnknown, kOpaqueConstant, kConstant, kOpaque };
144 
outputColorType()145         ColorType outputColorType() const { return static_cast<ColorType>(fOutputColorType); }
146 
147         void internalInit(const GrPipelineAnalysisColor&, const GrPipelineAnalysisCoverage,
148                           const GrProcessorSet&, const GrFragmentProcessor* clipFP, const GrCaps&);
149 
150         // MSVS 2015 won't pack a bool with an unsigned.
151         using PackedBool = unsigned;
152 
153         PackedBool fIsInitializedWithProcessorSet : 1;
154         PackedBool fUsesLocalCoords : 1;
155         PackedBool fCompatibleWithCoverageAsAlpha : 1;
156         PackedBool fValidInputColor : 1;
157         unsigned fOutputCoverageType : 2;
158         unsigned fOutputColorType : 2;
159         unsigned fInitialColorProcessorsToEliminate : 32 - 8;
160 
161         GrColor fInputColor;
162         GrColor fKnownOutputColor;
163 
164         friend class GrProcessorSet;
165     };
166     GR_STATIC_ASSERT(sizeof(FragmentProcessorAnalysis) == 2 * sizeof(GrColor) + sizeof(uint32_t));
167 
168     void analyzeAndEliminateFragmentProcessors(FragmentProcessorAnalysis*,
169                                                const GrPipelineAnalysisColor& colorInput,
170                                                const GrPipelineAnalysisCoverage coverageInput,
171                                                const GrAppliedClip*, const GrCaps&);
172 
173 private:
174     // This absurdly large limit allows FragmentProcessorAnalysis and this to pack fields together.
175     static constexpr int kMaxColorProcessors = UINT8_MAX;
176 
177     enum Flags : uint16_t {
178         kUseDistanceVectorField_Flag = 0x1,
179         kDisableOutputConversionToSRGB_Flag = 0x2,
180         kAllowSRGBInputs_Flag = 0x4,
181         kPendingExecution_Flag = 0x8
182     };
183 
184     const GrXPFactory* fXPFactory = nullptr;
185     SkAutoSTArray<4, const GrFragmentProcessor*> fFragmentProcessors;
186     uint8_t fColorFragmentProcessorCnt;
187     uint8_t fFragmentProcessorOffset = 0;
188     uint8_t fFlags;
189 };
190 
191 #endif
192