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 "src/gpu/GrCoordTransform.h"
12#include "src/gpu/GrProcessor.h"
13#include "src/gpu/ops/GrOp.h"
14
15class GrGLSLFragmentProcessor;
16class GrPaint;
17class GrPipeline;
18class GrProcessorKeyBuilder;
19class GrShaderCaps;
20class GrSwizzle;
21
22/** Provides custom fragment shader code. Fragment processors receive an input color (half4) and
23 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 */
27class GrFragmentProcessor : public GrProcessor {
28public:
29 class TextureSampler;
30
31 /**
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 */
39 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);
50
51 /**
52 * 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.
56 */
57 static std::unique_ptr<GrFragmentProcessor> MakeInputPremulAndMulByOutput(
58 std::unique_ptr<GrFragmentProcessor>);
59
60 /**
61 * 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.
64 */
65 static std::unique_ptr<GrFragmentProcessor> OverrideInput(std::unique_ptr<GrFragmentProcessor>,
66 const SkPMColor4f&,
67 bool useUniform = true);
68
69 /**
70 * Returns a fragment processor that premuls the input before calling the passed in fragment
71 * processor.
72 */
73 static std::unique_ptr<GrFragmentProcessor> PremulInput(std::unique_ptr<GrFragmentProcessor>);
74
75 /**
76 * Returns a fragment processor that calls the passed in fragment processor, and then swizzles
77 * the output.
78 */
79 static std::unique_ptr<GrFragmentProcessor> SwizzleOutput(std::unique_ptr<GrFragmentProcessor>,
80 const GrSwizzle&);
81
82 /**
83 * Returns a fragment processor that calls the passed in fragment processor, and then ensures
84 * the output is a valid premul color by clamping RGB to [0, A].
85 */
86 static std::unique_ptr<GrFragmentProcessor> ClampPremulOutput(
87 std::unique_ptr<GrFragmentProcessor>);
88
89 /**
90 * Returns a fragment processor that runs the passed in array of fragment processors in a
91 * series. The original input is passed to the first, the first's output is passed to the
92 * second, etc. The output of the returned processor is the output of the last processor of the
93 * series.
94 *
95 * The array elements with be moved.
96 */
97 static std::unique_ptr<GrFragmentProcessor> RunInSeries(std::unique_ptr<GrFragmentProcessor>[],
98 int cnt);
99
100 /**
101 * Makes a copy of this fragment processor that draws equivalently to the original.
102 * If the processor has child processors they are cloned as well.
103 */
104 virtual std::unique_ptr<GrFragmentProcessor> clone() const = 0;
105
106 GrGLSLFragmentProcessor* createGLSLInstance() const;
107
108 void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
109 this->onGetGLSLProcessorKey(caps, b);
110 for (int i = 0; i < fChildProcessors.count(); ++i) {
111 fChildProcessors[i]->getGLSLProcessorKey(caps, b);
112 }
113 }
114
115 int numTextureSamplers() const { return fTextureSamplerCnt; }
116 const TextureSampler& textureSampler(int i) const;
117
118 int numCoordTransforms() const { return fCoordTransforms.count(); }
119
120 /** Returns the coordinate transformation at index. index must be valid according to
121 numCoordTransforms(). */
122 const GrCoordTransform& coordTransform(int index) const { return *fCoordTransforms[index]; }
123 GrCoordTransform& coordTransform(int index) { return *fCoordTransforms[index]; }
124
125 const SkTArray<GrCoordTransform*, true>& coordTransforms() const {
126 return fCoordTransforms;
127 }
128
129 int numChildProcessors() const { return fChildProcessors.count(); }
130
131 GrFragmentProcessor& childProcessor(int index) { return *fChildProcessors[index]; }
132 const GrFragmentProcessor& childProcessor(int index) const { return *fChildProcessors[index]; }
133
134 SkDEBUGCODE(bool isInstantiated() const;)
135
136 /** Do any of the coord transforms for this processor require local coords? */
137 bool usesLocalCoords() const {
138 // If the processor is sampled with explicit coords then we do not need to apply the
139 // coord transforms in the vertex shader to the local coords.
140 return SkToBool(fFlags & kHasCoordTransforms_Flag) &&
141 !SkToBool(fFlags & kSampledWithExplicitCoords);
142 }
143
144 bool isSampledWithExplicitCoords() const {
145 return SkToBool(fFlags & kSampledWithExplicitCoords);
146 }
147
148 void setSampledWithExplicitCoords(bool value) {
149 if (value) {
150 fFlags |= kSampledWithExplicitCoords;
151 } else {
152 fFlags &= ~kSampledWithExplicitCoords;
153 }
154 for (auto& child : fChildProcessors) {
155 child->setSampledWithExplicitCoords(value);
156 }
157 }
158
159 /**
160 * A GrDrawOp may premultiply its antialiasing coverage into its GrGeometryProcessor's color
161 * output under the following scenario:
162 * * all the color fragment processors report true to this query,
163 * * all the coverage fragment processors report true to this query,
164 * * the blend mode arithmetic allows for it it.
165 * To be compatible a fragment processor's output must be a modulation of its input color or
166 * alpha with a computed premultiplied color or alpha that is in 0..1 range. The computed color
167 * or alpha that is modulated against the input cannot depend on the input's alpha. The computed
168 * value cannot depend on the input's color channels unless it unpremultiplies the input color
169 * channels by the input alpha.
170 */
171 bool compatibleWithCoverageAsAlpha() const {
172 return SkToBool(fFlags & kCompatibleWithCoverageAsAlpha_OptimizationFlag);
173 }
174
175 /**
176 * If this is true then all opaque input colors to the processor produce opaque output colors.
177 */
178 bool preservesOpaqueInput() const {
179 return SkToBool(fFlags & kPreservesOpaqueInput_OptimizationFlag);
180 }
181
182 /**
183 * Tests whether given a constant input color the processor produces a constant output color
184 * (for all fragments). If true outputColor will contain the constant color produces for
185 * inputColor.
186 */
187 bool hasConstantOutputForConstantInput(SkPMColor4f inputColor, SkPMColor4f* outputColor) const {
188 if (fFlags & kConstantOutputForConstantInput_OptimizationFlag) {
189 *outputColor = this->constantOutputForConstantInput(inputColor);
190 return true;
191 }
192 return false;
193 }
194 bool hasConstantOutputForConstantInput() const {
195 return SkToBool(fFlags & kConstantOutputForConstantInput_OptimizationFlag);
196 }
197
198 /** Returns true if this and other processor conservatively draw identically. It can only return
199 true when the two processor are of the same subclass (i.e. they return the same object from
200 from getFactory()).
201
202 A return value of true from isEqual() should not be used to test whether the processor would
203 generate the same shader code. To test for identical code generation use getGLSLProcessorKey
204 */
205 bool isEqual(const GrFragmentProcessor& that) const;
206
207 void visitProxies(const GrOp::VisitProxyFunc& func);
208
209 // A pre-order traversal iterator over a hierarchy of FPs. It can also iterate over all the FP
210 // hierarchies rooted in a GrPaint, GrProcessorSet, or GrPipeline. For these collections it
211 // iterates the tree rooted at each color FP and then each coverage FP.
212 //
213 // Iter is the non-const version and CIter is the const version.
214 //
215 // An iterator is constructed from one of the srcs and used like this:
216 // for (GrFragmentProcessor::Iter iter(pipeline); iter; ++iter) {
217 // GrFragmentProcessor& fp = *iter;
218 // }
219 // The exit test for the loop is using Iter's operator bool().
220 // To use a range-for loop instead see CIterRange below.
221 class Iter;
222 class CIter;
223
224 // Used to implement a range-for loop using CIter. Src is one of GrFragmentProcessor,
225 // GrPaint, GrProcessorSet, or GrPipeline. Type aliases for these defined below.
226 // Example usage:
227 // for (const auto& fp : GrFragmentProcessor::PaintRange(paint)) {
228 // if (fp.usesLocalCoords()) {
229 // ...
230 // }
231 // }
232 template <typename Src> class CIterRange;
233 // Like CIterRange but non const and only constructable from GrFragmentProcessor. This could
234 // support GrPaint as it owns non-const FPs but no need for it as of now.
235 // for (auto& fp0 : GrFragmentProcessor::IterRange(fp)) {
236 // ...
237 // }
238 class IterRange;
239
240 // We would use template deduction guides for Iter/CIter but for:
241 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79501
242 // Instead we use these specialized type aliases to make it prettier
243 // to construct Iters for particular sources of FPs.
244 using FPCRange = CIterRange<GrFragmentProcessor>;
245 using PaintCRange = CIterRange<GrPaint>;
246
247 // Implementation details for iterators that walk an array of Items owned by a set of FPs.
248 using CountFn = int (GrFragmentProcessor::*)() const;
249 // Defined GetFn to be a member function that returns an Item by index. The function itself is
250 // const if Item is a const type and non-const if Item is non-const.
251 template <typename Item, bool IsConst = std::is_const<Item>::value> struct GetT;
252 template <typename Item> struct GetT<Item, false> {
253 using GetFn = Item& (GrFragmentProcessor::*)(int);
254 };
255 template <typename Item> struct GetT<Item, true> {
256 using GetFn = const Item& (GrFragmentProcessor::*)(int) const;
257 };
258 template <typename Item> using GetFn = typename GetT<Item>::GetFn;
259 // This is an iterator over the Items owned by a (collection of) FP. CountFn is a FP member that
260 // gets the number of Items owned by each FP and GetFn is a member that gets them by index.
261 template <typename Item, CountFn Count, GetFn<Item> Get> class FPItemIter;
262
263 // Loops over all the GrCoordTransforms owned by GrFragmentProcessors. The possible sources for
264 // the iteration are the same as those for Iter and the FPs are walked in the same order as
265 // Iter. This provides access to the coord transform and the FP that owns it. Example usage:
266 // for (GrFragmentProcessor::CoordTransformIter iter(pipeline); iter; ++iter) {
267 // // transform is const GrCoordTransform& and owningFP is const GrFragmentProcessor&.
268 // auto [transform, owningFP] = *iter;
269 // ...
270 // }
271 // See the ranges below to make this simpler a la range-for loops.
272 using CoordTransformIter = FPItemIter<const GrCoordTransform,
273 &GrFragmentProcessor::numCoordTransforms,
274 &GrFragmentProcessor::coordTransform>;
275 // Same as CoordTransformIter but for TextureSamplers:
276 // for (GrFragmentProcessor::TextureSamplerIter iter(pipeline); iter; ++iter) {
277 // // TextureSamplerIter is const GrFragmentProcessor::TextureSampler& and
278 // // owningFP is const GrFragmentProcessor&.
279 // auto [sampler, owningFP] = *iter;
280 // ...
281 // }
282 // See the ranges below to make this simpler a la range-for loops.
283 using TextureSamplerIter = FPItemIter<const TextureSampler,
284 &GrFragmentProcessor::numTextureSamplers,
285 &GrFragmentProcessor::textureSampler>;
286
287 // Implementation detail for using CoordTransformIter and TextureSamplerIter in range-for loops.
288 template <typename Src, typename ItemIter> class FPItemRange;
289
290 // These allow iteration over coord transforms/texture samplers for various FP sources via
291 // range-for loops. An example usage for looping over the coord transforms in a pipeline:
292 // for (auto [transform, fp] : GrFragmentProcessor::PipelineCoordTransformRange(pipeline)) {
293 // ...
294 // }
295 // Only the combinations of FP sources and iterable things have been defined but it is easy
296 // to add more as they become useful. Maybe someday we'll have template argument deduction
297 // with guides for type aliases and the sources can be removed from the type aliases:
298 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1021r5.html
299 using PipelineCoordTransformRange = FPItemRange<const GrPipeline, CoordTransformIter>;
300 using PipelineTextureSamplerRange = FPItemRange<const GrPipeline, TextureSamplerIter>;
301 using FPTextureSamplerRange = FPItemRange<const GrFragmentProcessor, TextureSamplerIter>;
302 using ProcessorSetTextureSamplerRange = FPItemRange<const GrProcessorSet, TextureSamplerIter>;
303
304 // Not used directly.
305 using NonConstCoordTransformIter =
306 FPItemIter<GrCoordTransform, &GrFragmentProcessor::numCoordTransforms,
307 &GrFragmentProcessor::coordTransform>;
308 // Iterator over non-const GrCoordTransforms owned by FP and its descendants.
309 using FPCoordTransformRange = FPItemRange<GrFragmentProcessor, NonConstCoordTransformIter>;
310
311 // Sentinel type for range-for using Iter.
312 class EndIter {};
313 // Sentinel type for range-for using FPItemIter.
314 class FPItemEndIter {};
315
316protected:
317 enum OptimizationFlags : uint32_t {
318 kNone_OptimizationFlags,
319 kCompatibleWithCoverageAsAlpha_OptimizationFlag = 0x1,
320 kPreservesOpaqueInput_OptimizationFlag = 0x2,
321 kConstantOutputForConstantInput_OptimizationFlag = 0x4,
322 kAll_OptimizationFlags = kCompatibleWithCoverageAsAlpha_OptimizationFlag |
323 kPreservesOpaqueInput_OptimizationFlag |
324 kConstantOutputForConstantInput_OptimizationFlag
325 };
326 GR_DECL_BITFIELD_OPS_FRIENDS(OptimizationFlags)
327
328 /**
329 * Can be used as a helper to decide which fragment processor OptimizationFlags should be set.
330 * This assumes that the subclass output color will be a modulation of the input color with a
331 * value read from a texture of the passed color type and that the texture contains
332 * premultiplied color or alpha values that are in range.
333 *
334 * Since there are multiple ways in which a sampler may have its coordinates clamped or wrapped,
335 * callers must determine on their own if the sampling uses a decal strategy in any way, in
336 * which case the texture may become transparent regardless of the color type.
337 */
338 static OptimizationFlags ModulateForSamplerOptFlags(SkAlphaType alphaType, bool samplingDecal) {
339 if (samplingDecal) {
340 return kCompatibleWithCoverageAsAlpha_OptimizationFlag;
341 } else {
342 return ModulateForClampedSamplerOptFlags(alphaType);
343 }
344 }
345
346 // As above, but callers should somehow ensure or assert their sampler still uses clamping
347 static OptimizationFlags ModulateForClampedSamplerOptFlags(SkAlphaType alphaType) {
348 if (alphaType == kOpaque_SkAlphaType) {
349 return kCompatibleWithCoverageAsAlpha_OptimizationFlag |
350 kPreservesOpaqueInput_OptimizationFlag;
351 } else {
352 return kCompatibleWithCoverageAsAlpha_OptimizationFlag;
353 }
354 }
355
356 GrFragmentProcessor(ClassID classID, OptimizationFlags optimizationFlags)
357 : INHERITED(classID), fFlags(optimizationFlags) {
358 SkASSERT((optimizationFlags & ~kAll_OptimizationFlags) == 0);
359 }
360
361 OptimizationFlags optimizationFlags() const {
362 return static_cast<OptimizationFlags>(kAll_OptimizationFlags & fFlags);
363 }
364
365 /** Useful when you can't call fp->optimizationFlags() on a base class object from a subclass.*/
366 static OptimizationFlags ProcessorOptimizationFlags(const GrFragmentProcessor* fp) {
367 return fp->optimizationFlags();
368 }
369
370 /**
371 * This allows one subclass to access another subclass's implementation of
372 * constantOutputForConstantInput. It must only be called when
373 * hasConstantOutputForConstantInput() is known to be true.
374 */
375 static SkPMColor4f ConstantOutputForConstantInput(const GrFragmentProcessor& fp,
376 const SkPMColor4f& input) {
377 SkASSERT(fp.hasConstantOutputForConstantInput());
378 return fp.constantOutputForConstantInput(input);
379 }
380
381 /**
382 * Fragment Processor subclasses call this from their constructor to register coordinate
383 * transformations. Coord transforms provide a mechanism for a processor to receive coordinates
384 * in their FS code. The matrix expresses a transformation from local space. For a given
385 * fragment the matrix will be applied to the local coordinate that maps to the fragment.
386 *
387 * When the transformation has perspective, the transformed coordinates will have
388 * 3 components. Otherwise they'll have 2.
389 *
390 * This must only be called from the constructor because GrProcessors are immutable. The
391 * processor subclass manages the lifetime of the transformations (this function only stores a
392 * pointer). The GrCoordTransform is typically a member field of the GrProcessor subclass.
393 *
394 * A processor subclass that has multiple methods of construction should always add its coord
395 * transforms in a consistent order. The non-virtual implementation of isEqual() automatically
396 * compares transforms and will assume they line up across the two processor instances.
397 */
398 void addCoordTransform(GrCoordTransform*);
399
400 /**
401 * FragmentProcessor subclasses call this from their constructor to register any child
402 * FragmentProcessors they have. This must be called AFTER all texture accesses and coord
403 * transforms have been added.
404 * This is for processors whose shader code will be composed of nested processors whose output
405 * colors will be combined somehow to produce its output color. Registering these child
406 * processors will allow the ProgramBuilder to automatically handle their transformed coords and
407 * texture accesses and mangle their uniform and output color names.
408 */
409 int registerChildProcessor(std::unique_ptr<GrFragmentProcessor> child);
410
411 void setTextureSamplerCnt(int cnt) {
412 SkASSERT(cnt >= 0);
413 fTextureSamplerCnt = cnt;
414 }
415
416 /**
417 * Helper for implementing onTextureSampler(). E.g.:
418 * return IthTexureSampler(i, fMyFirstSampler, fMySecondSampler, fMyThirdSampler);
419 */
420 template <typename... Args>
421 static const TextureSampler& IthTextureSampler(int i, const TextureSampler& samp0,
422 const Args&... samps) {
423 return (0 == i) ? samp0 : IthTextureSampler(i - 1, samps...);
424 }
425 inline static const TextureSampler& IthTextureSampler(int i);
426
427private:
428 // Implementation details of Iter and CIter.
429 template <typename> class IterBase;
430
431 virtual SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& /* inputColor */) const {
432 SK_ABORT("Subclass must override this if advertising this optimization.");
433 }
434
435 /** Returns a new instance of the appropriate *GL* implementation class
436 for the given GrFragmentProcessor; caller is responsible for deleting
437 the object. */
438 virtual GrGLSLFragmentProcessor* onCreateGLSLInstance() const = 0;
439
440 /** Implemented using GLFragmentProcessor::GenKey as described in this class's comment. */
441 virtual void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const = 0;
442
443 /**
444 * Subclass implements this to support isEqual(). It will only be called if it is known that
445 * the two processors are of the same subclass (i.e. they return the same object from
446 * getFactory()). The processor subclass should not compare its coord transforms as that will
447 * be performed automatically in the non-virtual isEqual().
448 */
449 virtual bool onIsEqual(const GrFragmentProcessor&) const = 0;
450
451 virtual const TextureSampler& onTextureSampler(int) const { return IthTextureSampler(0); }
452
453 bool hasSameTransforms(const GrFragmentProcessor&) const;
454
455 enum PrivateFlags {
456 kFirstPrivateFlag = kAll_OptimizationFlags + 1,
457 kHasCoordTransforms_Flag = kFirstPrivateFlag,
458 kSampledWithExplicitCoords = kFirstPrivateFlag << 1,
459 };
460
461 uint32_t fFlags = 0;
462
463 int fTextureSamplerCnt = 0;
464
465 SkSTArray<4, GrCoordTransform*, true> fCoordTransforms;
466
467 SkSTArray<1, std::unique_ptr<GrFragmentProcessor>, true> fChildProcessors;
468
469 typedef GrProcessor INHERITED;
470};
471
472/**
473 * Used to represent a texture that is required by a GrFragmentProcessor. It holds a GrTextureProxy
474 * along with an associated GrSamplerState. TextureSamplers don't perform any coord manipulation to
475 * account for texture origin.
476 */
477class GrFragmentProcessor::TextureSampler {
478public:
479 TextureSampler() = default;
480
481 /**
482 * This copy constructor is used by GrFragmentProcessor::clone() implementations.
483 */
484 explicit TextureSampler(const TextureSampler&) = default;
485
486 TextureSampler(GrSurfaceProxyView, GrSamplerState = {});
487
488 TextureSampler& operator=(const TextureSampler&) = delete;
489
490 bool operator==(const TextureSampler& that) const {
491 return fView == that.fView && fSamplerState == that.fSamplerState;
492 }
493
494 bool operator!=(const TextureSampler& other) const { return !(*this == other); }
495
496 SkDEBUGCODE(bool isInstantiated() const { return this->proxy()->isInstantiated(); })
497
498 // 'peekTexture' should only ever be called after a successful 'instantiate' call
499 GrTexture* peekTexture() const {
500 SkASSERT(this->proxy()->isInstantiated());
501 return this->proxy()->peekTexture();
502 }
503
504 const GrSurfaceProxyView& view() const { return fView; }
505 GrSamplerState samplerState() const { return fSamplerState; }
506
507 bool isInitialized() const { return SkToBool(this->proxy()); }
508
509 GrSurfaceProxy* proxy() const { return fView.proxy(); }
510
511#if GR_TEST_UTILS
512 void set(GrSurfaceProxyView, GrSamplerState);
513#endif
514
515private:
516 GrSurfaceProxyView fView;
517 GrSamplerState fSamplerState;
518};
519
520//////////////////////////////////////////////////////////////////////////////
521
522const GrFragmentProcessor::TextureSampler& GrFragmentProcessor::IthTextureSampler(int i) {
523 SK_ABORT("Illegal texture sampler index");
524 static const TextureSampler kBogus;
525 return kBogus;
526}
527
528GR_MAKE_BITFIELD_OPS(GrFragmentProcessor::OptimizationFlags)
529
530//////////////////////////////////////////////////////////////////////////////
531
532template <typename FP> class GrFragmentProcessor::IterBase {
533public:
534 FP& operator*() const { return *fFPStack.back(); }
535 FP* operator->() const { return fFPStack.back(); }
536 operator bool() const { return !fFPStack.empty(); }
537 bool operator!=(const EndIter&) { return (bool)*this; }
538
539 // Hopefully this does not actually get called because of RVO.
540 IterBase(const IterBase&) = default;
541
542 // Because each iterator carries a stack we want to avoid copies.
543 IterBase& operator=(const IterBase&) = delete;
544
545protected:
546 void increment();
547
548 IterBase() = default;
549 explicit IterBase(FP& fp) { fFPStack.push_back(&fp); }
550
551 SkSTArray<4, FP*, true> fFPStack;
552};
553
554template <typename FP> void GrFragmentProcessor::IterBase<FP>::increment() {
555 SkASSERT(!fFPStack.empty());
556 FP* back = fFPStack.back();
557 fFPStack.pop_back();
558 for (int i = back->numChildProcessors() - 1; i >= 0; --i) {
559 fFPStack.push_back(&back->childProcessor(i));
560 }
561}
562
563//////////////////////////////////////////////////////////////////////////////
564
565class GrFragmentProcessor::Iter : public IterBase<GrFragmentProcessor> {
566public:
567 explicit Iter(GrFragmentProcessor& fp) : IterBase(fp) {}
568 Iter& operator++() {
569 this->increment();
570 return *this;
571 }
572};
573
574//////////////////////////////////////////////////////////////////////////////
575
576class GrFragmentProcessor::CIter : public IterBase<const GrFragmentProcessor> {
577public:
578 explicit CIter(const GrFragmentProcessor& fp) : IterBase(fp) {}
579 explicit CIter(const GrPaint&);
580 explicit CIter(const GrProcessorSet&);
581 explicit CIter(const GrPipeline&);
582 CIter& operator++() {
583 this->increment();
584 return *this;
585 }
586};
587
588//////////////////////////////////////////////////////////////////////////////
589
590template <typename Src> class GrFragmentProcessor::CIterRange {
591public:
592 explicit CIterRange(const Src& t) : fT(t) {}
593 CIter begin() const { return CIter(fT); }
594 EndIter end() const { return EndIter(); }
595
596private:
597 const Src& fT;
598};
599
600//////////////////////////////////////////////////////////////////////////////
601
602template <typename Item, GrFragmentProcessor::CountFn Count, GrFragmentProcessor::GetFn<Item> Get>
603class GrFragmentProcessor::FPItemIter {
604public:
605 template <typename Src> explicit FPItemIter(Src& s);
606
607 std::pair<Item&, const GrFragmentProcessor&> operator*() const {
608 return {(*fFPIter.*Get)(fIndex), *fFPIter};
609 }
610 FPItemIter& operator++();
611 operator bool() const { return fFPIter; }
612 bool operator!=(const FPItemEndIter&) { return (bool)*this; }
613
614 FPItemIter(const FPItemIter&) = delete;
615 FPItemIter& operator=(const FPItemIter&) = delete;
616
617private:
618 typename std::conditional<std::is_const<Item>::value, CIter, Iter>::type fFPIter;
619 int fIndex;
620};
621
622template <typename Item, GrFragmentProcessor::CountFn Count, GrFragmentProcessor::GetFn<Item> Get>
623template <typename Src>
624GrFragmentProcessor::FPItemIter<Item, Count, Get>::FPItemIter(Src& s) : fFPIter(s), fIndex(-1) {
625 if (fFPIter) {
626 ++*this;
627 }
628}
629
630template <typename Item, GrFragmentProcessor::CountFn Count, GrFragmentProcessor::GetFn<Item> Get>
631GrFragmentProcessor::FPItemIter<Item, Count, Get>&
632GrFragmentProcessor::FPItemIter<Item, Count, Get>::operator++() {
633 ++fIndex;
634 if (fIndex < ((*fFPIter).*Count)()) {
635 return *this;
636 }
637 fIndex = 0;
638 do {} while (++fFPIter && !((*fFPIter).*Count)());
639 return *this;
640}
641
642//////////////////////////////////////////////////////////////////////////////
643
644template <typename Src, typename ItemIter> class GrFragmentProcessor::FPItemRange {
645public:
646 FPItemRange(Src& src) : fSrc(src) {}
647 ItemIter begin() const { return ItemIter(fSrc); }
648 FPItemEndIter end() const { return FPItemEndIter(); }
649
650private:
651 Src& fSrc;
652};
653
654#endif
655