blob: 03d22aeaaee3b36d1aa038c26314c9c95b4db989 [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
Ethan Nicholasd4efe682019-08-29 16:10:13 -040011#include "src/gpu/GrCoordTransform.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "src/gpu/GrProcessor.h"
Chris Dalton7eb5c0f2019-05-23 15:15:47 -060013#include "src/gpu/ops/GrOp.h"
bsalomon6251d172014-10-15 10:50:36 -070014
egdaniel64c47282015-11-13 06:54:19 -080015class GrGLSLFragmentProcessor;
Chris Dalton1c548942018-05-22 13:09:48 -060016class GrPaint;
bsalomona624bf32016-09-20 09:12:47 -070017class GrPipeline;
joshualitteb2a6762014-12-04 11:35:33 -080018class GrProcessorKeyBuilder;
Brian Salomon94efbf52016-11-29 13:43:05 -050019class GrShaderCaps;
Brian Osmance425512017-03-22 14:37:50 -040020class GrSwizzle;
bsalomon6251d172014-10-15 10:50:36 -070021
Ethan Nicholasf7b88202017-09-18 14:10:39 -040022/** Provides custom fragment shader code. Fragment processors receive an input color (half4) and
bsalomon6251d172014-10-15 10:50:36 -070023 produce an output color. They may reference textures and uniforms. They may use
24 GrCoordTransforms to receive a transformation of the local coordinates that map from local space
25 to the fragment being processed.
26 */
Brian Salomone782f842018-07-31 13:53:11 -040027class GrFragmentProcessor : public GrProcessor {
bsalomon6251d172014-10-15 10:50:36 -070028public:
Brian Salomone782f842018-07-31 13:53:11 -040029 class TextureSampler;
30
bsalomon87ba62e2015-09-22 06:41:59 -070031 /**
32 * In many instances (e.g. SkShader::asFragmentProcessor() implementations) it is desirable to
33 * only consider the input color's alpha. However, there is a competing desire to have reusable
34 * GrFragmentProcessor subclasses that can be used in other scenarios where the entire input
35 * color is considered. This function exists to filter the input color and pass it to a FP. It
36 * does so by returning a parent FP that multiplies the passed in FPs output by the parent's
37 * input alpha. The passed in FP will not receive an input color.
38 */
Mike Reed28eaed22018-02-01 11:24:53 -050039 static std::unique_ptr<GrFragmentProcessor> MulChildByInputAlpha(
40 std::unique_ptr<GrFragmentProcessor> child);
41
42 /**
43 * Like MulChildByInputAlpha(), but reverses the sense of src and dst. In this case, return
44 * the input modulated by the child's alpha. The passed in FP will not receive an input color.
45 *
46 * output = input * child.a
47 */
48 static std::unique_ptr<GrFragmentProcessor> MulInputByChildAlpha(
49 std::unique_ptr<GrFragmentProcessor> child);
bsalomonf1b7a1d2015-09-28 06:26:28 -070050
51 /**
Brian Salomon22af73f2017-01-26 11:25:12 -050052 * This assumes that the input color to the returned processor will be unpremul and that the
53 * passed processor (which becomes the returned processor's child) produces a premul output.
54 * The result of the returned processor is a premul of its input color modulated by the child
55 * processor's premul output.
bsalomonf1b7a1d2015-09-28 06:26:28 -070056 */
Brian Salomonaff329b2017-08-11 09:40:37 -040057 static std::unique_ptr<GrFragmentProcessor> MakeInputPremulAndMulByOutput(
58 std::unique_ptr<GrFragmentProcessor>);
bsalomonf1b7a1d2015-09-28 06:26:28 -070059
60 /**
bsalomone25eea42015-09-29 06:38:55 -070061 * Returns a parent fragment processor that adopts the passed fragment processor as a child.
62 * The parent will ignore its input color and instead feed the passed in color as input to the
63 * child.
bsalomonf1b7a1d2015-09-28 06:26:28 -070064 */
Brian Salomonaff329b2017-08-11 09:40:37 -040065 static std::unique_ptr<GrFragmentProcessor> OverrideInput(std::unique_ptr<GrFragmentProcessor>,
Brian Salomonc0d79e52019-04-10 15:02:11 -040066 const SkPMColor4f&,
67 bool useUniform = true);
bsalomon87ba62e2015-09-22 06:41:59 -070068
bsalomone25eea42015-09-29 06:38:55 -070069 /**
dvonbeckc526da92016-07-20 11:20:30 -070070 * Returns a fragment processor that premuls the input before calling the passed in fragment
71 * processor.
72 */
Brian Salomonaff329b2017-08-11 09:40:37 -040073 static std::unique_ptr<GrFragmentProcessor> PremulInput(std::unique_ptr<GrFragmentProcessor>);
dvonbeckc526da92016-07-20 11:20:30 -070074
75 /**
Brian Osmance425512017-03-22 14:37:50 -040076 * Returns a fragment processor that calls the passed in fragment processor, and then swizzles
77 * the output.
78 */
Brian Salomonaff329b2017-08-11 09:40:37 -040079 static std::unique_ptr<GrFragmentProcessor> SwizzleOutput(std::unique_ptr<GrFragmentProcessor>,
80 const GrSwizzle&);
Brian Osmance425512017-03-22 14:37:50 -040081
82 /**
bsalomone25eea42015-09-29 06:38:55 -070083 * Returns a fragment processor that runs the passed in array of fragment processors in a
84 * series. The original input is passed to the first, the first's output is passed to the
85 * second, etc. The output of the returned processor is the output of the last processor of the
86 * series.
bungeman06ca8ec2016-06-09 08:01:03 -070087 *
88 * The array elements with be moved.
bsalomone25eea42015-09-29 06:38:55 -070089 */
Brian Salomonaff329b2017-08-11 09:40:37 -040090 static std::unique_ptr<GrFragmentProcessor> RunInSeries(std::unique_ptr<GrFragmentProcessor>*,
91 int cnt);
bsalomonac856c92015-08-27 06:30:17 -070092
Brian Salomon0e05a822017-07-25 09:43:22 -040093 /**
94 * Makes a copy of this fragment processor that draws equivalently to the original.
Brian Salomon96271cd2017-07-31 16:27:23 -040095 * If the processor has child processors they are cloned as well.
Brian Salomon0e05a822017-07-25 09:43:22 -040096 */
Brian Salomonaff329b2017-08-11 09:40:37 -040097 virtual std::unique_ptr<GrFragmentProcessor> clone() const = 0;
Brian Salomon0e05a822017-07-25 09:43:22 -040098
egdaniel57d3b032015-11-13 11:57:27 -080099 GrGLSLFragmentProcessor* createGLSLInstance() const;
joshualitteb2a6762014-12-04 11:35:33 -0800100
Brian Salomon94efbf52016-11-29 13:43:05 -0500101 void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
egdaniel57d3b032015-11-13 11:57:27 -0800102 this->onGetGLSLProcessorKey(caps, b);
wangyix4b3050b2015-08-04 07:59:37 -0700103 for (int i = 0; i < fChildProcessors.count(); ++i) {
egdaniel57d3b032015-11-13 11:57:27 -0800104 fChildProcessors[i]->getGLSLProcessorKey(caps, b);
wangyix4b3050b2015-08-04 07:59:37 -0700105 }
106 }
107
Brian Salomone782f842018-07-31 13:53:11 -0400108 int numTextureSamplers() const { return fTextureSamplerCnt; }
109 const TextureSampler& textureSampler(int i) const;
110
bsalomona624bf32016-09-20 09:12:47 -0700111 int numCoordTransforms() const { return fCoordTransforms.count(); }
bsalomon6251d172014-10-15 10:50:36 -0700112
113 /** Returns the coordinate transformation at index. index must be valid according to
Brian Salomon7eabfe82019-12-02 14:20:20 -0500114 numCoordTransforms(). */
bsalomon6251d172014-10-15 10:50:36 -0700115 const GrCoordTransform& coordTransform(int index) const { return *fCoordTransforms[index]; }
Brian Salomon7eabfe82019-12-02 14:20:20 -0500116 GrCoordTransform& coordTransform(int index) { return *fCoordTransforms[index]; }
bsalomon6251d172014-10-15 10:50:36 -0700117
Ethan Nicholasd4efe682019-08-29 16:10:13 -0400118 const SkTArray<GrCoordTransform*, true>& coordTransforms() const {
joshualittabb52a12015-01-13 15:02:10 -0800119 return fCoordTransforms;
120 }
121
wangyix4b3050b2015-08-04 07:59:37 -0700122 int numChildProcessors() const { return fChildProcessors.count(); }
123
Brian Salomon7eabfe82019-12-02 14:20:20 -0500124 GrFragmentProcessor& childProcessor(int index) { return *fChildProcessors[index]; }
bsalomonac856c92015-08-27 06:30:17 -0700125 const GrFragmentProcessor& childProcessor(int index) const { return *fChildProcessors[index]; }
wangyix4b3050b2015-08-04 07:59:37 -0700126
Robert Phillips82774f82019-06-20 14:38:27 -0400127 SkDEBUGCODE(bool isInstantiated() const;)
Robert Phillips9bee2e52017-05-29 12:37:20 -0400128
Brian Salomon7d8b3972019-11-26 22:34:44 -0500129 /** Do any of the coord transforms for this processor require local coords? */
130 bool usesLocalCoords() const {
131 // If the processor is sampled with explicit coords then we do not need to apply the
132 // coord transforms in the vertex shader to the local coords.
133 return SkToBool(fFlags & kHasCoordTranforms_Flag) &&
134 SkToBool(fFlags & kCoordTransformsApplyToLocalCoords_Flag);
Ethan Nicholasd4efe682019-08-29 16:10:13 -0400135 }
136
Brian Salomon7d8b3972019-11-26 22:34:44 -0500137 bool coordTransformsApplyToLocalCoords() const {
138 return SkToBool(fFlags & kCoordTransformsApplyToLocalCoords_Flag);
139 }
140
141 void setSampledWithExplicitCoords(bool value) {
Ethan Nicholasd4efe682019-08-29 16:10:13 -0400142 if (value) {
Brian Salomon7d8b3972019-11-26 22:34:44 -0500143 fFlags &= ~kCoordTransformsApplyToLocalCoords_Flag;
Ethan Nicholasd4efe682019-08-29 16:10:13 -0400144 } else {
Brian Salomon7d8b3972019-11-26 22:34:44 -0500145 fFlags |= kCoordTransformsApplyToLocalCoords_Flag;
Ethan Nicholasd4efe682019-08-29 16:10:13 -0400146 }
Brian Salomon7d8b3972019-11-26 22:34:44 -0500147 for (auto& child : fChildProcessors) {
148 child->setSampledWithExplicitCoords(value);
Ethan Nicholasd4efe682019-08-29 16:10:13 -0400149 }
150 }
151
Brian Salomon587e08f2017-01-27 10:59:27 -0500152 /**
Brian Salomonf3b995b2017-02-15 10:22:23 -0500153 * A GrDrawOp may premultiply its antialiasing coverage into its GrGeometryProcessor's color
154 * output under the following scenario:
155 * * all the color fragment processors report true to this query,
156 * * all the coverage fragment processors report true to this query,
157 * * the blend mode arithmetic allows for it it.
158 * To be compatible a fragment processor's output must be a modulation of its input color or
159 * alpha with a computed premultiplied color or alpha that is in 0..1 range. The computed color
160 * or alpha that is modulated against the input cannot depend on the input's alpha. The computed
161 * value cannot depend on the input's color channels unless it unpremultiplies the input color
162 * channels by the input alpha.
Brian Salomon587e08f2017-01-27 10:59:27 -0500163 */
Brian Salomonf3b995b2017-02-15 10:22:23 -0500164 bool compatibleWithCoverageAsAlpha() const {
165 return SkToBool(fFlags & kCompatibleWithCoverageAsAlpha_OptimizationFlag);
166 }
Brian Salomon587e08f2017-01-27 10:59:27 -0500167
168 /**
169 * If this is true then all opaque input colors to the processor produce opaque output colors.
170 */
171 bool preservesOpaqueInput() const {
172 return SkToBool(fFlags & kPreservesOpaqueInput_OptimizationFlag);
173 }
174
175 /**
176 * Tests whether given a constant input color the processor produces a constant output color
177 * (for all fragments). If true outputColor will contain the constant color produces for
178 * inputColor.
179 */
Brian Osman1d5b5982018-10-01 13:41:39 -0400180 bool hasConstantOutputForConstantInput(SkPMColor4f inputColor, SkPMColor4f* outputColor) const {
Brian Salomon587e08f2017-01-27 10:59:27 -0500181 if (fFlags & kConstantOutputForConstantInput_OptimizationFlag) {
182 *outputColor = this->constantOutputForConstantInput(inputColor);
183 return true;
184 }
185 return false;
186 }
187 bool hasConstantOutputForConstantInput() const {
188 return SkToBool(fFlags & kConstantOutputForConstantInput_OptimizationFlag);
189 }
dvonbeck9b03e7b2016-08-01 11:01:56 -0700190
joshualitteb2a6762014-12-04 11:35:33 -0800191 /** Returns true if this and other processor conservatively draw identically. It can only return
192 true when the two processor are of the same subclass (i.e. they return the same object from
bsalomon6251d172014-10-15 10:50:36 -0700193 from getFactory()).
194
joshualitteb2a6762014-12-04 11:35:33 -0800195 A return value of true from isEqual() should not be used to test whether the processor would
egdaniel57d3b032015-11-13 11:57:27 -0800196 generate the same shader code. To test for identical code generation use getGLSLProcessorKey
197 */
bsalomon7312ff82016-09-12 08:55:38 -0700198 bool isEqual(const GrFragmentProcessor& that) const;
bsalomon6251d172014-10-15 10:50:36 -0700199
Brian Salomonc241b582019-11-27 08:57:17 -0500200 void visitProxies(const GrOp::VisitProxyFunc& func);
bsalomona624bf32016-09-20 09:12:47 -0700201
Brian Salomonc241b582019-11-27 08:57:17 -0500202 // A pre-order traversal iterator over a hierarchy of FPs. It can also iterate over all the FP
203 // hierarchies rooted in a GrPaint, GrProcessorSet, or GrPipeline. For these collections it
204 // iterates the tree rooted at each color FP and then each coverage FP.
205 //
Brian Salomon7eabfe82019-12-02 14:20:20 -0500206 // Iter is the non-const version and CIter is the const version.
207 //
Brian Salomonc241b582019-11-27 08:57:17 -0500208 // An iterator is constructed from one of the srcs and used like this:
209 // for (GrFragmentProcessor::Iter iter(pipeline); iter; ++iter) {
Brian Salomon7eabfe82019-12-02 14:20:20 -0500210 // GrFragmentProcessor& fp = *iter;
Brian Salomonc241b582019-11-27 08:57:17 -0500211 // }
212 // The exit test for the loop is using Iter's operator bool().
Brian Salomon7eabfe82019-12-02 14:20:20 -0500213 // To use a range-for loop instead see CIterRange below.
Brian Salomonc241b582019-11-27 08:57:17 -0500214 class Iter;
Brian Salomon7eabfe82019-12-02 14:20:20 -0500215 class CIter;
bsalomona624bf32016-09-20 09:12:47 -0700216
Brian Salomon7eabfe82019-12-02 14:20:20 -0500217 // Used to implement a range-for loop using CIter. Src is one of GrFragmentProcessor,
218 // GrPaint, GrProcessorSet, or GrPipeline. Type aliases for these defined below.
Brian Salomonc241b582019-11-27 08:57:17 -0500219 // Example usage:
220 // for (const auto& fp : GrFragmentProcessor::PaintRange(paint)) {
221 // if (fp.usesLocalCoords()) {
222 // ...
223 // }
224 // }
Brian Salomon7eabfe82019-12-02 14:20:20 -0500225 template <typename Src> class CIterRange;
226 // Like CIterRange but non const and only constructable from GrFragmentProcessor. This could
227 // support GrPaint as it owns non-const FPs but no need for it as of now.
228 // for (auto& fp0 : GrFragmentProcessor::IterRange(fp)) {
229 // ...
230 // }
231 class IterRange;
bsalomonb58a2b42016-09-26 06:55:02 -0700232
Brian Salomon7eabfe82019-12-02 14:20:20 -0500233 // We would use template deduction guides for Iter/CIter but for:
Brian Salomonc241b582019-11-27 08:57:17 -0500234 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79501
235 // Instead we use these specialized type aliases to make it prettier
236 // to construct Iters for particular sources of FPs.
Brian Salomon7eabfe82019-12-02 14:20:20 -0500237 using FPCRange = CIterRange<GrFragmentProcessor>;
238 using PaintCRange = CIterRange<GrPaint>;
bsalomona624bf32016-09-20 09:12:47 -0700239
Brian Salomon7eabfe82019-12-02 14:20:20 -0500240 // Implementation details for iterators that walk an array of Items owned by a set of FPs.
Brian Salomonc241b582019-11-27 08:57:17 -0500241 using CountFn = int (GrFragmentProcessor::*)() const;
Brian Salomon7eabfe82019-12-02 14:20:20 -0500242 // Defined GetFn to be a member function that returns an Item by index. The function itself is
243 // const if Item is a const type and non-const if Item is non-const.
244 template <typename Item, bool IsConst = std::is_const<Item>::value> struct GetT;
245 template <typename Item> struct GetT<Item, false> {
246 using GetFn = Item& (GrFragmentProcessor::*)(int);
247 };
248 template <typename Item> struct GetT<Item, true> {
249 using GetFn = const Item& (GrFragmentProcessor::*)(int) const;
250 };
251 template <typename Item> using GetFn = typename GetT<Item>::GetFn;
252 // This is an iterator over the Items owned by a (collection of) FP. CountFn is a FP member that
253 // gets the number of Items owned by each FP and GetFn is a member that gets them by index.
Brian Salomonc241b582019-11-27 08:57:17 -0500254 template <typename Item, CountFn Count, GetFn<Item> Get> class FPItemIter;
255
256 // Loops over all the GrCoordTransforms owned by GrFragmentProcessors. The possible sources for
257 // the iteration are the same as those for Iter and the FPs are walked in the same order as
258 // Iter. This provides access to the coord transform and the FP that owns it. Example usage:
259 // for (GrFragmentProcessor::CoordTransformIter iter(pipeline); iter; ++iter) {
260 // // transform is const GrCoordTransform& and owningFP is const GrFragmentProcessor&.
261 // auto [transform, owningFP] = *iter;
262 // ...
263 // }
264 // See the ranges below to make this simpler a la range-for loops.
Brian Salomon7eabfe82019-12-02 14:20:20 -0500265 using CoordTransformIter = FPItemIter<const GrCoordTransform,
bsalomonb58a2b42016-09-26 06:55:02 -0700266 &GrFragmentProcessor::numCoordTransforms,
267 &GrFragmentProcessor::coordTransform>;
Brian Salomonc241b582019-11-27 08:57:17 -0500268 // Same as CoordTransformIter but for TextureSamplers:
269 // for (GrFragmentProcessor::TextureSamplerIter iter(pipeline); iter; ++iter) {
270 // // TextureSamplerIter is const GrFragmentProcessor::TextureSampler& and
271 // // owningFP is const GrFragmentProcessor&.
272 // auto [sampler, owningFP] = *iter;
273 // ...
274 // }
275 // See the ranges below to make this simpler a la range-for loops.
Brian Salomon7eabfe82019-12-02 14:20:20 -0500276 using TextureSamplerIter = FPItemIter<const TextureSampler,
Brian Salomonc241b582019-11-27 08:57:17 -0500277 &GrFragmentProcessor::numTextureSamplers,
278 &GrFragmentProcessor::textureSampler>;
bsalomonb58a2b42016-09-26 06:55:02 -0700279
Brian Salomonc241b582019-11-27 08:57:17 -0500280 // Implementation detail for using CoordTransformIter and TextureSamplerIter in range-for loops.
281 template <typename Src, typename ItemIter> class FPItemRange;
bsalomonb58a2b42016-09-26 06:55:02 -0700282
Brian Salomonc241b582019-11-27 08:57:17 -0500283 // These allow iteration over coord transforms/texture samplers for various FP sources via
284 // range-for loops. An example usage for looping over the coord transforms in a pipeline:
285 // for (auto [transform, fp] : GrFragmentProcessor::PipelineCoordTransformRange(pipeline)) {
286 // ...
287 // }
288 // Only the combinations of FP sources and iterable things have been defined but it is easy
289 // to add more as they become useful. Maybe someday we'll have template argument deduction
290 // with guides for type aliases and the sources can be removed from the type aliases:
291 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1021r5.html
Brian Salomon7eabfe82019-12-02 14:20:20 -0500292 using PipelineCoordTransformRange = FPItemRange<const GrPipeline, CoordTransformIter>;
293 using PipelineTextureSamplerRange = FPItemRange<const GrPipeline, TextureSamplerIter>;
294 using FPTextureSamplerRange = FPItemRange<const GrFragmentProcessor, TextureSamplerIter>;
295 using ProcessorSetTextureSamplerRange = FPItemRange<const GrProcessorSet, TextureSamplerIter>;
296
297 // Not used directly.
298 using NonConstCoordTransformIter =
299 FPItemIter<GrCoordTransform, &GrFragmentProcessor::numCoordTransforms,
300 &GrFragmentProcessor::coordTransform>;
301 // Iterator over non-const GrCoordTransforms owned by FP and its descendants.
302 using FPCoordTransformRange = FPItemRange<GrFragmentProcessor, NonConstCoordTransformIter>;
Brian Salomonc241b582019-11-27 08:57:17 -0500303
304 // Sentinel type for range-for using Iter.
305 class EndIter {};
306 // Sentinel type for range-for using FPItemIter.
307 class FPItemEndIter {};
Robert Phillipsb493eeb2017-09-13 13:10:52 -0400308
bsalomon6251d172014-10-15 10:50:36 -0700309protected:
Brian Salomon587e08f2017-01-27 10:59:27 -0500310 enum OptimizationFlags : uint32_t {
311 kNone_OptimizationFlags,
Brian Salomonf3b995b2017-02-15 10:22:23 -0500312 kCompatibleWithCoverageAsAlpha_OptimizationFlag = 0x1,
Brian Salomon587e08f2017-01-27 10:59:27 -0500313 kPreservesOpaqueInput_OptimizationFlag = 0x2,
314 kConstantOutputForConstantInput_OptimizationFlag = 0x4,
Brian Salomonf3b995b2017-02-15 10:22:23 -0500315 kAll_OptimizationFlags = kCompatibleWithCoverageAsAlpha_OptimizationFlag |
Brian Salomon587e08f2017-01-27 10:59:27 -0500316 kPreservesOpaqueInput_OptimizationFlag |
317 kConstantOutputForConstantInput_OptimizationFlag
318 };
319 GR_DECL_BITFIELD_OPS_FRIENDS(OptimizationFlags)
320
Brian Salomon6cd51b52017-07-26 19:07:15 -0400321 /**
322 * Can be used as a helper to decide which fragment processor OptimizationFlags should be set.
323 * This assumes that the subclass output color will be a modulation of the input color with a
Greg Danielc594e622019-10-15 14:01:49 -0400324 * value read from a texture of the passed color type and that the texture contains
325 * premultiplied color or alpha values that are in range.
Michael Ludwig257a03d2018-12-13 14:07:07 -0500326 *
327 * Since there are multiple ways in which a sampler may have its coordinates clamped or wrapped,
328 * callers must determine on their own if the sampling uses a decal strategy in any way, in
Greg Danielc594e622019-10-15 14:01:49 -0400329 * which case the texture may become transparent regardless of the color type.
Brian Salomon6cd51b52017-07-26 19:07:15 -0400330 */
Brian Salomonfc118442019-11-22 19:09:27 -0500331 static OptimizationFlags ModulateForSamplerOptFlags(SkAlphaType alphaType, bool samplingDecal) {
Michael Ludwig257a03d2018-12-13 14:07:07 -0500332 if (samplingDecal) {
333 return kCompatibleWithCoverageAsAlpha_OptimizationFlag;
334 } else {
Brian Salomonfc118442019-11-22 19:09:27 -0500335 return ModulateForClampedSamplerOptFlags(alphaType);
Michael Ludwig257a03d2018-12-13 14:07:07 -0500336 }
337 }
338
339 // As above, but callers should somehow ensure or assert their sampler still uses clamping
Brian Salomonfc118442019-11-22 19:09:27 -0500340 static OptimizationFlags ModulateForClampedSamplerOptFlags(SkAlphaType alphaType) {
341 if (alphaType == kOpaque_SkAlphaType) {
Brian Salomon6cd51b52017-07-26 19:07:15 -0400342 return kCompatibleWithCoverageAsAlpha_OptimizationFlag |
343 kPreservesOpaqueInput_OptimizationFlag;
344 } else {
345 return kCompatibleWithCoverageAsAlpha_OptimizationFlag;
346 }
347 }
348
Ethan Nicholasabff9562017-10-09 10:54:08 -0400349 GrFragmentProcessor(ClassID classID, OptimizationFlags optimizationFlags)
Robert Phillips39667382019-04-17 16:03:30 -0400350 : INHERITED(classID)
Brian Salomon7d8b3972019-11-26 22:34:44 -0500351 , fFlags(optimizationFlags | kCoordTransformsApplyToLocalCoords_Flag) {
Ethan Nicholasd4efe682019-08-29 16:10:13 -0400352 SkASSERT((optimizationFlags & ~kAll_OptimizationFlags) == 0);
Brian Salomon587e08f2017-01-27 10:59:27 -0500353 }
354
355 OptimizationFlags optimizationFlags() const {
356 return static_cast<OptimizationFlags>(kAll_OptimizationFlags & fFlags);
357 }
358
Brian Salomonc0d79e52019-04-10 15:02:11 -0400359 /** Useful when you can't call fp->optimizationFlags() on a base class object from a subclass.*/
360 static OptimizationFlags ProcessorOptimizationFlags(const GrFragmentProcessor* fp) {
361 return fp->optimizationFlags();
362 }
363
Brian Salomon587e08f2017-01-27 10:59:27 -0500364 /**
365 * This allows one subclass to access another subclass's implementation of
366 * constantOutputForConstantInput. It must only be called when
367 * hasConstantOutputForConstantInput() is known to be true.
368 */
Brian Osman1d5b5982018-10-01 13:41:39 -0400369 static SkPMColor4f ConstantOutputForConstantInput(const GrFragmentProcessor& fp,
370 const SkPMColor4f& input) {
Brian Salomon587e08f2017-01-27 10:59:27 -0500371 SkASSERT(fp.hasConstantOutputForConstantInput());
372 return fp.constantOutputForConstantInput(input);
373 }
374
bsalomon6251d172014-10-15 10:50:36 -0700375 /**
376 * Fragment Processor subclasses call this from their constructor to register coordinate
bsalomonde258cd2014-10-15 19:06:21 -0700377 * transformations. Coord transforms provide a mechanism for a processor to receive coordinates
378 * in their FS code. The matrix expresses a transformation from local space. For a given
379 * fragment the matrix will be applied to the local coordinate that maps to the fragment.
380 *
381 * When the transformation has perspective, the transformed coordinates will have
mtklein790d74f2015-08-19 11:05:39 -0700382 * 3 components. Otherwise they'll have 2.
bsalomonde258cd2014-10-15 19:06:21 -0700383 *
384 * This must only be called from the constructor because GrProcessors are immutable. The
385 * processor subclass manages the lifetime of the transformations (this function only stores a
mtklein790d74f2015-08-19 11:05:39 -0700386 * pointer). The GrCoordTransform is typically a member field of the GrProcessor subclass.
bsalomonde258cd2014-10-15 19:06:21 -0700387 *
388 * A processor subclass that has multiple methods of construction should always add its coord
389 * transforms in a consistent order. The non-virtual implementation of isEqual() automatically
390 * compares transforms and will assume they line up across the two processor instances.
bsalomon6251d172014-10-15 10:50:36 -0700391 */
Ethan Nicholasd4efe682019-08-29 16:10:13 -0400392 void addCoordTransform(GrCoordTransform*);
bsalomon6251d172014-10-15 10:50:36 -0700393
394 /**
wangyix58d890b2015-08-12 09:40:47 -0700395 * FragmentProcessor subclasses call this from their constructor to register any child
wangyix93ab2542015-08-19 08:23:12 -0700396 * FragmentProcessors they have. This must be called AFTER all texture accesses and coord
397 * transforms have been added.
wangyix4b3050b2015-08-04 07:59:37 -0700398 * This is for processors whose shader code will be composed of nested processors whose output
399 * colors will be combined somehow to produce its output color. Registering these child
wangyix58d890b2015-08-12 09:40:47 -0700400 * processors will allow the ProgramBuilder to automatically handle their transformed coords and
401 * texture accesses and mangle their uniform and output color names.
wangyix4b3050b2015-08-04 07:59:37 -0700402 */
Brian Salomonaff329b2017-08-11 09:40:37 -0400403 int registerChildProcessor(std::unique_ptr<GrFragmentProcessor> child);
wangyix4b3050b2015-08-04 07:59:37 -0700404
Brian Salomone782f842018-07-31 13:53:11 -0400405 void setTextureSamplerCnt(int cnt) {
406 SkASSERT(cnt >= 0);
407 fTextureSamplerCnt = cnt;
408 }
409
410 /**
411 * Helper for implementing onTextureSampler(). E.g.:
412 * return IthTexureSampler(i, fMyFirstSampler, fMySecondSampler, fMyThirdSampler);
413 */
414 template <typename... Args>
415 static const TextureSampler& IthTextureSampler(int i, const TextureSampler& samp0,
416 const Args&... samps) {
417 return (0 == i) ? samp0 : IthTextureSampler(i - 1, samps...);
418 }
419 inline static const TextureSampler& IthTextureSampler(int i);
420
bsalomon6251d172014-10-15 10:50:36 -0700421private:
Brian Salomon7eabfe82019-12-02 14:20:20 -0500422 // Implementation details of Iter and CIter.
423 template <typename> class IterBase;
424
Brian Osman1d5b5982018-10-01 13:41:39 -0400425 virtual SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& /* inputColor */) const {
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400426 SK_ABORT("Subclass must override this if advertising this optimization.");
Brian Salomon587e08f2017-01-27 10:59:27 -0500427 }
428
wangyixb1daa862015-08-18 11:29:31 -0700429 /** Returns a new instance of the appropriate *GL* implementation class
430 for the given GrFragmentProcessor; caller is responsible for deleting
431 the object. */
egdaniel57d3b032015-11-13 11:57:27 -0800432 virtual GrGLSLFragmentProcessor* onCreateGLSLInstance() const = 0;
wangyixb1daa862015-08-18 11:29:31 -0700433
wangyix4b3050b2015-08-04 07:59:37 -0700434 /** Implemented using GLFragmentProcessor::GenKey as described in this class's comment. */
Brian Salomon94efbf52016-11-29 13:43:05 -0500435 virtual void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const = 0;
wangyix4b3050b2015-08-04 07:59:37 -0700436
bsalomonde258cd2014-10-15 19:06:21 -0700437 /**
438 * Subclass implements this to support isEqual(). It will only be called if it is known that
439 * the two processors are of the same subclass (i.e. they return the same object from
440 * getFactory()). The processor subclass should not compare its coord transforms as that will
441 * be performed automatically in the non-virtual isEqual().
442 */
443 virtual bool onIsEqual(const GrFragmentProcessor&) const = 0;
444
Brian Salomone782f842018-07-31 13:53:11 -0400445 virtual const TextureSampler& onTextureSampler(int) const { return IthTextureSampler(0); }
446
bsalomonde258cd2014-10-15 19:06:21 -0700447 bool hasSameTransforms(const GrFragmentProcessor&) const;
bsalomon6251d172014-10-15 10:50:36 -0700448
Brian Salomon587e08f2017-01-27 10:59:27 -0500449 enum PrivateFlags {
450 kFirstPrivateFlag = kAll_OptimizationFlags + 1,
Brian Salomon7d8b3972019-11-26 22:34:44 -0500451 kHasCoordTranforms_Flag = kFirstPrivateFlag,
452 kCoordTransformsApplyToLocalCoords_Flag = kFirstPrivateFlag << 1,
Brian Salomon587e08f2017-01-27 10:59:27 -0500453 };
454
Brian Salomon7d8b3972019-11-26 22:34:44 -0500455 uint32_t fFlags = kCoordTransformsApplyToLocalCoords_Flag;
wangyix58d890b2015-08-12 09:40:47 -0700456
Brian Salomone782f842018-07-31 13:53:11 -0400457 int fTextureSamplerCnt = 0;
458
Ethan Nicholasd4efe682019-08-29 16:10:13 -0400459 SkSTArray<4, GrCoordTransform*, true> fCoordTransforms;
bsalomona624bf32016-09-20 09:12:47 -0700460
Brian Salomonaff329b2017-08-11 09:40:37 -0400461 SkSTArray<1, std::unique_ptr<GrFragmentProcessor>, true> fChildProcessors;
bsalomon6251d172014-10-15 10:50:36 -0700462
Brian Salomone782f842018-07-31 13:53:11 -0400463 typedef GrProcessor INHERITED;
bsalomon6251d172014-10-15 10:50:36 -0700464};
465
Brian Salomone782f842018-07-31 13:53:11 -0400466/**
467 * Used to represent a texture that is required by a GrFragmentProcessor. It holds a GrTextureProxy
468 * along with an associated GrSamplerState. TextureSamplers don't perform any coord manipulation to
469 * account for texture origin.
470 */
471class GrFragmentProcessor::TextureSampler {
472public:
473 TextureSampler() = default;
474
475 /**
Robert Phillips7d7aaf42019-10-14 11:34:16 -0400476 * This copy constructor is used by GrFragmentProcessor::clone() implementations.
Brian Salomone782f842018-07-31 13:53:11 -0400477 */
478 explicit TextureSampler(const TextureSampler& that)
Robert Phillipsb5204762019-06-19 14:12:13 -0400479 : fProxy(that.fProxy)
Brian Salomone782f842018-07-31 13:53:11 -0400480 , fSamplerState(that.fSamplerState) {}
481
Michael Ludwig8fa469d2019-11-25 16:08:44 -0500482 TextureSampler(sk_sp<GrSurfaceProxy>, const GrSamplerState& = GrSamplerState::ClampNearest());
Brian Salomone782f842018-07-31 13:53:11 -0400483
484 TextureSampler& operator=(const TextureSampler&) = delete;
485
Michael Ludwig8fa469d2019-11-25 16:08:44 -0500486 void reset(sk_sp<GrSurfaceProxy>, const GrSamplerState&);
Brian Salomone782f842018-07-31 13:53:11 -0400487
488 bool operator==(const TextureSampler& that) const {
489 return this->proxy()->underlyingUniqueID() == that.proxy()->underlyingUniqueID() &&
490 fSamplerState == that.fSamplerState;
491 }
492
493 bool operator!=(const TextureSampler& other) const { return !(*this == other); }
494
Robert Phillips82774f82019-06-20 14:38:27 -0400495 SkDEBUGCODE(bool isInstantiated() const { return fProxy->isInstantiated(); })
Brian Salomone782f842018-07-31 13:53:11 -0400496
497 // 'peekTexture' should only ever be called after a successful 'instantiate' call
498 GrTexture* peekTexture() const {
Robert Phillipsb5204762019-06-19 14:12:13 -0400499 SkASSERT(fProxy->isInstantiated());
500 return fProxy->peekTexture();
Brian Salomone782f842018-07-31 13:53:11 -0400501 }
502
Michael Ludwig8fa469d2019-11-25 16:08:44 -0500503 GrSurfaceProxy* proxy() const { return fProxy.get(); }
Brian Salomone782f842018-07-31 13:53:11 -0400504 const GrSamplerState& samplerState() const { return fSamplerState; }
Greg Daniel2c3398d2019-06-19 11:58:01 -0400505 const GrSwizzle& swizzle() const { return this->proxy()->textureSwizzle(); }
Brian Salomone782f842018-07-31 13:53:11 -0400506
Robert Phillipsb5204762019-06-19 14:12:13 -0400507 bool isInitialized() const { return SkToBool(fProxy.get()); }
Brian Salomone782f842018-07-31 13:53:11 -0400508
509private:
Michael Ludwig8fa469d2019-11-25 16:08:44 -0500510 sk_sp<GrSurfaceProxy> fProxy;
Robert Phillipsb5204762019-06-19 14:12:13 -0400511 GrSamplerState fSamplerState;
Brian Salomone782f842018-07-31 13:53:11 -0400512};
513
514//////////////////////////////////////////////////////////////////////////////
515
516const GrFragmentProcessor::TextureSampler& GrFragmentProcessor::IthTextureSampler(int i) {
517 SK_ABORT("Illegal texture sampler index");
518 static const TextureSampler kBogus;
519 return kBogus;
520}
521
Brian Salomon587e08f2017-01-27 10:59:27 -0500522GR_MAKE_BITFIELD_OPS(GrFragmentProcessor::OptimizationFlags)
523
Brian Salomonc241b582019-11-27 08:57:17 -0500524//////////////////////////////////////////////////////////////////////////////
525
Brian Salomon7eabfe82019-12-02 14:20:20 -0500526template <typename FP> class GrFragmentProcessor::IterBase {
Brian Salomonc241b582019-11-27 08:57:17 -0500527public:
Brian Salomon7eabfe82019-12-02 14:20:20 -0500528 FP& operator*() const { return *fFPStack.back(); }
529 FP* operator->() const { return fFPStack.back(); }
Brian Salomonc241b582019-11-27 08:57:17 -0500530 operator bool() const { return !fFPStack.empty(); }
531 bool operator!=(const EndIter&) { return (bool)*this; }
532
533 // Because each iterator carries a stack we want to avoid copies.
Brian Salomon7eabfe82019-12-02 14:20:20 -0500534 IterBase(const IterBase&) = delete;
535 IterBase& operator=(const IterBase&) = delete;
Brian Salomonc241b582019-11-27 08:57:17 -0500536
Brian Salomon7eabfe82019-12-02 14:20:20 -0500537protected:
538 void increment();
539
540 IterBase() = default;
541 explicit IterBase(FP& fp) { fFPStack.push_back(&fp); }
542
543 SkSTArray<4, FP*, true> fFPStack;
544};
545
546template <typename FP> void GrFragmentProcessor::IterBase<FP>::increment() {
547 SkASSERT(!fFPStack.empty());
548 FP* back = fFPStack.back();
549 fFPStack.pop_back();
550 for (int i = back->numChildProcessors() - 1; i >= 0; --i) {
551 fFPStack.push_back(&back->childProcessor(i));
552 }
553}
554
555//////////////////////////////////////////////////////////////////////////////
556
557class GrFragmentProcessor::Iter : public IterBase<GrFragmentProcessor> {
558public:
559 explicit Iter(GrFragmentProcessor& fp) : IterBase(fp) {}
560 Iter& operator++() {
561 this->increment();
562 return *this;
563 }
Brian Salomonc241b582019-11-27 08:57:17 -0500564};
565
566//////////////////////////////////////////////////////////////////////////////
567
Brian Salomon7eabfe82019-12-02 14:20:20 -0500568class GrFragmentProcessor::CIter : public IterBase<const GrFragmentProcessor> {
Brian Salomonc241b582019-11-27 08:57:17 -0500569public:
Brian Salomon7eabfe82019-12-02 14:20:20 -0500570 explicit CIter(const GrFragmentProcessor& fp) : IterBase(fp) {}
571 explicit CIter(const GrPaint&);
572 explicit CIter(const GrProcessorSet&);
573 explicit CIter(const GrPipeline&);
574 CIter& operator++() {
575 this->increment();
576 return *this;
577 }
578};
579
580//////////////////////////////////////////////////////////////////////////////
581
582template <typename Src> class GrFragmentProcessor::CIterRange {
583public:
584 explicit CIterRange(const Src& t) : fT(t) {}
585 CIter begin() const { return CIter(fT); }
Brian Salomonc241b582019-11-27 08:57:17 -0500586 EndIter end() const { return EndIter(); }
587
588private:
589 const Src& fT;
590};
591
592//////////////////////////////////////////////////////////////////////////////
593
594template <typename Item, GrFragmentProcessor::CountFn Count, GrFragmentProcessor::GetFn<Item> Get>
595class GrFragmentProcessor::FPItemIter {
596public:
Brian Salomon7eabfe82019-12-02 14:20:20 -0500597 template <typename Src> explicit FPItemIter(Src& s);
Brian Salomonc241b582019-11-27 08:57:17 -0500598
Brian Salomon7eabfe82019-12-02 14:20:20 -0500599 std::pair<Item&, const GrFragmentProcessor&> operator*() const {
Brian Salomonc241b582019-11-27 08:57:17 -0500600 return {(*fFPIter.*Get)(fIndex), *fFPIter};
601 }
602 FPItemIter& operator++();
603 operator bool() const { return fFPIter; }
604 bool operator!=(const FPItemEndIter&) { return (bool)*this; }
605
606 FPItemIter(const FPItemIter&) = delete;
607 FPItemIter& operator=(const FPItemIter&) = delete;
608
609private:
Brian Salomon7eabfe82019-12-02 14:20:20 -0500610 typename std::conditional<std::is_const<Item>::value, CIter, Iter>::type fFPIter;
Brian Salomonc241b582019-11-27 08:57:17 -0500611 int fIndex;
612};
613
Brian Salomonc241b582019-11-27 08:57:17 -0500614template <typename Item, GrFragmentProcessor::CountFn Count, GrFragmentProcessor::GetFn<Item> Get>
615template <typename Src>
Brian Salomon7eabfe82019-12-02 14:20:20 -0500616GrFragmentProcessor::FPItemIter<Item, Count, Get>::FPItemIter(Src& s) : fFPIter(s), fIndex(-1) {
Brian Salomonc241b582019-11-27 08:57:17 -0500617 if (fFPIter) {
618 ++*this;
619 }
620}
621
622template <typename Item, GrFragmentProcessor::CountFn Count, GrFragmentProcessor::GetFn<Item> Get>
623GrFragmentProcessor::FPItemIter<Item, Count, Get>&
624GrFragmentProcessor::FPItemIter<Item, Count, Get>::operator++() {
625 ++fIndex;
626 if (fIndex < ((*fFPIter).*Count)()) {
627 return *this;
628 }
629 fIndex = 0;
630 do {} while (++fFPIter && !((*fFPIter).*Count)());
631 return *this;
632}
633
Brian Salomon7eabfe82019-12-02 14:20:20 -0500634//////////////////////////////////////////////////////////////////////////////
635
636template <typename Src, typename ItemIter> class GrFragmentProcessor::FPItemRange {
637public:
638 FPItemRange(Src& src) : fSrc(src) {}
639 ItemIter begin() const { return ItemIter(fSrc); }
640 FPItemEndIter end() const { return FPItemEndIter(); }
641
642private:
643 Src& fSrc;
644};
645
bsalomon6251d172014-10-15 10:50:36 -0700646#endif