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