Line data Source code
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 GrFragmentProcessor_DEFINED
9 : #define GrFragmentProcessor_DEFINED
10 :
11 : #include "GrProcessor.h"
12 :
13 : class GrCoordTransform;
14 : class GrGLSLFragmentProcessor;
15 : class GrInvariantOutput;
16 : class GrPipeline;
17 : class GrProcessorKeyBuilder;
18 : class GrShaderCaps;
19 : class GrSwizzle;
20 :
21 : /** Provides custom fragment shader code. Fragment processors receive an input color (vec4f) and
22 : produce an output color. They may reference textures and uniforms. They may use
23 : GrCoordTransforms to receive a transformation of the local coordinates that map from local space
24 : to the fragment being processed.
25 : */
26 : class GrFragmentProcessor : public GrResourceIOProcessor, public GrProgramElement {
27 : public:
28 : /**
29 : * In many instances (e.g. SkShader::asFragmentProcessor() implementations) it is desirable to
30 : * only consider the input color's alpha. However, there is a competing desire to have reusable
31 : * GrFragmentProcessor subclasses that can be used in other scenarios where the entire input
32 : * color is considered. This function exists to filter the input color and pass it to a FP. It
33 : * does so by returning a parent FP that multiplies the passed in FPs output by the parent's
34 : * input alpha. The passed in FP will not receive an input color.
35 : */
36 : static sk_sp<GrFragmentProcessor> MulOutputByInputAlpha(sk_sp<GrFragmentProcessor>);
37 :
38 : /**
39 : * This assumes that the input color to the returned processor will be unpremul and that the
40 : * passed processor (which becomes the returned processor's child) produces a premul output.
41 : * The result of the returned processor is a premul of its input color modulated by the child
42 : * processor's premul output.
43 : */
44 : static sk_sp<GrFragmentProcessor> MakeInputPremulAndMulByOutput(sk_sp<GrFragmentProcessor>);
45 :
46 : /**
47 : * Returns a parent fragment processor that adopts the passed fragment processor as a child.
48 : * The parent will ignore its input color and instead feed the passed in color as input to the
49 : * child.
50 : */
51 : static sk_sp<GrFragmentProcessor> OverrideInput(sk_sp<GrFragmentProcessor>, GrColor4f);
52 :
53 : /**
54 : * Returns a fragment processor that premuls the input before calling the passed in fragment
55 : * processor.
56 : */
57 : static sk_sp<GrFragmentProcessor> PremulInput(sk_sp<GrFragmentProcessor>);
58 :
59 : /**
60 : * Returns a fragment processor that calls the passed in fragment processor, and then premuls
61 : * the output.
62 : */
63 : static sk_sp<GrFragmentProcessor> PremulOutput(sk_sp<GrFragmentProcessor>);
64 :
65 : /**
66 : * Returns a fragment processor that calls the passed in fragment processor, and then unpremuls
67 : * the output.
68 : */
69 : static sk_sp<GrFragmentProcessor> UnpremulOutput(sk_sp<GrFragmentProcessor>);
70 :
71 : /**
72 : * Returns a fragment processor that calls the passed in fragment processor, and then swizzles
73 : * the output.
74 : */
75 : static sk_sp<GrFragmentProcessor> SwizzleOutput(sk_sp<GrFragmentProcessor>, const GrSwizzle&);
76 :
77 : /**
78 : * Returns a fragment processor that runs the passed in array of fragment processors in a
79 : * series. The original input is passed to the first, the first's output is passed to the
80 : * second, etc. The output of the returned processor is the output of the last processor of the
81 : * series.
82 : *
83 : * The array elements with be moved.
84 : */
85 : static sk_sp<GrFragmentProcessor> RunInSeries(sk_sp<GrFragmentProcessor>*, int cnt);
86 :
87 : ~GrFragmentProcessor() override;
88 :
89 : GrGLSLFragmentProcessor* createGLSLInstance() const;
90 :
91 0 : void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
92 0 : this->onGetGLSLProcessorKey(caps, b);
93 0 : for (int i = 0; i < fChildProcessors.count(); ++i) {
94 0 : fChildProcessors[i]->getGLSLProcessorKey(caps, b);
95 : }
96 0 : }
97 :
98 0 : int numCoordTransforms() const { return fCoordTransforms.count(); }
99 :
100 : /** Returns the coordinate transformation at index. index must be valid according to
101 : numTransforms(). */
102 0 : const GrCoordTransform& coordTransform(int index) const { return *fCoordTransforms[index]; }
103 :
104 0 : const SkTArray<const GrCoordTransform*, true>& coordTransforms() const {
105 0 : return fCoordTransforms;
106 : }
107 :
108 0 : int numChildProcessors() const { return fChildProcessors.count(); }
109 :
110 0 : const GrFragmentProcessor& childProcessor(int index) const { return *fChildProcessors[index]; }
111 :
112 : /** Do any of the coordtransforms for this processor require local coords? */
113 0 : bool usesLocalCoords() const { return SkToBool(fFlags & kUsesLocalCoords_Flag); }
114 :
115 : /** Does this FP need a vector to the nearest edge? */
116 0 : bool usesDistanceVectorField() const {
117 0 : return SkToBool(fFlags & kUsesDistanceVectorField_Flag);
118 : }
119 :
120 : /**
121 : * A GrDrawOp may premultiply its antialiasing coverage into its GrGeometryProcessor's color
122 : * output under the following scenario:
123 : * * all the color fragment processors report true to this query,
124 : * * all the coverage fragment processors report true to this query,
125 : * * the blend mode arithmetic allows for it it.
126 : * To be compatible a fragment processor's output must be a modulation of its input color or
127 : * alpha with a computed premultiplied color or alpha that is in 0..1 range. The computed color
128 : * or alpha that is modulated against the input cannot depend on the input's alpha. The computed
129 : * value cannot depend on the input's color channels unless it unpremultiplies the input color
130 : * channels by the input alpha.
131 : */
132 0 : bool compatibleWithCoverageAsAlpha() const {
133 0 : return SkToBool(fFlags & kCompatibleWithCoverageAsAlpha_OptimizationFlag);
134 : }
135 :
136 : /**
137 : * If this is true then all opaque input colors to the processor produce opaque output colors.
138 : */
139 0 : bool preservesOpaqueInput() const {
140 0 : return SkToBool(fFlags & kPreservesOpaqueInput_OptimizationFlag);
141 : }
142 :
143 : /**
144 : * Tests whether given a constant input color the processor produces a constant output color
145 : * (for all fragments). If true outputColor will contain the constant color produces for
146 : * inputColor.
147 : */
148 0 : bool hasConstantOutputForConstantInput(GrColor4f inputColor, GrColor4f* outputColor) const {
149 0 : if (fFlags & kConstantOutputForConstantInput_OptimizationFlag) {
150 0 : *outputColor = this->constantOutputForConstantInput(inputColor);
151 0 : return true;
152 : }
153 0 : return false;
154 : }
155 0 : bool hasConstantOutputForConstantInput() const {
156 0 : return SkToBool(fFlags & kConstantOutputForConstantInput_OptimizationFlag);
157 : }
158 :
159 : /** Returns true if this and other processor conservatively draw identically. It can only return
160 : true when the two processor are of the same subclass (i.e. they return the same object from
161 : from getFactory()).
162 :
163 : A return value of true from isEqual() should not be used to test whether the processor would
164 : generate the same shader code. To test for identical code generation use getGLSLProcessorKey
165 : */
166 : bool isEqual(const GrFragmentProcessor& that) const;
167 :
168 : /**
169 : * Pre-order traversal of a FP hierarchy, or of the forest of FPs in a GrPipeline. In the latter
170 : * case the tree rooted at each FP in the GrPipeline is visited successively.
171 : */
172 0 : class Iter : public SkNoncopyable {
173 : public:
174 0 : explicit Iter(const GrFragmentProcessor* fp) { fFPStack.push_back(fp); }
175 : explicit Iter(const GrPipeline& pipeline);
176 : const GrFragmentProcessor* next();
177 :
178 : private:
179 : SkSTArray<4, const GrFragmentProcessor*, true> fFPStack;
180 : };
181 :
182 : /**
183 : * Iterates over all the Ts owned by a GrFragmentProcessor and its children or over all the Ts
184 : * owned by the forest of GrFragmentProcessors in a GrPipeline. FPs are visited in the same
185 : * order as Iter and each of an FP's Ts are visited in order.
186 : */
187 : template <typename T, typename BASE,
188 : int (BASE::*COUNT)() const,
189 : const T& (BASE::*GET)(int) const>
190 0 : class FPItemIter : public SkNoncopyable {
191 : public:
192 0 : explicit FPItemIter(const GrFragmentProcessor* fp)
193 : : fCurrFP(nullptr)
194 : , fCTIdx(0)
195 0 : , fFPIter(fp) {
196 0 : fCurrFP = fFPIter.next();
197 0 : }
198 0 : explicit FPItemIter(const GrPipeline& pipeline)
199 : : fCurrFP(nullptr)
200 : , fCTIdx(0)
201 0 : , fFPIter(pipeline) {
202 0 : fCurrFP = fFPIter.next();
203 0 : }
204 :
205 0 : const T* next() {
206 0 : if (!fCurrFP) {
207 0 : return nullptr;
208 : }
209 0 : while (fCTIdx == (fCurrFP->*COUNT)()) {
210 0 : fCTIdx = 0;
211 0 : fCurrFP = fFPIter.next();
212 0 : if (!fCurrFP) {
213 0 : return nullptr;
214 : }
215 : }
216 0 : return &(fCurrFP->*GET)(fCTIdx++);
217 : }
218 :
219 : private:
220 : const GrFragmentProcessor* fCurrFP;
221 : int fCTIdx;
222 : GrFragmentProcessor::Iter fFPIter;
223 : };
224 :
225 : using CoordTransformIter = FPItemIter<GrCoordTransform,
226 : GrFragmentProcessor,
227 : &GrFragmentProcessor::numCoordTransforms,
228 : &GrFragmentProcessor::coordTransform>;
229 :
230 : using TextureAccessIter = FPItemIter<TextureSampler,
231 : GrResourceIOProcessor,
232 : &GrResourceIOProcessor::numTextureSamplers,
233 : &GrResourceIOProcessor::textureSampler>;
234 :
235 : protected:
236 : enum OptimizationFlags : uint32_t {
237 : kNone_OptimizationFlags,
238 : kCompatibleWithCoverageAsAlpha_OptimizationFlag = 0x1,
239 : kPreservesOpaqueInput_OptimizationFlag = 0x2,
240 : kConstantOutputForConstantInput_OptimizationFlag = 0x4,
241 : kAll_OptimizationFlags = kCompatibleWithCoverageAsAlpha_OptimizationFlag |
242 : kPreservesOpaqueInput_OptimizationFlag |
243 : kConstantOutputForConstantInput_OptimizationFlag
244 : };
245 : GR_DECL_BITFIELD_OPS_FRIENDS(OptimizationFlags)
246 :
247 0 : GrFragmentProcessor(OptimizationFlags optimizationFlags) : fFlags(optimizationFlags) {
248 0 : SkASSERT((fFlags & ~kAll_OptimizationFlags) == 0);
249 0 : }
250 :
251 0 : OptimizationFlags optimizationFlags() const {
252 0 : return static_cast<OptimizationFlags>(kAll_OptimizationFlags & fFlags);
253 : }
254 :
255 : /**
256 : * This allows one subclass to access another subclass's implementation of
257 : * constantOutputForConstantInput. It must only be called when
258 : * hasConstantOutputForConstantInput() is known to be true.
259 : */
260 0 : static GrColor4f ConstantOutputForConstantInput(const GrFragmentProcessor& fp,
261 : GrColor4f input) {
262 0 : SkASSERT(fp.hasConstantOutputForConstantInput());
263 0 : return fp.constantOutputForConstantInput(input);
264 : }
265 :
266 : /**
267 : * Fragment Processor subclasses call this from their constructor to register coordinate
268 : * transformations. Coord transforms provide a mechanism for a processor to receive coordinates
269 : * in their FS code. The matrix expresses a transformation from local space. For a given
270 : * fragment the matrix will be applied to the local coordinate that maps to the fragment.
271 : *
272 : * When the transformation has perspective, the transformed coordinates will have
273 : * 3 components. Otherwise they'll have 2.
274 : *
275 : * This must only be called from the constructor because GrProcessors are immutable. The
276 : * processor subclass manages the lifetime of the transformations (this function only stores a
277 : * pointer). The GrCoordTransform is typically a member field of the GrProcessor subclass.
278 : *
279 : * A processor subclass that has multiple methods of construction should always add its coord
280 : * transforms in a consistent order. The non-virtual implementation of isEqual() automatically
281 : * compares transforms and will assume they line up across the two processor instances.
282 : */
283 : void addCoordTransform(const GrCoordTransform*);
284 :
285 : /**
286 : * FragmentProcessor subclasses call this from their constructor to register any child
287 : * FragmentProcessors they have. This must be called AFTER all texture accesses and coord
288 : * transforms have been added.
289 : * This is for processors whose shader code will be composed of nested processors whose output
290 : * colors will be combined somehow to produce its output color. Registering these child
291 : * processors will allow the ProgramBuilder to automatically handle their transformed coords and
292 : * texture accesses and mangle their uniform and output color names.
293 : */
294 : int registerChildProcessor(sk_sp<GrFragmentProcessor> child);
295 :
296 : /**
297 : * Sub-classes should call this in their constructors if they need access to a distance
298 : * vector field to the nearest edge
299 : */
300 : void setWillUseDistanceVectorField() { fFlags |= kUsesDistanceVectorField_Flag; }
301 :
302 : private:
303 0 : void addPendingIOs() const override { GrResourceIOProcessor::addPendingIOs(); }
304 0 : void removeRefs() const override { GrResourceIOProcessor::removeRefs(); }
305 0 : void pendingIOComplete() const override { GrResourceIOProcessor::pendingIOComplete(); }
306 :
307 : void notifyRefCntIsZero() const final;
308 :
309 0 : virtual GrColor4f constantOutputForConstantInput(GrColor4f /* inputColor */) const {
310 0 : SkFAIL("Subclass must override this if advertising this optimization.");
311 0 : return GrColor4f::TransparentBlack();
312 : }
313 :
314 : /** Returns a new instance of the appropriate *GL* implementation class
315 : for the given GrFragmentProcessor; caller is responsible for deleting
316 : the object. */
317 : virtual GrGLSLFragmentProcessor* onCreateGLSLInstance() const = 0;
318 :
319 : /** Implemented using GLFragmentProcessor::GenKey as described in this class's comment. */
320 : virtual void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const = 0;
321 :
322 : /**
323 : * Subclass implements this to support isEqual(). It will only be called if it is known that
324 : * the two processors are of the same subclass (i.e. they return the same object from
325 : * getFactory()). The processor subclass should not compare its coord transforms as that will
326 : * be performed automatically in the non-virtual isEqual().
327 : */
328 : virtual bool onIsEqual(const GrFragmentProcessor&) const = 0;
329 :
330 : bool hasSameTransforms(const GrFragmentProcessor&) const;
331 :
332 : enum PrivateFlags {
333 : kFirstPrivateFlag = kAll_OptimizationFlags + 1,
334 : kUsesLocalCoords_Flag = kFirstPrivateFlag,
335 : kUsesDistanceVectorField_Flag = kFirstPrivateFlag << 1,
336 : };
337 :
338 : mutable uint32_t fFlags = 0;
339 :
340 : SkSTArray<4, const GrCoordTransform*, true> fCoordTransforms;
341 :
342 : /**
343 : * This is not SkSTArray<1, sk_sp<GrFragmentProcessor>> because this class holds strong
344 : * references until notifyRefCntIsZero and then it holds pending executions.
345 : */
346 : SkSTArray<1, GrFragmentProcessor*, true> fChildProcessors;
347 :
348 : typedef GrProcessor INHERITED;
349 : };
350 :
351 0 : GR_MAKE_BITFIELD_OPS(GrFragmentProcessor::OptimizationFlags)
352 :
353 : #endif
|