• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013 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 GrGLSLFragmentProcessor_DEFINED
9 #define GrGLSLFragmentProcessor_DEFINED
10 
11 #include "include/private/SkSLString.h"
12 #include "src/gpu/GrFragmentProcessor.h"
13 #include "src/gpu/GrShaderVar.h"
14 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
15 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
16 
17 class GrProcessor;
18 class GrProcessorKeyBuilder;
19 class GrGLSLFPBuilder;
20 class GrGLSLFPFragmentBuilder;
21 
22 class GrGLSLFragmentProcessor {
23 public:
24     GrGLSLFragmentProcessor() = default;
25 
26     virtual ~GrGLSLFragmentProcessor() = default;
27 
28     using UniformHandle      = GrGLSLUniformHandler::UniformHandle;
29     using SamplerHandle      = GrGLSLUniformHandler::SamplerHandle;
30 
31 private:
32     /**
33      * This class allows the shader builder to provide each GrGLSLFragmentProcessor with an array of
34      * generated variables where each generated variable corresponds to an element of an array on
35      * the GrFragmentProcessor that generated the GLSLFP. For example, this is used to provide a
36      * variable holding transformed coords for each GrCoordTransform owned by the FP.
37      */
38     template <typename T, int (GrFragmentProcessor::*COUNT)() const>
39     class BuilderInputProvider {
40     public:
BuilderInputProvider(const GrFragmentProcessor * fp,const T * ts)41         BuilderInputProvider(const GrFragmentProcessor* fp, const T* ts) : fFP(fp) , fTs(ts) {}
42 
43         const T& operator[] (int i) const {
44             SkASSERT(i >= 0 && i < (fFP->*COUNT)());
45             return fTs[i];
46         }
47 
count()48         int count() const { return (fFP->*COUNT)(); }
49 
childInputs(int childIdx)50         BuilderInputProvider childInputs(int childIdx) const {
51             const GrFragmentProcessor* child = fFP->childProcessor(childIdx);
52             SkASSERT(child);
53             int numToSkip = 0;
54             for (const auto& fp : GrFragmentProcessor::FPRange(*fFP)) {
55                 if (&fp == child) {
56                     return BuilderInputProvider(child, fTs + numToSkip);
57                 }
58                 numToSkip += (fp.*COUNT)();
59             }
60             SK_ABORT("Didn't find the child.");
61             return {nullptr, nullptr};
62         }
63 
64     private:
65         const GrFragmentProcessor* fFP;
66         const T*                   fTs;
67     };
68 
69 public:
70     using TransformedCoordVars =
71             BuilderInputProvider<GrShaderVar, &GrFragmentProcessor::numVaryingCoordsUsed>;
72 
73     /** Called when the program stage should insert its code into the shaders. The code in each
74         shader will be in its own block ({}) and so locally scoped names will not collide across
75         stages.
76 
77         @param fragBuilder       Interface used to emit code in the shaders.
78         @param fp                The processor that generated this program stage.
79         @param key               The key that was computed by GenKey() from the generating
80                                  GrProcessor.
81         @param outputColor       A predefined half4 in the FS in which the stage should place its
82                                  output color (or coverage).
83         @param inputColor        A half4 that holds the input color to the stage in the FS. This may
84                                  be nullptr in which case the fInputColor is set to "half4(1.0)"
85                                  (solid white) so this is guaranteed non-null.
86                                  TODO: Better system for communicating optimization info
87                                  (e.g. input color is solid white, trans black, known to be opaque,
88                                  etc.) that allows the processor to communicate back similar known
89                                  info about its output.
90         @param localCoord        The name of a local coord reference to a float2 variable.
91         @param transformedCoords Fragment shader variables containing the coords computed using
92                                  each of the GrFragmentProcessor's GrCoordTransforms.
93      */
94     struct EmitArgs {
EmitArgsEmitArgs95         EmitArgs(GrGLSLFPFragmentBuilder* fragBuilder,
96                  GrGLSLUniformHandler* uniformHandler,
97                  const GrShaderCaps* caps,
98                  const GrFragmentProcessor& fp,
99                  const char* inputColor,
100                  const char* sampleCoord,
101                  const TransformedCoordVars& transformedCoordVars)
102                 : fFragBuilder(fragBuilder)
103                 , fUniformHandler(uniformHandler)
104                 , fShaderCaps(caps)
105                 , fFp(fp)
106                 , fInputColor(inputColor ? inputColor : "half4(1.0)")
107                 , fSampleCoord(sampleCoord)
108                 , fTransformedCoords(transformedCoordVars) {}
109         GrGLSLFPFragmentBuilder* fFragBuilder;
110         GrGLSLUniformHandler* fUniformHandler;
111         const GrShaderCaps* fShaderCaps;
112         const GrFragmentProcessor& fFp;
113         const char* fInputColor;
114         const char* fSampleCoord;
115         const TransformedCoordVars& fTransformedCoords;
116     };
117 
118     virtual void emitCode(EmitArgs&) = 0;
119 
120     // This does not recurse to any attached child processors. Recursing the entire processor tree
121     // is the responsibility of the caller.
122     void setData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor);
123 
numChildProcessors()124     int numChildProcessors() const { return fChildProcessors.count(); }
125 
childProcessor(int index)126     GrGLSLFragmentProcessor* childProcessor(int index) const {
127         return fChildProcessors[index].get();
128     }
129 
130     void emitChildFunction(int childIndex, EmitArgs& parentArgs);
131 
132     // Invoke the child with the default input color (solid white)
133     inline SkString invokeChild(int childIndex, EmitArgs& parentArgs,
134                                 SkSL::String skslCoords = "") {
135         return this->invokeChild(childIndex, nullptr, parentArgs, skslCoords);
136     }
137 
invokeChildWithMatrix(int childIndex,EmitArgs & parentArgs)138     inline SkString invokeChildWithMatrix(int childIndex, EmitArgs& parentArgs) {
139         return this->invokeChildWithMatrix(childIndex, nullptr, parentArgs);
140     }
141 
142     /** Invokes a child proc in its own scope. Pass in the parent's EmitArgs and invokeChild will
143      *  automatically extract the coords and samplers of that child and pass them on to the child's
144      *  emitCode(). Also, any uniforms or functions emitted by the child will have their names
145      *  mangled to prevent redefinitions. The returned string contains the output color (as a call
146      *  to the child's helper function). It is legal to pass nullptr as inputColor, since all
147      *  fragment processors are required to work without an input color.
148      *
149      *  When skslCoords is empty, invokeChild corresponds to a call to "sample(child, color)"
150      *  in SkSL. When skslCoords is not empty, invokeChild corresponds to a call to
151      *  "sample(child, color, float2)", where skslCoords is an SkSL expression that evaluates to a
152      *  float2 and is passed in as the 3rd argument.
153      */
154     SkString invokeChild(int childIndex, const char* inputColor, EmitArgs& parentArgs,
155                          SkSL::String skslCoords = "");
156 
157     /**
158      * As invokeChild, but transforms the coordinates according to the matrix expression attached
159      * to the child's SampleUsage object. This is only valid if the child is sampled with a
160      * const-uniform matrix.
161      */
162     SkString invokeChildWithMatrix(int childIndex, const char* inputColor, EmitArgs& parentArgs);
163 
164     /**
165      * Pre-order traversal of a GLSLFP hierarchy, or of multiple trees with roots in an array of
166      * GLSLFPS. If initialized with an array color followed by coverage processors installed in a
167      * program thenthe iteration order will agree with a GrFragmentProcessor::Iter initialized with
168      * a GrPipeline that produces the same program key.
169      */
170     class Iter {
171     public:
172         Iter(std::unique_ptr<GrGLSLFragmentProcessor> fps[], int cnt);
Iter(GrGLSLFragmentProcessor & fp)173         Iter(GrGLSLFragmentProcessor& fp) { fFPStack.push_back(&fp); }
174 
175         GrGLSLFragmentProcessor& operator*() const;
176         GrGLSLFragmentProcessor* operator->() const;
177         Iter& operator++();
178         operator bool() const { return !fFPStack.empty(); }
179 
180         // Because each iterator carries a stack we want to avoid copies.
181         Iter(const Iter&) = delete;
182         Iter& operator=(const Iter&) = delete;
183 
184     private:
185         SkSTArray<4, GrGLSLFragmentProcessor*, true> fFPStack;
186     };
187 
188     class ParallelIterEnd {};
189 
190     /**
191      * Walks parallel trees of GrFragmentProcessor and associated GrGLSLFragmentProcessors. The
192      * GrGLSLFragmentProcessor used to initialize the iterator must have been created by calling
193      * GrFragmentProcessor::createGLSLInstance() on the passed GrFragmentProcessor.
194      */
195     class ParallelIter {
196     public:
197         ParallelIter(const GrFragmentProcessor& fp, GrGLSLFragmentProcessor& glslFP);
198 
199         ParallelIter& operator++();
200 
201         std::tuple<const GrFragmentProcessor&, GrGLSLFragmentProcessor&> operator*() const;
202 
203         bool operator==(const ParallelIterEnd& end) const;
204 
205         bool operator!=(const ParallelIterEnd& end) const { return !(*this == end); }
206 
207     private:
208         GrFragmentProcessor::CIter fpIter;
209         GrGLSLFragmentProcessor::Iter glslIter;
210     };
211 
212     class ParallelRange {
213     public:
214         ParallelRange(const GrFragmentProcessor& fp, GrGLSLFragmentProcessor& glslFP);
215 
begin()216         ParallelIter begin() { return {fInitialFP, fInitialGLSLFP}; }
217 
end()218         ParallelIterEnd end() { return {}; }
219 
220     private:
221         const GrFragmentProcessor& fInitialFP;
222         GrGLSLFragmentProcessor& fInitialGLSLFP;
223     };
224 
225 protected:
226     /** A GrGLSLFragmentProcessor instance can be reused with any GrFragmentProcessor that produces
227     the same stage key; this function reads data from a GrFragmentProcessor and uploads any
228     uniform variables required by the shaders created in emitCode(). The GrFragmentProcessor
229     parameter is guaranteed to be of the same type that created this GrGLSLFragmentProcessor and
230     to have an identical processor key as the one that created this GrGLSLFragmentProcessor.  */
onSetData(const GrGLSLProgramDataManager &,const GrFragmentProcessor &)231     virtual void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) {}
232 
233 private:
234     // one per child; either not present or empty string if not yet emitted
235     SkTArray<SkString> fFunctionNames;
236 
237     SkTArray<std::unique_ptr<GrGLSLFragmentProcessor>, true> fChildProcessors;
238 
239     friend class GrFragmentProcessor;
240 };
241 
242 #endif
243