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
17struct GrUserStencilSettings;
18class GrAppliedClip;
19class GrXPFactory;
20
21class GrProcessorSet {
22private:
23 // Arbitrary constructor arg for empty set and analysis
24 enum class Empty { kEmpty };
25
26public:
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
158private:
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