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 "include/private/SkTemplates.h" |
12 | #include "src/gpu/GrFragmentProcessor.h" |
13 | #include "src/gpu/GrPaint.h" |
14 | #include "src/gpu/GrProcessorAnalysis.h" |
15 | #include "src/gpu/GrXferProcessor.h" |
16 | |
17 | struct GrUserStencilSettings; |
18 | class GrAppliedClip; |
19 | class GrXPFactory; |
20 | |
21 | class GrProcessorSet { |
22 | private: |
23 | // Arbitrary constructor arg for empty set and analysis |
24 | enum class Empty { kEmpty }; |
25 | |
26 | public: |
27 | GrProcessorSet(GrPaint&&); |
28 | GrProcessorSet(SkBlendMode); |
29 | GrProcessorSet(std::unique_ptr<GrFragmentProcessor> colorFP); |
30 | GrProcessorSet(GrProcessorSet&&); |
31 | GrProcessorSet(const GrProcessorSet&) = delete; |
32 | GrProcessorSet& operator=(const GrProcessorSet&) = delete; |
33 | |
34 | ~GrProcessorSet(); |
35 | |
36 | int numColorFragmentProcessors() const { return fColorFragmentProcessorCnt; } |
37 | int numCoverageFragmentProcessors() const { |
38 | return this->numFragmentProcessors() - fColorFragmentProcessorCnt; |
39 | } |
40 | |
41 | const GrFragmentProcessor* colorFragmentProcessor(int idx) const { |
42 | SkASSERT(idx < fColorFragmentProcessorCnt); |
43 | return fFragmentProcessors[idx + fFragmentProcessorOffset].get(); |
44 | } |
45 | const GrFragmentProcessor* coverageFragmentProcessor(int idx) const { |
46 | return fFragmentProcessors[idx + fColorFragmentProcessorCnt + |
47 | fFragmentProcessorOffset].get(); |
48 | } |
49 | |
50 | const GrXferProcessor* xferProcessor() const { |
51 | SkASSERT(this->isFinalized()); |
52 | return fXP.fProcessor; |
53 | } |
54 | sk_sp<const GrXferProcessor> refXferProcessor() const { |
55 | SkASSERT(this->isFinalized()); |
56 | return sk_ref_sp(fXP.fProcessor); |
57 | } |
58 | |
59 | std::unique_ptr<const GrFragmentProcessor> detachColorFragmentProcessor(int idx) { |
60 | SkASSERT(idx < fColorFragmentProcessorCnt); |
61 | return std::move(fFragmentProcessors[idx + fFragmentProcessorOffset]); |
62 | } |
63 | |
64 | std::unique_ptr<const GrFragmentProcessor> detachCoverageFragmentProcessor(int idx) { |
65 | return std::move( |
66 | fFragmentProcessors[idx + fFragmentProcessorOffset + fColorFragmentProcessorCnt]); |
67 | } |
68 | |
69 | /** Comparisons are only legal on finalized processor sets. */ |
70 | bool operator==(const GrProcessorSet& that) const; |
71 | bool operator!=(const GrProcessorSet& that) const { return !(*this == that); } |
72 | |
73 | /** |
74 | * This is used to report results of processor analysis when a processor set is finalized (see |
75 | * below). |
76 | */ |
77 | class Analysis { |
78 | public: |
79 | Analysis(const Analysis&) = default; |
80 | Analysis() { *reinterpret_cast<uint32_t*>(this) = 0; } |
81 | |
82 | bool isInitialized() const { return fIsInitialized; } |
83 | bool usesLocalCoords() const { return fUsesLocalCoords; } |
84 | bool requiresDstTexture() const { return fRequiresDstTexture; } |
85 | bool requiresNonOverlappingDraws() const { return fRequiresNonOverlappingDraws; } |
86 | bool isCompatibleWithCoverageAsAlpha() const { return fCompatibleWithCoverageAsAlpha; } |
87 | // Indicates whether all color fragment processors were eliminated in the analysis. |
88 | bool hasColorFragmentProcessor() const { return fHasColorFragmentProcessor; } |
89 | |
90 | bool inputColorIsIgnored() const { return fInputColorType == kIgnored_InputColorType; } |
91 | bool inputColorIsOverridden() const { |
92 | return fInputColorType == kOverridden_InputColorType; |
93 | } |
94 | |
95 | private: |
96 | constexpr Analysis(Empty) |
97 | : fUsesLocalCoords(false) |
98 | , fCompatibleWithCoverageAsAlpha(true) |
99 | , fRequiresDstTexture(false) |
100 | , fRequiresNonOverlappingDraws(false) |
101 | , fHasColorFragmentProcessor(false) |
102 | , fIsInitialized(true) |
103 | , fInputColorType(kOriginal_InputColorType) {} |
104 | enum InputColorType : uint32_t { |
105 | kOriginal_InputColorType, |
106 | kOverridden_InputColorType, |
107 | kIgnored_InputColorType |
108 | }; |
109 | |
110 | // MSVS 2015 won't pack different underlying types |
111 | using PackedBool = uint32_t; |
112 | using PackedInputColorType = uint32_t; |
113 | |
114 | PackedBool fUsesLocalCoords : 1; |
115 | PackedBool fCompatibleWithCoverageAsAlpha : 1; |
116 | PackedBool fRequiresDstTexture : 1; |
117 | PackedBool fRequiresNonOverlappingDraws : 1; |
118 | PackedBool fHasColorFragmentProcessor : 1; |
119 | PackedBool fIsInitialized : 1; |
120 | PackedInputColorType fInputColorType : 2; |
121 | |
122 | friend class GrProcessorSet; |
123 | }; |
124 | static_assert(sizeof(Analysis) <= sizeof(uint32_t)); |
125 | |
126 | /** |
127 | * This analyzes the processors given an op's input color and coverage as well as a clip. The |
128 | * state of the processor set may change to an equivalent but more optimal set of processors. |
129 | * This new state requires that the caller respect the returned 'inputColorOverride'. This is |
130 | * indicated by the returned Analysis's inputColorIsOverridden(). 'inputColorOverride' will not |
131 | * be written if the analysis does not override the input color. |
132 | * |
133 | * This must be called before the processor set is used to construct a GrPipeline and may only |
134 | * be called once. |
135 | * |
136 | * This also puts the processors in "pending execution" state and must be called when an op |
137 | * that owns a processor set is recorded to ensure pending and writes are propagated to |
138 | * resources referred to by the processors. Otherwise, data hazards may occur. |
139 | */ |
140 | Analysis finalize( |
141 | const GrProcessorAnalysisColor&, const GrProcessorAnalysisCoverage, |
142 | const GrAppliedClip*, const GrUserStencilSettings*, bool hasMixedSampledCoverage, |
143 | const GrCaps&, GrClampType, SkPMColor4f* inputColorOverride); |
144 | |
145 | bool isFinalized() const { return SkToBool(kFinalized_Flag & fFlags); } |
146 | |
147 | /** These are valid only for non-LCD coverage. */ |
148 | static const GrProcessorSet& EmptySet(); |
149 | static GrProcessorSet MakeEmptySet(); |
150 | static constexpr const Analysis EmptySetAnalysis() { return Analysis(Empty::kEmpty); } |
151 | |
152 | #ifdef SK_DEBUG |
153 | SkString dumpProcessors() const; |
154 | #endif |
155 | |
156 | void visitProxies(const GrOp::VisitProxyFunc& func) const; |
157 | |
158 | private: |
159 | GrProcessorSet(Empty) : fXP((const GrXferProcessor*)nullptr), fFlags(kFinalized_Flag) {} |
160 | |
161 | int numFragmentProcessors() const { |
162 | return fFragmentProcessors.count() - fFragmentProcessorOffset; |
163 | } |
164 | |
165 | const GrFragmentProcessor* fragmentProcessor(int idx) const { |
166 | return fFragmentProcessors[idx + fFragmentProcessorOffset].get(); |
167 | } |
168 | |
169 | // This absurdly large limit allows Analysis and this to pack fields together. |
170 | static constexpr int kMaxColorProcessors = UINT8_MAX; |
171 | |
172 | enum Flags : uint16_t { kFinalized_Flag = 0x1 }; |
173 | |
174 | union XP { |
175 | XP(const GrXPFactory* factory) : fFactory(factory) {} |
176 | XP(const GrXferProcessor* processor) : fProcessor(processor) {} |
177 | explicit XP(XP&& that) : fProcessor(that.fProcessor) { |
178 | SkASSERT(fProcessor == that.fProcessor); |
179 | that.fProcessor = nullptr; |
180 | } |
181 | const GrXPFactory* fFactory; |
182 | const GrXferProcessor* fProcessor; |
183 | }; |
184 | |
185 | const GrXPFactory* xpFactory() const { |
186 | SkASSERT(!this->isFinalized()); |
187 | return fXP.fFactory; |
188 | } |
189 | |
190 | SkAutoSTArray<4, std::unique_ptr<GrFragmentProcessor>> fFragmentProcessors; |
191 | XP fXP; |
192 | uint8_t fColorFragmentProcessorCnt = 0; |
193 | uint8_t fFragmentProcessorOffset = 0; |
194 | uint8_t fFlags; |
195 | }; |
196 | |
197 | #endif |
198 | |