blob: 0d41a267de2e78b6e2049dc93caab1b8ca6d504e [file] [log] [blame]
bsalomon6251d172014-10-15 10:50:36 -07001/*
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
13class GrCoordTransform;
egdaniel64c47282015-11-13 06:54:19 -080014class GrGLSLFragmentProcessor;
bsalomonc21b09e2015-08-28 18:46:56 -070015class GrInvariantOutput;
bsalomona624bf32016-09-20 09:12:47 -070016class GrPipeline;
joshualitteb2a6762014-12-04 11:35:33 -080017class GrProcessorKeyBuilder;
Brian Salomon94efbf52016-11-29 13:43:05 -050018class GrShaderCaps;
bsalomon6251d172014-10-15 10:50:36 -070019
20/** Provides custom fragment shader code. Fragment processors receive an input color (vec4f) and
21 produce an output color. They may reference textures and uniforms. They may use
22 GrCoordTransforms to receive a transformation of the local coordinates that map from local space
23 to the fragment being processed.
24 */
25class GrFragmentProcessor : public GrProcessor {
26public:
bsalomon87ba62e2015-09-22 06:41:59 -070027 /**
28 * In many instances (e.g. SkShader::asFragmentProcessor() implementations) it is desirable to
29 * only consider the input color's alpha. However, there is a competing desire to have reusable
30 * GrFragmentProcessor subclasses that can be used in other scenarios where the entire input
31 * color is considered. This function exists to filter the input color and pass it to a FP. It
32 * does so by returning a parent FP that multiplies the passed in FPs output by the parent's
33 * input alpha. The passed in FP will not receive an input color.
34 */
bungeman06ca8ec2016-06-09 08:01:03 -070035 static sk_sp<GrFragmentProcessor> MulOutputByInputAlpha(sk_sp<GrFragmentProcessor>);
bsalomonf1b7a1d2015-09-28 06:26:28 -070036
37 /**
38 * Similar to the above but it modulates the output r,g,b of the child processor by the input
39 * rgb and then multiplies all the components by the input alpha. This effectively modulates
40 * the child processor's premul color by a unpremul'ed input and produces a premul output
41 */
bungeman06ca8ec2016-06-09 08:01:03 -070042 static sk_sp<GrFragmentProcessor> MulOutputByInputUnpremulColor(sk_sp<GrFragmentProcessor>);
bsalomonf1b7a1d2015-09-28 06:26:28 -070043
44 /**
bsalomone25eea42015-09-29 06:38:55 -070045 * Returns a parent fragment processor that adopts the passed fragment processor as a child.
46 * The parent will ignore its input color and instead feed the passed in color as input to the
47 * child.
bsalomonf1b7a1d2015-09-28 06:26:28 -070048 */
brianosman4cea3b92016-09-08 09:33:50 -070049 static sk_sp<GrFragmentProcessor> OverrideInput(sk_sp<GrFragmentProcessor>, GrColor4f);
bsalomon87ba62e2015-09-22 06:41:59 -070050
bsalomone25eea42015-09-29 06:38:55 -070051 /**
dvonbeckc526da92016-07-20 11:20:30 -070052 * Returns a fragment processor that premuls the input before calling the passed in fragment
53 * processor.
54 */
55 static sk_sp<GrFragmentProcessor> PremulInput(sk_sp<GrFragmentProcessor>);
56
57 /**
bsalomone25eea42015-09-29 06:38:55 -070058 * Returns a fragment processor that runs the passed in array of fragment processors in a
59 * series. The original input is passed to the first, the first's output is passed to the
60 * second, etc. The output of the returned processor is the output of the last processor of the
61 * series.
bungeman06ca8ec2016-06-09 08:01:03 -070062 *
63 * The array elements with be moved.
bsalomone25eea42015-09-29 06:38:55 -070064 */
bungeman06ca8ec2016-06-09 08:01:03 -070065 static sk_sp<GrFragmentProcessor> RunInSeries(sk_sp<GrFragmentProcessor>*, int cnt);
bsalomone25eea42015-09-29 06:38:55 -070066
bsalomonac856c92015-08-27 06:30:17 -070067 ~GrFragmentProcessor() override;
68
egdaniel57d3b032015-11-13 11:57:27 -080069 GrGLSLFragmentProcessor* createGLSLInstance() const;
joshualitteb2a6762014-12-04 11:35:33 -080070
Brian Salomon94efbf52016-11-29 13:43:05 -050071 void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
egdaniel57d3b032015-11-13 11:57:27 -080072 this->onGetGLSLProcessorKey(caps, b);
wangyix4b3050b2015-08-04 07:59:37 -070073 for (int i = 0; i < fChildProcessors.count(); ++i) {
egdaniel57d3b032015-11-13 11:57:27 -080074 fChildProcessors[i]->getGLSLProcessorKey(caps, b);
wangyix4b3050b2015-08-04 07:59:37 -070075 }
76 }
77
bsalomona624bf32016-09-20 09:12:47 -070078 int numCoordTransforms() const { return fCoordTransforms.count(); }
bsalomon6251d172014-10-15 10:50:36 -070079
80 /** Returns the coordinate transformation at index. index must be valid according to
81 numTransforms(). */
82 const GrCoordTransform& coordTransform(int index) const { return *fCoordTransforms[index]; }
83
joshualittabb52a12015-01-13 15:02:10 -080084 const SkTArray<const GrCoordTransform*, true>& coordTransforms() const {
85 return fCoordTransforms;
86 }
87
wangyix4b3050b2015-08-04 07:59:37 -070088 int numChildProcessors() const { return fChildProcessors.count(); }
89
bsalomonac856c92015-08-27 06:30:17 -070090 const GrFragmentProcessor& childProcessor(int index) const { return *fChildProcessors[index]; }
wangyix4b3050b2015-08-04 07:59:37 -070091
joshualitt290c09b2014-12-19 13:45:20 -080092 /** Do any of the coordtransforms for this processor require local coords? */
Brian Salomon587e08f2017-01-27 10:59:27 -050093 bool usesLocalCoords() const { return SkToBool(fFlags & kUsesLocalCoords_Flag); }
joshualitt290c09b2014-12-19 13:45:20 -080094
dvonbeck9b03e7b2016-08-01 11:01:56 -070095 /** Does this FP need a vector to the nearest edge? */
Brian Salomon587e08f2017-01-27 10:59:27 -050096 bool usesDistanceVectorField() const {
97 return SkToBool(fFlags & kUsesDistanceVectorField_Flag);
98 }
99
100 /**
101 * True if the processor's output is a modulation of its input color or alpha with a computed
102 * color or alpha in the 0..1 range. If true and the blend mode allows it we may fold coverage
103 * into the first color fragment processor's input.
104 */
105 bool modulatesInput() const { return SkToBool(fFlags & kModulatesInput_OptimizationFlag); }
106
107 /**
108 * If this is true then all opaque input colors to the processor produce opaque output colors.
109 */
110 bool preservesOpaqueInput() const {
111 return SkToBool(fFlags & kPreservesOpaqueInput_OptimizationFlag);
112 }
113
114 /**
115 * Tests whether given a constant input color the processor produces a constant output color
116 * (for all fragments). If true outputColor will contain the constant color produces for
117 * inputColor.
118 */
119 bool hasConstantOutputForConstantInput(GrColor4f inputColor, GrColor4f* outputColor) const {
120 if (fFlags & kConstantOutputForConstantInput_OptimizationFlag) {
121 *outputColor = this->constantOutputForConstantInput(inputColor);
122 return true;
123 }
124 return false;
125 }
126 bool hasConstantOutputForConstantInput() const {
127 return SkToBool(fFlags & kConstantOutputForConstantInput_OptimizationFlag);
128 }
dvonbeck9b03e7b2016-08-01 11:01:56 -0700129
joshualitteb2a6762014-12-04 11:35:33 -0800130 /** Returns true if this and other processor conservatively draw identically. It can only return
131 true when the two processor are of the same subclass (i.e. they return the same object from
bsalomon6251d172014-10-15 10:50:36 -0700132 from getFactory()).
133
joshualitteb2a6762014-12-04 11:35:33 -0800134 A return value of true from isEqual() should not be used to test whether the processor would
egdaniel57d3b032015-11-13 11:57:27 -0800135 generate the same shader code. To test for identical code generation use getGLSLProcessorKey
136 */
bsalomon7312ff82016-09-12 08:55:38 -0700137 bool isEqual(const GrFragmentProcessor& that) const;
bsalomon6251d172014-10-15 10:50:36 -0700138
joshualitt56995b52014-12-11 15:44:02 -0800139 /**
140 * This function is used to perform optimizations. When called the invarientOuput param
141 * indicate whether the input components to this processor in the FS will have known values.
142 * In inout the validFlags member is a bitfield of GrColorComponentFlags. The isSingleComponent
143 * member indicates whether the input will be 1 or 4 bytes. The function updates the members of
144 * inout to indicate known values of its output. A component of the color member only has
145 * meaning if the corresponding bit in validFlags is set.
146 */
bsalomonc21b09e2015-08-28 18:46:56 -0700147 void computeInvariantOutput(GrInvariantOutput* inout) const {
148 this->onComputeInvariantOutput(inout);
149 }
joshualitt56995b52014-12-11 15:44:02 -0800150
bsalomona624bf32016-09-20 09:12:47 -0700151 /**
152 * Pre-order traversal of a FP hierarchy, or of the forest of FPs in a GrPipeline. In the latter
153 * case the tree rooted at each FP in the GrPipeline is visited successively.
bsalomonb58a2b42016-09-26 06:55:02 -0700154 */
bsalomona624bf32016-09-20 09:12:47 -0700155 class Iter : public SkNoncopyable {
156 public:
157 explicit Iter(const GrFragmentProcessor* fp) { fFPStack.push_back(fp); }
158 explicit Iter(const GrPipeline& pipeline);
159 const GrFragmentProcessor* next();
160
161 private:
162 SkSTArray<4, const GrFragmentProcessor*, true> fFPStack;
163 };
164
165 /**
bsalomonb58a2b42016-09-26 06:55:02 -0700166 * Iterates over all the Ts owned by a GrFragmentProcessor and its children or over all the Ts
167 * owned by the forest of GrFragmentProcessors in a GrPipeline. FPs are visited in the same
168 * order as Iter and each of an FP's Ts are visited in order.
bsalomona624bf32016-09-20 09:12:47 -0700169 */
bsalomonb58a2b42016-09-26 06:55:02 -0700170 template <typename T, typename BASE,
171 int (BASE::*COUNT)() const,
172 const T& (BASE::*GET)(int) const>
173 class FPItemIter : public SkNoncopyable {
bsalomona624bf32016-09-20 09:12:47 -0700174 public:
bsalomonb58a2b42016-09-26 06:55:02 -0700175 explicit FPItemIter(const GrFragmentProcessor* fp)
176 : fCurrFP(nullptr)
177 , fCTIdx(0)
178 , fFPIter(fp) {
179 fCurrFP = fFPIter.next();
180 }
181 explicit FPItemIter(const GrPipeline& pipeline)
bsalomona624bf32016-09-20 09:12:47 -0700182 : fCurrFP(nullptr)
183 , fCTIdx(0)
184 , fFPIter(pipeline) {
185 fCurrFP = fFPIter.next();
186 }
bsalomonb58a2b42016-09-26 06:55:02 -0700187
188 const T* next() {
189 if (!fCurrFP) {
190 return nullptr;
191 }
192 while (fCTIdx == (fCurrFP->*COUNT)()) {
193 fCTIdx = 0;
194 fCurrFP = fFPIter.next();
195 if (!fCurrFP) {
196 return nullptr;
197 }
198 }
199 return &(fCurrFP->*GET)(fCTIdx++);
200 }
bsalomona624bf32016-09-20 09:12:47 -0700201
202 private:
203 const GrFragmentProcessor* fCurrFP;
204 int fCTIdx;
205 GrFragmentProcessor::Iter fFPIter;
206 };
207
bsalomonb58a2b42016-09-26 06:55:02 -0700208 using CoordTransformIter = FPItemIter<GrCoordTransform,
209 GrFragmentProcessor,
210 &GrFragmentProcessor::numCoordTransforms,
211 &GrFragmentProcessor::coordTransform>;
212
Brian Salomon0bbecb22016-11-17 11:38:22 -0500213 using TextureAccessIter = FPItemIter<TextureSampler,
bsalomonb58a2b42016-09-26 06:55:02 -0700214 GrProcessor,
Brian Salomon0bbecb22016-11-17 11:38:22 -0500215 &GrProcessor::numTextureSamplers,
216 &GrProcessor::textureSampler>;
bsalomonb58a2b42016-09-26 06:55:02 -0700217
bsalomon6251d172014-10-15 10:50:36 -0700218protected:
Brian Salomon587e08f2017-01-27 10:59:27 -0500219 enum OptimizationFlags : uint32_t {
220 kNone_OptimizationFlags,
221 kModulatesInput_OptimizationFlag = 0x1,
222 kPreservesOpaqueInput_OptimizationFlag = 0x2,
223 kConstantOutputForConstantInput_OptimizationFlag = 0x4,
224 kAll_OptimizationFlags = kModulatesInput_OptimizationFlag |
225 kPreservesOpaqueInput_OptimizationFlag |
226 kConstantOutputForConstantInput_OptimizationFlag
227 };
228 GR_DECL_BITFIELD_OPS_FRIENDS(OptimizationFlags)
229
230 GrFragmentProcessor(OptimizationFlags optimizationFlags) : fFlags(optimizationFlags) {
231 SkASSERT((fFlags & ~kAll_OptimizationFlags) == 0);
232 }
233
234 OptimizationFlags optimizationFlags() const {
235 return static_cast<OptimizationFlags>(kAll_OptimizationFlags & fFlags);
236 }
237
238 /**
239 * This allows one subclass to access another subclass's implementation of
240 * constantOutputForConstantInput. It must only be called when
241 * hasConstantOutputForConstantInput() is known to be true.
242 */
243 static GrColor4f ConstantOutputForConstantInput(const GrFragmentProcessor& fp,
244 GrColor4f input) {
245 SkASSERT(fp.hasConstantOutputForConstantInput());
246 return fp.constantOutputForConstantInput(input);
247 }
248
bsalomon6251d172014-10-15 10:50:36 -0700249 /**
250 * Fragment Processor subclasses call this from their constructor to register coordinate
bsalomonde258cd2014-10-15 19:06:21 -0700251 * transformations. Coord transforms provide a mechanism for a processor to receive coordinates
252 * in their FS code. The matrix expresses a transformation from local space. For a given
253 * fragment the matrix will be applied to the local coordinate that maps to the fragment.
254 *
255 * When the transformation has perspective, the transformed coordinates will have
mtklein790d74f2015-08-19 11:05:39 -0700256 * 3 components. Otherwise they'll have 2.
bsalomonde258cd2014-10-15 19:06:21 -0700257 *
258 * This must only be called from the constructor because GrProcessors are immutable. The
259 * processor subclass manages the lifetime of the transformations (this function only stores a
mtklein790d74f2015-08-19 11:05:39 -0700260 * pointer). The GrCoordTransform is typically a member field of the GrProcessor subclass.
bsalomonde258cd2014-10-15 19:06:21 -0700261 *
262 * A processor subclass that has multiple methods of construction should always add its coord
263 * transforms in a consistent order. The non-virtual implementation of isEqual() automatically
264 * compares transforms and will assume they line up across the two processor instances.
bsalomon6251d172014-10-15 10:50:36 -0700265 */
266 void addCoordTransform(const GrCoordTransform*);
267
268 /**
wangyix58d890b2015-08-12 09:40:47 -0700269 * FragmentProcessor subclasses call this from their constructor to register any child
wangyix93ab2542015-08-19 08:23:12 -0700270 * FragmentProcessors they have. This must be called AFTER all texture accesses and coord
271 * transforms have been added.
wangyix4b3050b2015-08-04 07:59:37 -0700272 * This is for processors whose shader code will be composed of nested processors whose output
273 * colors will be combined somehow to produce its output color. Registering these child
wangyix58d890b2015-08-12 09:40:47 -0700274 * processors will allow the ProgramBuilder to automatically handle their transformed coords and
275 * texture accesses and mangle their uniform and output color names.
wangyix4b3050b2015-08-04 07:59:37 -0700276 */
bungeman06ca8ec2016-06-09 08:01:03 -0700277 int registerChildProcessor(sk_sp<GrFragmentProcessor> child);
wangyix4b3050b2015-08-04 07:59:37 -0700278
279 /**
joshualitt56995b52014-12-11 15:44:02 -0800280 * Subclass implements this to support getConstantColorComponents(...).
wangyix54017d72015-08-18 07:39:33 -0700281 *
282 * Note: it's up to the subclass implementation to do any recursive call to compute the child
283 * procs' output invariants; computeInvariantOutput will not be recursive.
joshualitt56995b52014-12-11 15:44:02 -0800284 */
285 virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const = 0;
286
Brian Salomon587e08f2017-01-27 10:59:27 -0500287 /**
288 * Sub-classes should call this in their constructors if they need access to a distance
dvonbeck9b03e7b2016-08-01 11:01:56 -0700289 * vector field to the nearest edge
290 */
Brian Salomon587e08f2017-01-27 10:59:27 -0500291 void setWillUseDistanceVectorField() { fFlags |= kUsesDistanceVectorField_Flag; }
dvonbeck9b03e7b2016-08-01 11:01:56 -0700292
bsalomon6251d172014-10-15 10:50:36 -0700293private:
bsalomon42048002015-08-27 16:43:48 -0700294 void notifyRefCntIsZero() const final;
295
Brian Salomon587e08f2017-01-27 10:59:27 -0500296 virtual GrColor4f constantOutputForConstantInput(GrColor4f /* inputColor */) const {
297 SkFAIL("Subclass must override this if advertising this optimization.");
298 return GrColor4f::TransparentBlack();
299 }
300
wangyixb1daa862015-08-18 11:29:31 -0700301 /** Returns a new instance of the appropriate *GL* implementation class
302 for the given GrFragmentProcessor; caller is responsible for deleting
303 the object. */
egdaniel57d3b032015-11-13 11:57:27 -0800304 virtual GrGLSLFragmentProcessor* onCreateGLSLInstance() const = 0;
wangyixb1daa862015-08-18 11:29:31 -0700305
wangyix4b3050b2015-08-04 07:59:37 -0700306 /** Implemented using GLFragmentProcessor::GenKey as described in this class's comment. */
Brian Salomon94efbf52016-11-29 13:43:05 -0500307 virtual void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const = 0;
wangyix4b3050b2015-08-04 07:59:37 -0700308
bsalomonde258cd2014-10-15 19:06:21 -0700309 /**
310 * Subclass implements this to support isEqual(). It will only be called if it is known that
311 * the two processors are of the same subclass (i.e. they return the same object from
312 * getFactory()). The processor subclass should not compare its coord transforms as that will
313 * be performed automatically in the non-virtual isEqual().
314 */
315 virtual bool onIsEqual(const GrFragmentProcessor&) const = 0;
316
317 bool hasSameTransforms(const GrFragmentProcessor&) const;
bsalomon6251d172014-10-15 10:50:36 -0700318
Brian Salomon587e08f2017-01-27 10:59:27 -0500319 enum PrivateFlags {
320 kFirstPrivateFlag = kAll_OptimizationFlags + 1,
321 kUsesLocalCoords_Flag = kFirstPrivateFlag,
322 kUsesDistanceVectorField_Flag = kFirstPrivateFlag << 1,
323 };
324
325 mutable uint32_t fFlags = 0;
wangyix58d890b2015-08-12 09:40:47 -0700326
bsalomona624bf32016-09-20 09:12:47 -0700327 SkSTArray<4, const GrCoordTransform*, true> fCoordTransforms;
328
wangyix58d890b2015-08-12 09:40:47 -0700329 /**
bungeman06ca8ec2016-06-09 08:01:03 -0700330 * This is not SkSTArray<1, sk_sp<GrFragmentProcessor>> because this class holds strong
331 * references until notifyRefCntIsZero and then it holds pending executions.
332 */
Brian Salomon587e08f2017-01-27 10:59:27 -0500333 SkSTArray<1, GrFragmentProcessor*, true> fChildProcessors;
bsalomon6251d172014-10-15 10:50:36 -0700334
335 typedef GrProcessor INHERITED;
336};
337
Brian Salomon587e08f2017-01-27 10:59:27 -0500338GR_MAKE_BITFIELD_OPS(GrFragmentProcessor::OptimizationFlags)
339
bsalomon6251d172014-10-15 10:50:36 -0700340#endif