| /* |
| * Copyright 2013 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef GrGLSLFragmentProcessor_DEFINED |
| #define GrGLSLFragmentProcessor_DEFINED |
| |
| #include "include/private/SkSLString.h" |
| #include "src/gpu/GrFragmentProcessor.h" |
| #include "src/gpu/GrShaderVar.h" |
| #include "src/gpu/glsl/GrGLSLProgramDataManager.h" |
| #include "src/gpu/glsl/GrGLSLUniformHandler.h" |
| |
| class GrProcessor; |
| class GrProcessorKeyBuilder; |
| class GrGLSLFPBuilder; |
| class GrGLSLFPFragmentBuilder; |
| |
| class GrGLSLFragmentProcessor { |
| public: |
| GrGLSLFragmentProcessor() = default; |
| |
| virtual ~GrGLSLFragmentProcessor() = default; |
| |
| using UniformHandle = GrGLSLUniformHandler::UniformHandle; |
| using SamplerHandle = GrGLSLUniformHandler::SamplerHandle; |
| |
| private: |
| /** |
| * This class allows the shader builder to provide each GrGLSLFragmentProcessor with an array of |
| * generated variables where each generated variable corresponds to an element of an array on |
| * the GrFragmentProcessor that generated the GLSLFP. For example, this is used to provide a |
| * variable holding transformed coords for each GrCoordTransform owned by the FP. |
| */ |
| template <typename T, int (GrFragmentProcessor::*COUNT)() const> |
| class BuilderInputProvider { |
| public: |
| BuilderInputProvider(const GrFragmentProcessor* fp, const T* ts) : fFP(fp) , fTs(ts) {} |
| |
| const T& operator[] (int i) const { |
| SkASSERT(i >= 0 && i < (fFP->*COUNT)()); |
| return fTs[i]; |
| } |
| |
| int count() const { return (fFP->*COUNT)(); } |
| |
| BuilderInputProvider childInputs(int childIdx) const { |
| const GrFragmentProcessor* child = fFP->childProcessor(childIdx); |
| SkASSERT(child); |
| int numToSkip = 0; |
| for (const auto& fp : GrFragmentProcessor::FPRange(*fFP)) { |
| if (&fp == child) { |
| return BuilderInputProvider(child, fTs + numToSkip); |
| } |
| numToSkip += (fp.*COUNT)(); |
| } |
| SK_ABORT("Didn't find the child."); |
| return {nullptr, nullptr}; |
| } |
| |
| private: |
| const GrFragmentProcessor* fFP; |
| const T* fTs; |
| }; |
| |
| public: |
| using TransformedCoordVars = |
| BuilderInputProvider<GrShaderVar, &GrFragmentProcessor::numVaryingCoordsUsed>; |
| |
| /** Called when the program stage should insert its code into the shaders. The code in each |
| shader will be in its own block ({}) and so locally scoped names will not collide across |
| stages. |
| |
| @param fragBuilder Interface used to emit code in the shaders. |
| @param fp The processor that generated this program stage. |
| @param key The key that was computed by GenKey() from the generating |
| GrProcessor. |
| @param outputColor A predefined half4 in the FS in which the stage should place its |
| output color (or coverage). |
| @param inputColor A half4 that holds the input color to the stage in the FS. This may |
| be nullptr in which case the fInputColor is set to "half4(1.0)" |
| (solid white) so this is guaranteed non-null. |
| TODO: Better system for communicating optimization info |
| (e.g. input color is solid white, trans black, known to be opaque, |
| etc.) that allows the processor to communicate back similar known |
| info about its output. |
| @param localCoord The name of a local coord reference to a float2 variable. |
| @param transformedCoords Fragment shader variables containing the coords computed using |
| each of the GrFragmentProcessor's GrCoordTransforms. |
| */ |
| struct EmitArgs { |
| EmitArgs(GrGLSLFPFragmentBuilder* fragBuilder, |
| GrGLSLUniformHandler* uniformHandler, |
| const GrShaderCaps* caps, |
| const GrFragmentProcessor& fp, |
| const char* inputColor, |
| const char* sampleCoord, |
| const TransformedCoordVars& transformedCoordVars) |
| : fFragBuilder(fragBuilder) |
| , fUniformHandler(uniformHandler) |
| , fShaderCaps(caps) |
| , fFp(fp) |
| , fInputColor(inputColor ? inputColor : "half4(1.0)") |
| , fSampleCoord(sampleCoord) |
| , fTransformedCoords(transformedCoordVars) {} |
| GrGLSLFPFragmentBuilder* fFragBuilder; |
| GrGLSLUniformHandler* fUniformHandler; |
| const GrShaderCaps* fShaderCaps; |
| const GrFragmentProcessor& fFp; |
| const char* fInputColor; |
| const char* fSampleCoord; |
| const TransformedCoordVars& fTransformedCoords; |
| }; |
| |
| virtual void emitCode(EmitArgs&) = 0; |
| |
| // This does not recurse to any attached child processors. Recursing the entire processor tree |
| // is the responsibility of the caller. |
| void setData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor); |
| |
| int numChildProcessors() const { return fChildProcessors.count(); } |
| |
| GrGLSLFragmentProcessor* childProcessor(int index) const { |
| return fChildProcessors[index].get(); |
| } |
| |
| void emitChildFunction(int childIndex, EmitArgs& parentArgs); |
| |
| // Invoke the child with the default input color (solid white) |
| inline SkString invokeChild(int childIndex, EmitArgs& parentArgs, |
| SkSL::String skslCoords = "") { |
| return this->invokeChild(childIndex, nullptr, parentArgs, skslCoords); |
| } |
| |
| inline SkString invokeChildWithMatrix(int childIndex, EmitArgs& parentArgs) { |
| return this->invokeChildWithMatrix(childIndex, nullptr, parentArgs); |
| } |
| |
| /** Invokes a child proc in its own scope. Pass in the parent's EmitArgs and invokeChild will |
| * automatically extract the coords and samplers of that child and pass them on to the child's |
| * emitCode(). Also, any uniforms or functions emitted by the child will have their names |
| * mangled to prevent redefinitions. The returned string contains the output color (as a call |
| * to the child's helper function). It is legal to pass nullptr as inputColor, since all |
| * fragment processors are required to work without an input color. |
| * |
| * When skslCoords is empty, invokeChild corresponds to a call to "sample(child, color)" |
| * in SkSL. When skslCoords is not empty, invokeChild corresponds to a call to |
| * "sample(child, color, float2)", where skslCoords is an SkSL expression that evaluates to a |
| * float2 and is passed in as the 3rd argument. |
| */ |
| SkString invokeChild(int childIndex, const char* inputColor, EmitArgs& parentArgs, |
| SkSL::String skslCoords = ""); |
| |
| /** |
| * As invokeChild, but transforms the coordinates according to the matrix expression attached |
| * to the child's SampleUsage object. This is only valid if the child is sampled with a |
| * const-uniform matrix. |
| */ |
| SkString invokeChildWithMatrix(int childIndex, const char* inputColor, EmitArgs& parentArgs); |
| |
| /** |
| * Pre-order traversal of a GLSLFP hierarchy, or of multiple trees with roots in an array of |
| * GLSLFPS. If initialized with an array color followed by coverage processors installed in a |
| * program thenthe iteration order will agree with a GrFragmentProcessor::Iter initialized with |
| * a GrPipeline that produces the same program key. |
| */ |
| class Iter { |
| public: |
| Iter(std::unique_ptr<GrGLSLFragmentProcessor> fps[], int cnt); |
| Iter(GrGLSLFragmentProcessor& fp) { fFPStack.push_back(&fp); } |
| |
| GrGLSLFragmentProcessor& operator*() const; |
| GrGLSLFragmentProcessor* operator->() const; |
| Iter& operator++(); |
| operator bool() const { return !fFPStack.empty(); } |
| |
| // Because each iterator carries a stack we want to avoid copies. |
| Iter(const Iter&) = delete; |
| Iter& operator=(const Iter&) = delete; |
| |
| private: |
| SkSTArray<4, GrGLSLFragmentProcessor*, true> fFPStack; |
| }; |
| |
| class ParallelIterEnd {}; |
| |
| /** |
| * Walks parallel trees of GrFragmentProcessor and associated GrGLSLFragmentProcessors. The |
| * GrGLSLFragmentProcessor used to initialize the iterator must have been created by calling |
| * GrFragmentProcessor::createGLSLInstance() on the passed GrFragmentProcessor. |
| */ |
| class ParallelIter { |
| public: |
| ParallelIter(const GrFragmentProcessor& fp, GrGLSLFragmentProcessor& glslFP); |
| |
| ParallelIter& operator++(); |
| |
| std::tuple<const GrFragmentProcessor&, GrGLSLFragmentProcessor&> operator*() const; |
| |
| bool operator==(const ParallelIterEnd& end) const; |
| |
| bool operator!=(const ParallelIterEnd& end) const { return !(*this == end); } |
| |
| private: |
| GrFragmentProcessor::CIter fpIter; |
| GrGLSLFragmentProcessor::Iter glslIter; |
| }; |
| |
| class ParallelRange { |
| public: |
| ParallelRange(const GrFragmentProcessor& fp, GrGLSLFragmentProcessor& glslFP); |
| |
| ParallelIter begin() { return {fInitialFP, fInitialGLSLFP}; } |
| |
| ParallelIterEnd end() { return {}; } |
| |
| private: |
| const GrFragmentProcessor& fInitialFP; |
| GrGLSLFragmentProcessor& fInitialGLSLFP; |
| }; |
| |
| protected: |
| /** A GrGLSLFragmentProcessor instance can be reused with any GrFragmentProcessor that produces |
| the same stage key; this function reads data from a GrFragmentProcessor and uploads any |
| uniform variables required by the shaders created in emitCode(). The GrFragmentProcessor |
| parameter is guaranteed to be of the same type that created this GrGLSLFragmentProcessor and |
| to have an identical processor key as the one that created this GrGLSLFragmentProcessor. */ |
| virtual void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) {} |
| |
| private: |
| // one per child; either not present or empty string if not yet emitted |
| SkTArray<SkString> fFunctionNames; |
| |
| SkTArray<std::unique_ptr<GrGLSLFragmentProcessor>, true> fChildProcessors; |
| |
| friend class GrFragmentProcessor; |
| }; |
| |
| #endif |