diff options
author | Florin Malita <fmalita@chromium.org> | 2017-11-08 15:46:42 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-11-09 15:15:54 +0000 |
commit | 14a8dd7255494c982673b2926e56a60e36a1a8a6 (patch) | |
tree | 70bda26bcd7b750855f1db9fe53e72a7e6313134 /src/shaders/gradients/SkGradientShaderPriv.h | |
parent | 5be933f01bf18e0869422d96840f6906ff42bfbb (diff) |
Simplify analytical GPU gradient impls
1) reformulate the gradient data as a series of interpolation intervals,
defined as tuples of (color_scale, color_bias) such that
color(t) = t * color_scale + color_bias
(this allows us to skip the relative_t computation and simply feed
tiled_t into a fast MAD)
2) then, the existing specializations can be generalized as
a) select an interpolation interval (possibly based on a threshold)
b) compute the interpolated color using the method in #1
3) simplify the hard-edge cases by using clamp intervals
(color_scale == 0) and relaxing the clamping step (allowing
tiled_t < 0 or tiled_t > 1, in order to hit the clamping intervals
during the selection step)
The existing specializations are converted as follows:
* kTwo_ColorType
-> single interpolation interval, normal clamping
* kThree_ColorType
-> two interpolation intervals, normal clamping, threshold == pos[1]
* kSingleHardStop_ColorType
-> two interpolation intervals, normal clamping, threshold == pos[1/2]
* kHardStopLeftEdged_ColorType
-> two interpolation intervals, clamping (-inf, 1], threshold == 0
* kHardStopRightEdged_ColorType
-> two interpolation intervals, clamping [0, +inf), threshold == 1
This reduces the SkSL overhead in a couple of ways:
* the clamp stage is sometimes reduced to min/max vs. full clamp()
* the color interpolation stage is just a MAD vs. full mix()
Change-Id: I65be84d131d56136ec5e946c2b3dba149a4473cf
Reviewed-on: https://skia-review.googlesource.com/68218
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'src/shaders/gradients/SkGradientShaderPriv.h')
-rw-r--r-- | src/shaders/gradients/SkGradientShaderPriv.h | 91 |
1 files changed, 28 insertions, 63 deletions
diff --git a/src/shaders/gradients/SkGradientShaderPriv.h b/src/shaders/gradients/SkGradientShaderPriv.h index 93c07094dc..9d82e82ef8 100644 --- a/src/shaders/gradients/SkGradientShaderPriv.h +++ b/src/shaders/gradients/SkGradientShaderPriv.h @@ -14,7 +14,7 @@ #include "SkAutoMalloc.h" #include "SkMatrix.h" #include "SkShaderBase.h" -#include "SkTDArray.h" +#include "SkTArray.h" #include "SkTemplates.h" class SkColorSpace; @@ -194,7 +194,7 @@ public: const SkGradientShaderBase* shader, const SkMatrix* matrix, SkShader::TileMode tileMode, - const SkColorSpace* dstColorSpace) + SkColorSpace* dstColorSpace) : fContext(context) , fShader(shader) , fMatrix(matrix) @@ -216,7 +216,7 @@ public: const SkGradientShaderBase* shader, const SkMatrix* matrix, GrSamplerState::WrapMode wrapMode, - const SkColorSpace* dstColorSpace) + SkColorSpace* dstColorSpace) : fContext(context) , fShader(shader) , fMatrix(matrix) @@ -227,7 +227,7 @@ public: const SkGradientShaderBase* fShader; const SkMatrix* fMatrix; GrSamplerState::WrapMode fWrapMode; - const SkColorSpace* fDstColorSpace; + SkColorSpace* fDstColorSpace; }; class GLSLProcessor; @@ -235,41 +235,22 @@ public: ~GrGradientEffect() override; bool useAtlas() const { return SkToBool(-1 != fRow); } - SkScalar getYCoord() const { return fYCoord; } - - enum ColorType { - kTwo_ColorType, - kThree_ColorType, // 0, t, 1 - kTexture_ColorType, - kSingleHardStop_ColorType, // 0, t, t, 1 - kHardStopLeftEdged_ColorType, // 0, 0, 1 - kHardStopRightEdged_ColorType, // 0, 1, 1 - }; - - ColorType getColorType() const { return fColorType; } - // Determines the type of gradient, one of: - // - Two-color - // - Symmetric three-color - // - Texture - // - Centered hard stop - // - Left-edged hard stop - // - Right-edged hard stop - ColorType determineColorType(const SkGradientShaderBase& shader); + // Controls the implementation strategy for this effect. + // NB: all entries need to be reflected in the key. + enum class InterpolationStrategy : uint8_t { + kSingle, // interpolation in a single domain [0,1] + kThreshold, // interpolation in two domains [0,T) [T,1], with normal clamping + kThresholdClamp0, // same as kThreshold, but clamped only on the left edge + kThresholdClamp1, // same as kThreshold, but clamped only on the right edge + kTexture, // texture-based fallback + }; enum PremulType { kBeforeInterp_PremulType, kAfterInterp_PremulType, }; - PremulType getPremulType() const { return fPremulType; } - - const GrColor4f* getColors4f(int pos) const { - SkASSERT(fColorType != kTexture_ColorType); - SkASSERT(pos < fColors4f.count()); - return &fColors4f[pos]; - } - protected: GrGradientEffect(ClassID classID, const CreateArgs&, bool isOpaque); explicit GrGradientEffect(const GrGradientEffect&); // facilitates clone() implementations @@ -287,7 +268,7 @@ protected: // With analytic gradients, we pre-convert the stops to the destination color space, so no // xform is needed. With texture-based gradients, we leave the data in the source color // space (to avoid clamping if we can't use F16)... Add an extra FP to do the xform. - if (kTexture_ColorType == gradientFP->getColorType()) { + if (gradientFP->fStrategy == InterpolationStrategy::kTexture) { // Our texture is always either F16 or sRGB, so the data is "linear" in the shader. // Create our xform assuming float inputs, which will suppress any extra sRGB work. // We do support having a transfer function on the color space of the stops, so @@ -331,15 +312,18 @@ protected: /** Checks whether the constructor failed to fully initialize the processor. */ bool isValid() const { - return fColorType != kTexture_ColorType || fTextureSampler.isInitialized(); + return fStrategy != InterpolationStrategy::kTexture || fTextureSampler.isInitialized(); } private: + void addInterval(const SkGradientShaderBase&, size_t idx0, size_t idx1, SkColorSpace*); + static OptimizationFlags OptFlags(bool isOpaque); - SkTDArray<GrColor4f> fColors4f; + // Interpolation intervals, encoded as 4f tuples of (scale, bias) + // such that color(t) = t * scale + bias. + SkSTArray<4, GrColor4f, true> fIntervals; - SkTDArray<SkScalar> fPositions; GrSamplerState::WrapMode fWrapMode; GrCoordTransform fCoordTransform; @@ -348,9 +332,12 @@ private: GrTextureStripAtlas* fAtlas; int fRow; bool fIsOpaque; - ColorType fColorType; - PremulType fPremulType; // This is already baked into the table for texture gradients, and - // only changes behavior for gradients that don't use a texture. + + InterpolationStrategy fStrategy; + SkScalar fThreshold; // used for InterpolationStrategy::kThreshold + PremulType fPremulType; // This is already baked into the table for texture + // gradients, and only changes behavior for gradients + // that don't use a texture. typedef GrFragmentProcessor INHERITED; }; @@ -395,31 +382,9 @@ private: const char* outputColor, const char* inputColor); - enum { - // First bit for premul before/after interpolation - kPremulBeforeInterpKey = 1, - - // Next three bits for 2/3 color type or different special - // hard stop cases ('none' means using texture atlas) - kTwoColorKey = 2, - kThreeColorKey = 4, - - kHardStopCenteredKey = 6, - kHardStopZeroZeroOneKey = 8, - kHardStopZeroOneOneKey = 10, - - // Next two bits for tile mode - kClampTileMode = 16, - kRepeatTileMode = 32, - kMirrorTileMode = 48, - - // Lower six bits for premul, 2/3 color type, and tile mode - kReservedBits = 6, - }; - SkScalar fCachedYCoord; - GrGLSLProgramDataManager::UniformHandle fColorsUni; - GrGLSLProgramDataManager::UniformHandle fExtraStopT; + GrGLSLProgramDataManager::UniformHandle fIntervalsUni; + GrGLSLProgramDataManager::UniformHandle fThresholdUni; GrGLSLProgramDataManager::UniformHandle fFSYUni; typedef GrGLSLFragmentProcessor INHERITED; |