• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "GrProxyRef.h"
13 
14 class GrCoordTransform;
15 class GrGLSLFragmentProcessor;
16 class GrPaint;
17 class GrPipeline;
18 class GrProcessorKeyBuilder;
19 class GrShaderCaps;
20 class 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  */
27 class GrFragmentProcessor : public GrProcessor {
28 public:
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 
68     /**
69      *  Returns a fragment processor that premuls the input before calling the passed in fragment
70      *  processor.
71      */
72     static std::unique_ptr<GrFragmentProcessor> PremulInput(std::unique_ptr<GrFragmentProcessor>);
73 
74     /**
75      *  Returns a fragment processor that calls the passed in fragment processor, and then swizzles
76      *  the output.
77      */
78     static std::unique_ptr<GrFragmentProcessor> SwizzleOutput(std::unique_ptr<GrFragmentProcessor>,
79                                                               const GrSwizzle&);
80 
81     /**
82      * Returns a fragment processor that runs the passed in array of fragment processors in a
83      * series. The original input is passed to the first, the first's output is passed to the
84      * second, etc. The output of the returned processor is the output of the last processor of the
85      * series.
86      *
87      * The array elements with be moved.
88      */
89     static std::unique_ptr<GrFragmentProcessor> RunInSeries(std::unique_ptr<GrFragmentProcessor>*,
90                                                             int cnt);
91 
92     /**
93      * Makes a copy of this fragment processor that draws equivalently to the original.
94      * If the processor has child processors they are cloned as well.
95      */
96     virtual std::unique_ptr<GrFragmentProcessor> clone() const = 0;
97 
98     GrGLSLFragmentProcessor* createGLSLInstance() const;
99 
getGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b)100     void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
101         this->onGetGLSLProcessorKey(caps, b);
102         for (int i = 0; i < fChildProcessors.count(); ++i) {
103             fChildProcessors[i]->getGLSLProcessorKey(caps, b);
104         }
105     }
106 
numTextureSamplers()107     int numTextureSamplers() const { return fTextureSamplerCnt; }
108     const TextureSampler& textureSampler(int i) const;
109 
numCoordTransforms()110     int numCoordTransforms() const { return fCoordTransforms.count(); }
111 
112     /** Returns the coordinate transformation at index. index must be valid according to
113         numTransforms(). */
coordTransform(int index)114     const GrCoordTransform& coordTransform(int index) const { return *fCoordTransforms[index]; }
115 
coordTransforms()116     const SkTArray<const GrCoordTransform*, true>& coordTransforms() const {
117         return fCoordTransforms;
118     }
119 
numChildProcessors()120     int numChildProcessors() const { return fChildProcessors.count(); }
121 
childProcessor(int index)122     const GrFragmentProcessor& childProcessor(int index) const { return *fChildProcessors[index]; }
123 
124     bool instantiate(GrResourceProvider*) const;
125 
126     void markPendingExecution() const;
127 
128     /** Do any of the coordtransforms for this processor require local coords? */
usesLocalCoords()129     bool usesLocalCoords() const { return SkToBool(fFlags & kUsesLocalCoords_Flag); }
130 
131     /**
132      * A GrDrawOp may premultiply its antialiasing coverage into its GrGeometryProcessor's color
133      * output under the following scenario:
134      *   * all the color fragment processors report true to this query,
135      *   * all the coverage fragment processors report true to this query,
136      *   * the blend mode arithmetic allows for it it.
137      * To be compatible a fragment processor's output must be a modulation of its input color or
138      * alpha with a computed premultiplied color or alpha that is in 0..1 range. The computed color
139      * or alpha that is modulated against the input cannot depend on the input's alpha. The computed
140      * value cannot depend on the input's color channels unless it unpremultiplies the input color
141      * channels by the input alpha.
142      */
compatibleWithCoverageAsAlpha()143     bool compatibleWithCoverageAsAlpha() const {
144         return SkToBool(fFlags & kCompatibleWithCoverageAsAlpha_OptimizationFlag);
145     }
146 
147     /**
148      * If this is true then all opaque input colors to the processor produce opaque output colors.
149      */
preservesOpaqueInput()150     bool preservesOpaqueInput() const {
151         return SkToBool(fFlags & kPreservesOpaqueInput_OptimizationFlag);
152     }
153 
154     /**
155      * Tests whether given a constant input color the processor produces a constant output color
156      * (for all fragments). If true outputColor will contain the constant color produces for
157      * inputColor.
158      */
hasConstantOutputForConstantInput(SkPMColor4f inputColor,SkPMColor4f * outputColor)159     bool hasConstantOutputForConstantInput(SkPMColor4f inputColor, SkPMColor4f* outputColor) const {
160         if (fFlags & kConstantOutputForConstantInput_OptimizationFlag) {
161             *outputColor = this->constantOutputForConstantInput(inputColor);
162             return true;
163         }
164         return false;
165     }
hasConstantOutputForConstantInput()166     bool hasConstantOutputForConstantInput() const {
167         return SkToBool(fFlags & kConstantOutputForConstantInput_OptimizationFlag);
168     }
169 
170     /** Returns true if this and other processor conservatively draw identically. It can only return
171         true when the two processor are of the same subclass (i.e. they return the same object from
172         from getFactory()).
173 
174         A return value of true from isEqual() should not be used to test whether the processor would
175         generate the same shader code. To test for identical code generation use getGLSLProcessorKey
176      */
177     bool isEqual(const GrFragmentProcessor& that) const;
178 
179     /**
180      * Pre-order traversal of a FP hierarchy, or of the forest of FPs in a GrPipeline. In the latter
181      * case the tree rooted at each FP in the GrPipeline is visited successively.
182      */
183     class Iter : public SkNoncopyable {
184     public:
Iter(const GrFragmentProcessor * fp)185         explicit Iter(const GrFragmentProcessor* fp) { fFPStack.push_back(fp); }
186         explicit Iter(const GrPipeline& pipeline);
187         explicit Iter(const GrPaint&);
188         const GrFragmentProcessor* next();
189 
190     private:
191         SkSTArray<4, const GrFragmentProcessor*, true> fFPStack;
192     };
193 
194     /**
195      * Iterates over all the Ts owned by a GrFragmentProcessor and its children or over all the Ts
196      * owned by the forest of GrFragmentProcessors in a GrPipeline. FPs are visited in the same
197      * order as Iter and each of an FP's Ts are visited in order.
198      */
199     template <typename T, int (GrFragmentProcessor::*COUNT)() const,
200               const T& (GrFragmentProcessor::*GET)(int)const>
201     class FPItemIter : public SkNoncopyable {
202     public:
FPItemIter(const GrFragmentProcessor * fp)203         explicit FPItemIter(const GrFragmentProcessor* fp)
204                 : fCurrFP(nullptr)
205                 , fCTIdx(0)
206                 , fFPIter(fp) {
207             fCurrFP = fFPIter.next();
208         }
FPItemIter(const GrPipeline & pipeline)209         explicit FPItemIter(const GrPipeline& pipeline)
210                 : fCurrFP(nullptr)
211                 , fCTIdx(0)
212                 , fFPIter(pipeline) {
213             fCurrFP = fFPIter.next();
214         }
215 
next()216         const T* next() {
217             if (!fCurrFP) {
218                 return nullptr;
219             }
220             while (fCTIdx == (fCurrFP->*COUNT)()) {
221                 fCTIdx = 0;
222                 fCurrFP = fFPIter.next();
223                 if (!fCurrFP) {
224                     return nullptr;
225                 }
226             }
227             return &(fCurrFP->*GET)(fCTIdx++);
228         }
229 
230     private:
231         const GrFragmentProcessor*  fCurrFP;
232         int                         fCTIdx;
233         GrFragmentProcessor::Iter   fFPIter;
234     };
235 
236     using CoordTransformIter = FPItemIter<GrCoordTransform,
237                                           &GrFragmentProcessor::numCoordTransforms,
238                                           &GrFragmentProcessor::coordTransform>;
239 
240     using TextureAccessIter = FPItemIter<TextureSampler,
241                                          &GrFragmentProcessor::numTextureSamplers,
242                                          &GrFragmentProcessor::textureSampler>;
243 
244     void visitProxies(const std::function<void(GrSurfaceProxy*)>& func);
245 
246 protected:
247     enum OptimizationFlags : uint32_t {
248         kNone_OptimizationFlags,
249         kCompatibleWithCoverageAsAlpha_OptimizationFlag = 0x1,
250         kPreservesOpaqueInput_OptimizationFlag = 0x2,
251         kConstantOutputForConstantInput_OptimizationFlag = 0x4,
252         kAll_OptimizationFlags = kCompatibleWithCoverageAsAlpha_OptimizationFlag |
253                                  kPreservesOpaqueInput_OptimizationFlag |
254                                  kConstantOutputForConstantInput_OptimizationFlag
255     };
GR_DECL_BITFIELD_OPS_FRIENDS(OptimizationFlags)256     GR_DECL_BITFIELD_OPS_FRIENDS(OptimizationFlags)
257 
258     /**
259      * Can be used as a helper to decide which fragment processor OptimizationFlags should be set.
260      * This assumes that the subclass output color will be a modulation of the input color with a
261      * value read from a texture of the passed config and that the texture contains premultiplied
262      * color or alpha values that are in range.
263      *
264      * Since there are multiple ways in which a sampler may have its coordinates clamped or wrapped,
265      * callers must determine on their own if the sampling uses a decal strategy in any way, in
266      * which case the texture may become transparent regardless of the pixel config.
267      */
268     static OptimizationFlags ModulateForSamplerOptFlags(GrPixelConfig config, bool samplingDecal) {
269         if (samplingDecal) {
270             return kCompatibleWithCoverageAsAlpha_OptimizationFlag;
271         } else {
272             return ModulateForClampedSamplerOptFlags(config);
273         }
274     }
275 
276     // As above, but callers should somehow ensure or assert their sampler still uses clamping
ModulateForClampedSamplerOptFlags(GrPixelConfig config)277     static OptimizationFlags ModulateForClampedSamplerOptFlags(GrPixelConfig config) {
278         if (GrPixelConfigIsOpaque(config)) {
279             return kCompatibleWithCoverageAsAlpha_OptimizationFlag |
280                    kPreservesOpaqueInput_OptimizationFlag;
281         } else {
282             return kCompatibleWithCoverageAsAlpha_OptimizationFlag;
283         }
284     }
285 
GrFragmentProcessor(ClassID classID,OptimizationFlags optimizationFlags)286     GrFragmentProcessor(ClassID classID, OptimizationFlags optimizationFlags)
287     : INHERITED(classID)
288     , fFlags(optimizationFlags) {
289         SkASSERT((fFlags & ~kAll_OptimizationFlags) == 0);
290     }
291 
optimizationFlags()292     OptimizationFlags optimizationFlags() const {
293         return static_cast<OptimizationFlags>(kAll_OptimizationFlags & fFlags);
294     }
295 
296     /**
297      * This allows one subclass to access another subclass's implementation of
298      * constantOutputForConstantInput. It must only be called when
299      * hasConstantOutputForConstantInput() is known to be true.
300      */
ConstantOutputForConstantInput(const GrFragmentProcessor & fp,const SkPMColor4f & input)301     static SkPMColor4f ConstantOutputForConstantInput(const GrFragmentProcessor& fp,
302                                                       const SkPMColor4f& input) {
303         SkASSERT(fp.hasConstantOutputForConstantInput());
304         return fp.constantOutputForConstantInput(input);
305     }
306 
307     /**
308      * Fragment Processor subclasses call this from their constructor to register coordinate
309      * transformations. Coord transforms provide a mechanism for a processor to receive coordinates
310      * in their FS code. The matrix expresses a transformation from local space. For a given
311      * fragment the matrix will be applied to the local coordinate that maps to the fragment.
312      *
313      * When the transformation has perspective, the transformed coordinates will have
314      * 3 components. Otherwise they'll have 2.
315      *
316      * This must only be called from the constructor because GrProcessors are immutable. The
317      * processor subclass manages the lifetime of the transformations (this function only stores a
318      * pointer). The GrCoordTransform is typically a member field of the GrProcessor subclass.
319      *
320      * A processor subclass that has multiple methods of construction should always add its coord
321      * transforms in a consistent order. The non-virtual implementation of isEqual() automatically
322      * compares transforms and will assume they line up across the two processor instances.
323      */
324     void addCoordTransform(const GrCoordTransform*);
325 
326     /**
327      * FragmentProcessor subclasses call this from their constructor to register any child
328      * FragmentProcessors they have. This must be called AFTER all texture accesses and coord
329      * transforms have been added.
330      * This is for processors whose shader code will be composed of nested processors whose output
331      * colors will be combined somehow to produce its output color.  Registering these child
332      * processors will allow the ProgramBuilder to automatically handle their transformed coords and
333      * texture accesses and mangle their uniform and output color names.
334      */
335     int registerChildProcessor(std::unique_ptr<GrFragmentProcessor> child);
336 
setTextureSamplerCnt(int cnt)337     void setTextureSamplerCnt(int cnt) {
338         SkASSERT(cnt >= 0);
339         fTextureSamplerCnt = cnt;
340     }
341 
342     /**
343      * Helper for implementing onTextureSampler(). E.g.:
344      * return IthTexureSampler(i, fMyFirstSampler, fMySecondSampler, fMyThirdSampler);
345      */
346     template <typename... Args>
IthTextureSampler(int i,const TextureSampler & samp0,const Args &...samps)347     static const TextureSampler& IthTextureSampler(int i, const TextureSampler& samp0,
348                                                    const Args&... samps) {
349         return (0 == i) ? samp0 : IthTextureSampler(i - 1, samps...);
350     }
351     inline static const TextureSampler& IthTextureSampler(int i);
352 
353 private:
constantOutputForConstantInput(const SkPMColor4f &)354     virtual SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& /* inputColor */) const {
355         SK_ABORT("Subclass must override this if advertising this optimization.");
356         return SK_PMColor4fTRANSPARENT;
357     }
358 
359     /** Returns a new instance of the appropriate *GL* implementation class
360         for the given GrFragmentProcessor; caller is responsible for deleting
361         the object. */
362     virtual GrGLSLFragmentProcessor* onCreateGLSLInstance() const = 0;
363 
364     /** Implemented using GLFragmentProcessor::GenKey as described in this class's comment. */
365     virtual void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const = 0;
366 
367     /**
368      * Subclass implements this to support isEqual(). It will only be called if it is known that
369      * the two processors are of the same subclass (i.e. they return the same object from
370      * getFactory()). The processor subclass should not compare its coord transforms as that will
371      * be performed automatically in the non-virtual isEqual().
372      */
373     virtual bool onIsEqual(const GrFragmentProcessor&) const = 0;
374 
onTextureSampler(int)375     virtual const TextureSampler& onTextureSampler(int) const { return IthTextureSampler(0); }
376 
377     bool hasSameTransforms(const GrFragmentProcessor&) const;
378 
379     enum PrivateFlags {
380         kFirstPrivateFlag = kAll_OptimizationFlags + 1,
381         kUsesLocalCoords_Flag = kFirstPrivateFlag,
382     };
383 
384     mutable uint32_t fFlags = 0;
385 
386     int fTextureSamplerCnt = 0;
387 
388     SkSTArray<4, const GrCoordTransform*, true> fCoordTransforms;
389 
390     SkSTArray<1, std::unique_ptr<GrFragmentProcessor>, true> fChildProcessors;
391 
392     typedef GrProcessor INHERITED;
393 };
394 
395 /**
396  * Used to represent a texture that is required by a GrFragmentProcessor. It holds a GrTextureProxy
397  * along with an associated GrSamplerState. TextureSamplers don't perform any coord manipulation to
398  * account for texture origin.
399  */
400 class GrFragmentProcessor::TextureSampler {
401 public:
402     TextureSampler() = default;
403 
404     /**
405      * This copy constructor is used by GrFragmentProcessor::clone() implementations. The copy
406      * always takes a new ref on the texture proxy as the new fragment processor will not yet be
407      * in pending execution state.
408      */
TextureSampler(const TextureSampler & that)409     explicit TextureSampler(const TextureSampler& that)
410             : fProxyRef(sk_ref_sp(that.fProxyRef.get()), that.fProxyRef.ioType())
411             , fSamplerState(that.fSamplerState) {}
412 
413     TextureSampler(sk_sp<GrTextureProxy>, const GrSamplerState&);
414 
415     explicit TextureSampler(sk_sp<GrTextureProxy>,
416                             GrSamplerState::Filter = GrSamplerState::Filter::kNearest,
417                             GrSamplerState::WrapMode wrapXAndY = GrSamplerState::WrapMode::kClamp);
418 
419     TextureSampler& operator=(const TextureSampler&) = delete;
420 
421     void reset(sk_sp<GrTextureProxy>, const GrSamplerState&);
422     void reset(sk_sp<GrTextureProxy>,
423                GrSamplerState::Filter = GrSamplerState::Filter::kNearest,
424                GrSamplerState::WrapMode wrapXAndY = GrSamplerState::WrapMode::kClamp);
425 
426     bool operator==(const TextureSampler& that) const {
427         return this->proxy()->underlyingUniqueID() == that.proxy()->underlyingUniqueID() &&
428                fSamplerState == that.fSamplerState;
429     }
430 
431     bool operator!=(const TextureSampler& other) const { return !(*this == other); }
432 
433     // 'instantiate' should only ever be called at flush time.
instantiate(GrResourceProvider * resourceProvider)434     bool instantiate(GrResourceProvider* resourceProvider) const {
435         return SkToBool(fProxyRef.get()->instantiate(resourceProvider));
436     }
437 
438     // 'peekTexture' should only ever be called after a successful 'instantiate' call
peekTexture()439     GrTexture* peekTexture() const {
440         SkASSERT(fProxyRef.get()->peekTexture());
441         return fProxyRef.get()->peekTexture();
442     }
443 
proxy()444     GrTextureProxy* proxy() const { return fProxyRef.get(); }
samplerState()445     const GrSamplerState& samplerState() const { return fSamplerState; }
446 
isInitialized()447     bool isInitialized() const { return SkToBool(fProxyRef.get()); }
448     /**
449      * For internal use by GrFragmentProcessor.
450      */
proxyRef()451     const GrTextureProxyRef* proxyRef() const { return &fProxyRef; }
452 
453 private:
454     GrTextureProxyRef fProxyRef;
455     GrSamplerState fSamplerState;
456 };
457 
458 //////////////////////////////////////////////////////////////////////////////
459 
IthTextureSampler(int i)460 const GrFragmentProcessor::TextureSampler& GrFragmentProcessor::IthTextureSampler(int i) {
461     SK_ABORT("Illegal texture sampler index");
462     static const TextureSampler kBogus;
463     return kBogus;
464 }
465 
466 GR_MAKE_BITFIELD_OPS(GrFragmentProcessor::OptimizationFlags)
467 
468 #endif
469