diff options
author | Robert Phillips <robertphillips@google.com> | 2017-04-21 12:24:00 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-04-21 17:12:17 +0000 |
commit | 9f5d4679e107ab83de635392798b3ddd62f48a12 (patch) | |
tree | 59c25bac71401ce32219d1e8c4362004a3d889a6 /src/gpu/GrFragmentProcessor.h | |
parent | 09419508669d203421f739b3105596655b7f0dcb (diff) |
Remove more headers from include/gpu
TBR=bsalomon@google.com
Change-Id: I93b28cfcb4d7b50c12e24ea81faab680bccce9ef
Reviewed-on: https://skia-review.googlesource.com/14036
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Diffstat (limited to 'src/gpu/GrFragmentProcessor.h')
-rw-r--r-- | src/gpu/GrFragmentProcessor.h | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/src/gpu/GrFragmentProcessor.h b/src/gpu/GrFragmentProcessor.h new file mode 100644 index 0000000000..00f2dbd9d8 --- /dev/null +++ b/src/gpu/GrFragmentProcessor.h @@ -0,0 +1,353 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrFragmentProcessor_DEFINED +#define GrFragmentProcessor_DEFINED + +#include "GrProcessor.h" + +class GrCoordTransform; +class GrGLSLFragmentProcessor; +class GrInvariantOutput; +class GrPipeline; +class GrProcessorKeyBuilder; +class GrShaderCaps; +class GrSwizzle; + +/** Provides custom fragment shader code. Fragment processors receive an input color (vec4f) and + produce an output color. They may reference textures and uniforms. They may use + GrCoordTransforms to receive a transformation of the local coordinates that map from local space + to the fragment being processed. + */ +class GrFragmentProcessor : public GrResourceIOProcessor, public GrProgramElement { +public: + /** + * In many instances (e.g. SkShader::asFragmentProcessor() implementations) it is desirable to + * only consider the input color's alpha. However, there is a competing desire to have reusable + * GrFragmentProcessor subclasses that can be used in other scenarios where the entire input + * color is considered. This function exists to filter the input color and pass it to a FP. It + * does so by returning a parent FP that multiplies the passed in FPs output by the parent's + * input alpha. The passed in FP will not receive an input color. + */ + static sk_sp<GrFragmentProcessor> MulOutputByInputAlpha(sk_sp<GrFragmentProcessor>); + + /** + * This assumes that the input color to the returned processor will be unpremul and that the + * passed processor (which becomes the returned processor's child) produces a premul output. + * The result of the returned processor is a premul of its input color modulated by the child + * processor's premul output. + */ + static sk_sp<GrFragmentProcessor> MakeInputPremulAndMulByOutput(sk_sp<GrFragmentProcessor>); + + /** + * Returns a parent fragment processor that adopts the passed fragment processor as a child. + * The parent will ignore its input color and instead feed the passed in color as input to the + * child. + */ + static sk_sp<GrFragmentProcessor> OverrideInput(sk_sp<GrFragmentProcessor>, GrColor4f); + + /** + * Returns a fragment processor that premuls the input before calling the passed in fragment + * processor. + */ + static sk_sp<GrFragmentProcessor> PremulInput(sk_sp<GrFragmentProcessor>); + + /** + * Returns a fragment processor that calls the passed in fragment processor, and then premuls + * the output. + */ + static sk_sp<GrFragmentProcessor> PremulOutput(sk_sp<GrFragmentProcessor>); + + /** + * Returns a fragment processor that calls the passed in fragment processor, and then unpremuls + * the output. + */ + static sk_sp<GrFragmentProcessor> UnpremulOutput(sk_sp<GrFragmentProcessor>); + + /** + * Returns a fragment processor that calls the passed in fragment processor, and then swizzles + * the output. + */ + static sk_sp<GrFragmentProcessor> SwizzleOutput(sk_sp<GrFragmentProcessor>, const GrSwizzle&); + + /** + * Returns a fragment processor that runs the passed in array of fragment processors in a + * series. The original input is passed to the first, the first's output is passed to the + * second, etc. The output of the returned processor is the output of the last processor of the + * series. + * + * The array elements with be moved. + */ + static sk_sp<GrFragmentProcessor> RunInSeries(sk_sp<GrFragmentProcessor>*, int cnt); + + ~GrFragmentProcessor() override; + + GrGLSLFragmentProcessor* createGLSLInstance() const; + + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { + this->onGetGLSLProcessorKey(caps, b); + for (int i = 0; i < fChildProcessors.count(); ++i) { + fChildProcessors[i]->getGLSLProcessorKey(caps, b); + } + } + + int numCoordTransforms() const { return fCoordTransforms.count(); } + + /** Returns the coordinate transformation at index. index must be valid according to + numTransforms(). */ + const GrCoordTransform& coordTransform(int index) const { return *fCoordTransforms[index]; } + + const SkTArray<const GrCoordTransform*, true>& coordTransforms() const { + return fCoordTransforms; + } + + int numChildProcessors() const { return fChildProcessors.count(); } + + const GrFragmentProcessor& childProcessor(int index) const { return *fChildProcessors[index]; } + + /** Do any of the coordtransforms for this processor require local coords? */ + bool usesLocalCoords() const { return SkToBool(fFlags & kUsesLocalCoords_Flag); } + + /** Does this FP need a vector to the nearest edge? */ + bool usesDistanceVectorField() const { + return SkToBool(fFlags & kUsesDistanceVectorField_Flag); + } + + /** + * A GrDrawOp may premultiply its antialiasing coverage into its GrGeometryProcessor's color + * output under the following scenario: + * * all the color fragment processors report true to this query, + * * all the coverage fragment processors report true to this query, + * * the blend mode arithmetic allows for it it. + * To be compatible a fragment processor's output must be a modulation of its input color or + * alpha with a computed premultiplied color or alpha that is in 0..1 range. The computed color + * or alpha that is modulated against the input cannot depend on the input's alpha. The computed + * value cannot depend on the input's color channels unless it unpremultiplies the input color + * channels by the input alpha. + */ + bool compatibleWithCoverageAsAlpha() const { + return SkToBool(fFlags & kCompatibleWithCoverageAsAlpha_OptimizationFlag); + } + + /** + * If this is true then all opaque input colors to the processor produce opaque output colors. + */ + bool preservesOpaqueInput() const { + return SkToBool(fFlags & kPreservesOpaqueInput_OptimizationFlag); + } + + /** + * Tests whether given a constant input color the processor produces a constant output color + * (for all fragments). If true outputColor will contain the constant color produces for + * inputColor. + */ + bool hasConstantOutputForConstantInput(GrColor4f inputColor, GrColor4f* outputColor) const { + if (fFlags & kConstantOutputForConstantInput_OptimizationFlag) { + *outputColor = this->constantOutputForConstantInput(inputColor); + return true; + } + return false; + } + bool hasConstantOutputForConstantInput() const { + return SkToBool(fFlags & kConstantOutputForConstantInput_OptimizationFlag); + } + + /** Returns true if this and other processor conservatively draw identically. It can only return + true when the two processor are of the same subclass (i.e. they return the same object from + from getFactory()). + + A return value of true from isEqual() should not be used to test whether the processor would + generate the same shader code. To test for identical code generation use getGLSLProcessorKey + */ + bool isEqual(const GrFragmentProcessor& that) const; + + /** + * Pre-order traversal of a FP hierarchy, or of the forest of FPs in a GrPipeline. In the latter + * case the tree rooted at each FP in the GrPipeline is visited successively. + */ + class Iter : public SkNoncopyable { + public: + explicit Iter(const GrFragmentProcessor* fp) { fFPStack.push_back(fp); } + explicit Iter(const GrPipeline& pipeline); + const GrFragmentProcessor* next(); + + private: + SkSTArray<4, const GrFragmentProcessor*, true> fFPStack; + }; + + /** + * Iterates over all the Ts owned by a GrFragmentProcessor and its children or over all the Ts + * owned by the forest of GrFragmentProcessors in a GrPipeline. FPs are visited in the same + * order as Iter and each of an FP's Ts are visited in order. + */ + template <typename T, typename BASE, + int (BASE::*COUNT)() const, + const T& (BASE::*GET)(int) const> + class FPItemIter : public SkNoncopyable { + public: + explicit FPItemIter(const GrFragmentProcessor* fp) + : fCurrFP(nullptr) + , fCTIdx(0) + , fFPIter(fp) { + fCurrFP = fFPIter.next(); + } + explicit FPItemIter(const GrPipeline& pipeline) + : fCurrFP(nullptr) + , fCTIdx(0) + , fFPIter(pipeline) { + fCurrFP = fFPIter.next(); + } + + const T* next() { + if (!fCurrFP) { + return nullptr; + } + while (fCTIdx == (fCurrFP->*COUNT)()) { + fCTIdx = 0; + fCurrFP = fFPIter.next(); + if (!fCurrFP) { + return nullptr; + } + } + return &(fCurrFP->*GET)(fCTIdx++); + } + + private: + const GrFragmentProcessor* fCurrFP; + int fCTIdx; + GrFragmentProcessor::Iter fFPIter; + }; + + using CoordTransformIter = FPItemIter<GrCoordTransform, + GrFragmentProcessor, + &GrFragmentProcessor::numCoordTransforms, + &GrFragmentProcessor::coordTransform>; + + using TextureAccessIter = FPItemIter<TextureSampler, + GrResourceIOProcessor, + &GrResourceIOProcessor::numTextureSamplers, + &GrResourceIOProcessor::textureSampler>; + +protected: + enum OptimizationFlags : uint32_t { + kNone_OptimizationFlags, + kCompatibleWithCoverageAsAlpha_OptimizationFlag = 0x1, + kPreservesOpaqueInput_OptimizationFlag = 0x2, + kConstantOutputForConstantInput_OptimizationFlag = 0x4, + kAll_OptimizationFlags = kCompatibleWithCoverageAsAlpha_OptimizationFlag | + kPreservesOpaqueInput_OptimizationFlag | + kConstantOutputForConstantInput_OptimizationFlag + }; + GR_DECL_BITFIELD_OPS_FRIENDS(OptimizationFlags) + + GrFragmentProcessor(OptimizationFlags optimizationFlags) : fFlags(optimizationFlags) { + SkASSERT((fFlags & ~kAll_OptimizationFlags) == 0); + } + + OptimizationFlags optimizationFlags() const { + return static_cast<OptimizationFlags>(kAll_OptimizationFlags & fFlags); + } + + /** + * This allows one subclass to access another subclass's implementation of + * constantOutputForConstantInput. It must only be called when + * hasConstantOutputForConstantInput() is known to be true. + */ + static GrColor4f ConstantOutputForConstantInput(const GrFragmentProcessor& fp, + GrColor4f input) { + SkASSERT(fp.hasConstantOutputForConstantInput()); + return fp.constantOutputForConstantInput(input); + } + + /** + * Fragment Processor subclasses call this from their constructor to register coordinate + * transformations. Coord transforms provide a mechanism for a processor to receive coordinates + * in their FS code. The matrix expresses a transformation from local space. For a given + * fragment the matrix will be applied to the local coordinate that maps to the fragment. + * + * When the transformation has perspective, the transformed coordinates will have + * 3 components. Otherwise they'll have 2. + * + * This must only be called from the constructor because GrProcessors are immutable. The + * processor subclass manages the lifetime of the transformations (this function only stores a + * pointer). The GrCoordTransform is typically a member field of the GrProcessor subclass. + * + * A processor subclass that has multiple methods of construction should always add its coord + * transforms in a consistent order. The non-virtual implementation of isEqual() automatically + * compares transforms and will assume they line up across the two processor instances. + */ + void addCoordTransform(const GrCoordTransform*); + + /** + * FragmentProcessor subclasses call this from their constructor to register any child + * FragmentProcessors they have. This must be called AFTER all texture accesses and coord + * transforms have been added. + * This is for processors whose shader code will be composed of nested processors whose output + * colors will be combined somehow to produce its output color. Registering these child + * processors will allow the ProgramBuilder to automatically handle their transformed coords and + * texture accesses and mangle their uniform and output color names. + */ + int registerChildProcessor(sk_sp<GrFragmentProcessor> child); + + /** + * Sub-classes should call this in their constructors if they need access to a distance + * vector field to the nearest edge + */ + void setWillUseDistanceVectorField() { fFlags |= kUsesDistanceVectorField_Flag; } + +private: + void addPendingIOs() const override { GrResourceIOProcessor::addPendingIOs(); } + void removeRefs() const override { GrResourceIOProcessor::removeRefs(); } + void pendingIOComplete() const override { GrResourceIOProcessor::pendingIOComplete(); } + + void notifyRefCntIsZero() const final; + + virtual GrColor4f constantOutputForConstantInput(GrColor4f /* inputColor */) const { + SkFAIL("Subclass must override this if advertising this optimization."); + return GrColor4f::TransparentBlack(); + } + + /** Returns a new instance of the appropriate *GL* implementation class + for the given GrFragmentProcessor; caller is responsible for deleting + the object. */ + virtual GrGLSLFragmentProcessor* onCreateGLSLInstance() const = 0; + + /** Implemented using GLFragmentProcessor::GenKey as described in this class's comment. */ + virtual void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const = 0; + + /** + * Subclass implements this to support isEqual(). It will only be called if it is known that + * the two processors are of the same subclass (i.e. they return the same object from + * getFactory()). The processor subclass should not compare its coord transforms as that will + * be performed automatically in the non-virtual isEqual(). + */ + virtual bool onIsEqual(const GrFragmentProcessor&) const = 0; + + bool hasSameTransforms(const GrFragmentProcessor&) const; + + enum PrivateFlags { + kFirstPrivateFlag = kAll_OptimizationFlags + 1, + kUsesLocalCoords_Flag = kFirstPrivateFlag, + kUsesDistanceVectorField_Flag = kFirstPrivateFlag << 1, + }; + + mutable uint32_t fFlags = 0; + + SkSTArray<4, const GrCoordTransform*, true> fCoordTransforms; + + /** + * This is not SkSTArray<1, sk_sp<GrFragmentProcessor>> because this class holds strong + * references until notifyRefCntIsZero and then it holds pending executions. + */ + SkSTArray<1, GrFragmentProcessor*, true> fChildProcessors; + + typedef GrProcessor INHERITED; +}; + +GR_MAKE_BITFIELD_OPS(GrFragmentProcessor::OptimizationFlags) + +#endif |