Revert "Revert "Start of rewrite of GrFragmentProcessor optimizations.""
authorBrian Salomon <bsalomon@google.com>
Fri, 27 Jan 2017 15:59:27 +0000 (10:59 -0500)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Fri, 27 Jan 2017 16:43:38 +0000 (16:43 +0000)
This reverts commit 052fd5158f7f85e478a9f87c45fecaacf7d0f5f3.

Disables the test (of unused code) until platform-specific issues are addressed.

Change-Id: I7aa23a07954fccf382aa07d28afcbffb0bebcd6d
Reviewed-on: https://skia-review.googlesource.com/7656
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>

58 files changed:
experimental/SkPerlinNoiseShader2/SkPerlinNoiseShader2.cpp
include/gpu/GrColor.h
include/gpu/GrFragmentProcessor.h
include/gpu/GrProcessorUnitTest.h
include/gpu/GrTypes.h
include/gpu/effects/GrConstColorProcessor.h
src/core/SkColorMatrixFilterRowMajor255.cpp
src/core/SkLightingShader.cpp
src/core/SkNormalBevelSource.cpp
src/core/SkNormalFlatSource.cpp
src/core/SkNormalMapSource.cpp
src/effects/GrAlphaThresholdFragmentProcessor.cpp
src/effects/GrAlphaThresholdFragmentProcessor.h
src/effects/GrCircleBlurFragmentProcessor.cpp
src/effects/SkArithmeticImageFilter.cpp
src/effects/SkBlurMaskFilter.cpp
src/effects/SkDisplacementMapEffect.cpp
src/effects/SkGaussianEdgeShader.cpp
src/effects/SkLightingImageFilter.cpp
src/effects/SkLumaColorFilter.cpp
src/effects/SkMagnifierImageFilter.cpp
src/effects/SkMorphologyImageFilter.cpp
src/effects/SkOverdrawColorFilter.cpp
src/effects/SkPerlinNoiseShader.cpp
src/effects/SkRRectsGaussianEdgeMaskFilter.cpp
src/effects/SkTableColorFilter.cpp
src/effects/gradients/SkGradientShader.cpp
src/effects/gradients/SkGradientShaderPriv.h
src/effects/gradients/SkLinearGradient.cpp
src/effects/gradients/SkRadialGradient.cpp
src/effects/gradients/SkSweepGradient.cpp
src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp
src/effects/shadows/SkAmbientShadowMaskFilter.cpp
src/gpu/GrFragmentProcessor.cpp
src/gpu/SkGrPriv.h
src/gpu/effects/Gr1DKernelEffect.h
src/gpu/effects/GrBicubicEffect.cpp
src/gpu/effects/GrConfigConversionEffect.cpp
src/gpu/effects/GrConfigConversionEffect.h
src/gpu/effects/GrConstColorProcessor.cpp
src/gpu/effects/GrConvexPolyEffect.cpp
src/gpu/effects/GrDitherEffect.cpp
src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp
src/gpu/effects/GrMatrixConvolutionEffect.cpp
src/gpu/effects/GrOvalEffect.cpp
src/gpu/effects/GrRRectEffect.cpp
src/gpu/effects/GrSRGBEffect.cpp
src/gpu/effects/GrSRGBEffect.h
src/gpu/effects/GrSimpleTextureEffect.h
src/gpu/effects/GrSingleTextureEffect.cpp
src/gpu/effects/GrSingleTextureEffect.h
src/gpu/effects/GrTextureDomain.cpp
src/gpu/effects/GrTextureDomain.h
src/gpu/effects/GrXfermodeFragmentProcessor.cpp
src/gpu/effects/GrYUVEffect.cpp
tests/GLProgramsTest.cpp
tests/ImageStorageTest.cpp
tests/ProcessorTest.cpp

index de5cfab039a7bcd43f53bc55bfb9fe8dba65a24c..c9fca4bd555bad3afed614299b02c60fb6746979 100644 (file)
@@ -675,17 +675,17 @@ private:
         inout->setToUnknown();
     }
 
-    GrPerlinNoise2Effect(SkPerlinNoiseShader2::Type type,
-                        int numOctaves, bool stitchTiles,
-                        SkPerlinNoiseShader2::PaintingData* paintingData,
-                        GrTexture* permutationsTexture, GrTexture* noiseTexture,
-                        const SkMatrix& matrix)
-      : fType(type)
-      , fNumOctaves(numOctaves)
-      , fStitchTiles(stitchTiles)
-      , fPermutationsSampler(permutationsTexture)
-      , fNoiseSampler(noiseTexture)
-      , fPaintingData(paintingData) {
+    GrPerlinNoise2Effect(SkPerlinNoiseShader2::Type type, int numOctaves, bool stitchTiles,
+                         SkPerlinNoiseShader2::PaintingData* paintingData,
+                         GrTexture* permutationsTexture, GrTexture* noiseTexture,
+                         const SkMatrix& matrix)
+            : INHERITED(kNone_OptimizationFlags)
+            , fType(type)
+            , fNumOctaves(numOctaves)
+            , fStitchTiles(stitchTiles)
+            , fPermutationsSampler(permutationsTexture)
+            , fNoiseSampler(noiseTexture)
+            , fPaintingData(paintingData) {
         this->initClassID<GrPerlinNoise2Effect>();
         this->addTextureSampler(&fPermutationsSampler);
         this->addTextureSampler(&fNoiseSampler);
@@ -703,7 +703,6 @@ private:
     TextureSampler                      fNoiseSampler;
     SkPerlinNoiseShader2::PaintingData* fPaintingData;
 
-private:
     typedef GrFragmentProcessor INHERITED;
 };
 
@@ -1087,15 +1086,16 @@ private:
         inout->setToUnknown();
     }
 
-    GrImprovedPerlinNoiseEffect(int octaves, SkScalar z, 
+    GrImprovedPerlinNoiseEffect(int octaves, SkScalar z,
                                 SkPerlinNoiseShader2::PaintingData* paintingData,
                                 GrTexture* permutationsTexture, GrTexture* gradientTexture,
                                 const SkMatrix& matrix)
-      : fOctaves(octaves)
-      , fZ(z)
-      , fPermutationsSampler(permutationsTexture)
-      , fGradientSampler(gradientTexture)
-      , fPaintingData(paintingData) {
+            : INHERITED(kNone_OptimizationFlags)
+            , fOctaves(octaves)
+            , fZ(z)
+            , fPermutationsSampler(permutationsTexture)
+            , fGradientSampler(gradientTexture)
+            , fPaintingData(paintingData) {
         this->initClassID<GrImprovedPerlinNoiseEffect>();
         this->addTextureSampler(&fPermutationsSampler);
         this->addTextureSampler(&fGradientSampler);
@@ -1112,7 +1112,6 @@ private:
     TextureSampler                      fGradientSampler;
     SkPerlinNoiseShader2::PaintingData* fPaintingData;
 
-private:
     typedef GrFragmentProcessor INHERITED;
 };
 
index cebceea2d0da83272bd523cabb5d2f7365218290..64368b9ef9e5ce7aa6c01861998e49e8b69c1379 100644 (file)
@@ -213,6 +213,17 @@ struct GrColor4f {
         return GrColor4f(color.fR, color.fG, color.fB, color.fA);
     }
 
+    GrColor4f modulate(const GrColor4f& x) const {
+        return GrColor4f(fRGBA[0] * x.fRGBA[0],
+                         fRGBA[1] * x.fRGBA[1],
+                         fRGBA[2] * x.fRGBA[2],
+                         fRGBA[3] * x.fRGBA[3]);
+    }
+
+    GrColor4f mulByScalar(float x) const {
+        return GrColor4f(fRGBA[0] * x, fRGBA[1] * x, fRGBA[2] * x, fRGBA[3] * x);
+    }
+
     bool operator==(const GrColor4f& other) const {
         return
             fRGBA[0] == other.fRGBA[0] &&
@@ -240,6 +251,10 @@ struct GrColor4f {
         return GrColor4f(fRGBA[0], fRGBA[1], fRGBA[2], 1.0f);
     }
 
+    bool isOpaque() const {
+        return fRGBA[3] >= 1.f;  // just in case precision causes a superopaque value.
+    }
+
     GrColor4f premul() const {
         float a = fRGBA[3];
         return GrColor4f(fRGBA[0] * a, fRGBA[1] * a, fRGBA[2] * a, a);
index 49ccceabae60289cb8c9e74cca5c8b15735a3e7c..0d41a267de2e78b6e2049dc93caab1b8ca6d504e 100644 (file)
@@ -64,11 +64,6 @@ public:
      */
     static sk_sp<GrFragmentProcessor> RunInSeries(sk_sp<GrFragmentProcessor>*, int cnt);
 
-    GrFragmentProcessor()
-        : INHERITED()
-        , fUsesDistanceVectorField(false)
-        , fUsesLocalCoords(false) {}
-
     ~GrFragmentProcessor() override;
 
     GrGLSLFragmentProcessor* createGLSLInstance() const;
@@ -95,10 +90,42 @@ public:
     const GrFragmentProcessor& childProcessor(int index) const { return *fChildProcessors[index]; }
 
     /** Do any of the coordtransforms for this processor require local coords? */
-    bool usesLocalCoords() const { return fUsesLocalCoords; }
+    bool usesLocalCoords() const { return SkToBool(fFlags & kUsesLocalCoords_Flag); }
 
     /** Does this FP need a vector to the nearest edge? */
-    bool usesDistanceVectorField() const { return fUsesDistanceVectorField; }
+    bool usesDistanceVectorField() const {
+        return SkToBool(fFlags & kUsesDistanceVectorField_Flag);
+    }
+
+    /**
+     * True if the processor's output is a modulation of its input color or alpha with a computed
+     * color or alpha in the 0..1 range. If true and the blend mode allows it we may fold coverage
+     * into the first color fragment processor's input.
+     */
+    bool modulatesInput() const { return SkToBool(fFlags & kModulatesInput_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
@@ -189,6 +216,36 @@ public:
                                          &GrProcessor::textureSampler>;
 
 protected:
+    enum OptimizationFlags : uint32_t {
+        kNone_OptimizationFlags,
+        kModulatesInput_OptimizationFlag = 0x1,
+        kPreservesOpaqueInput_OptimizationFlag = 0x2,
+        kConstantOutputForConstantInput_OptimizationFlag = 0x4,
+        kAll_OptimizationFlags = kModulatesInput_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
@@ -227,14 +284,20 @@ protected:
      */
     virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const = 0;
 
-    /* Sub-classes should set this to true in their constructors if they need access to a distance
+    /**
+     * Sub-classes should call this in their constructors if they need access to a distance
      * vector field to the nearest edge
      */
-    bool fUsesDistanceVectorField;
+    void setWillUseDistanceVectorField() { fFlags |= kUsesDistanceVectorField_Flag; }
 
 private:
     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. */
@@ -253,7 +316,13 @@ private:
 
     bool hasSameTransforms(const GrFragmentProcessor&) const;
 
-    bool                                       fUsesLocalCoords;
+    enum PrivateFlags {
+        kFirstPrivateFlag = kAll_OptimizationFlags + 1,
+        kUsesLocalCoords_Flag = kFirstPrivateFlag,
+        kUsesDistanceVectorField_Flag = kFirstPrivateFlag << 1,
+    };
+
+    mutable uint32_t fFlags = 0;
 
     SkSTArray<4, const GrCoordTransform*, true> fCoordTransforms;
 
@@ -261,9 +330,11 @@ private:
      * 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;
+    SkSTArray<1, GrFragmentProcessor*, true> fChildProcessors;
 
     typedef GrProcessor INHERITED;
 };
 
+GR_MAKE_BITFIELD_OPS(GrFragmentProcessor::OptimizationFlags)
+
 #endif
index 7cec307f28584d00a4fcef12b1e876f5e94db6c0..a56db8188b28a6abe01a8683f62af175575dedd1 100644 (file)
@@ -46,10 +46,8 @@ struct GrProcessorTestData {
     GrProcessorTestData(SkRandom* random,
                         GrContext* context,
                         const GrRenderTargetContext* renderTargetContext,
-                        GrTexture* textures[2])
-        : fRandom(random)
-        , fContext(context)
-        , fRenderTargetContext(renderTargetContext) {
+                        GrTexture* const textures[2])
+            : fRandom(random), fContext(context), fRenderTargetContext(renderTargetContext) {
         fTextures[0] = textures[0];
         fTextures[1] = textures[1];
 
index b3f1c19ebb7bec70ff734cb484c4f53bcb2612ab..8da7f71e6288f232492c09ce89c6d024d2a4f4b6 100644 (file)
  * bitfield.
  */
 #define GR_MAKE_BITFIELD_OPS(X) \
-    inline X operator | (X a, X b) { \
+    inline X operator |(X a, X b) { \
         return (X) (+a | +b); \
     } \
-    inline X& operator |= (X& a, X b) { \
+    inline X& operator |=(X& a, X b) { \
         return (a = a | b); \
     } \
-    \
-    inline X operator & (X a, X b) { \
+    inline X operator &(X a, X b) { \
         return (X) (+a & +b); \
     } \
+    inline X& operator &=(X& a, X b) { \
+        return (a = a & b); \
+    } \
     template <typename T> \
-    inline X operator & (T a, X b) { \
+    inline X operator &(T a, X b) { \
         return (X) (+a & +b); \
     } \
     template <typename T> \
-    inline X operator & (X a, T b) { \
+    inline X operator &(X a, T b) { \
         return (X) (+a & +b); \
     } \
 
 #define GR_DECL_BITFIELD_OPS_FRIENDS(X) \
-    friend X operator | (X a, X b); \
-    friend X& operator |= (X& a, X b); \
+    friend X operator |(X a, X b); \
+    friend X& operator |=(X& a, X b); \
     \
-    friend X operator & (X a, X b); \
+    friend X operator &(X a, X b); \
+    friend X& operator &=(X& a, X b); \
     \
     template <typename T> \
-    friend X operator & (T a, X b); \
+    friend X operator &(T a, X b); \
     \
     template <typename T> \
-    friend X operator & (X a, T b); \
+    friend X operator &(X a, T b); \
 
 /**
  * Defines bitwise operators that make it possible to use an enum class as a
  * very basic bitfield.
  */
 #define GR_MAKE_BITFIELD_CLASS_OPS(X) \
-    inline X operator | (X a, X b) { \
+    inline X operator |(X a, X b) { \
         return (X) ((int)a | (int)b); \
     } \
-    inline X& operator |= (X& a, X b) { \
+    inline X& operator |=(X& a, X b) { \
         return (a = a | b); \
     } \
-    inline bool operator & (X a, X b) { \
+    inline bool operator &(X a, X b) { \
         return SkToBool((int)a & (int)b); \
     }
 
 #define GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(X) \
-    friend X operator | (X a, X b); \
-    friend X& operator |= (X& a, X b); \
-    friend bool operator & (X a, X b);
+    friend X operator |(X a, X b); \
+    friend X& operator |=(X& a, X b); \
+    friend bool operator &(X a, X b);
 
 ////////////////////////////////////////////////////////////////////////////////
 
index 73ea9eb196cb1ed4fd358acff641761412f2b2f2..b32421bd5513f47664f6bbf29568600316f86588 100644 (file)
@@ -43,7 +43,19 @@ public:
     InputMode inputMode() const { return fMode; }
 
 private:
-    GrConstColorProcessor(GrColor4f color, InputMode mode) : fColor(color), fMode(mode) {
+    static OptimizationFlags OptFlags(GrColor4f color, InputMode mode) {
+        OptimizationFlags flags = kConstantOutputForConstantInput_OptimizationFlag;
+        if (mode != kIgnore_InputMode) {
+            flags |= kModulatesInput_OptimizationFlag;
+        }
+        if (color.isOpaque()) {
+            flags |= kPreservesOpaqueInput_OptimizationFlag;
+        }
+        return flags;
+    }
+
+    GrConstColorProcessor(GrColor4f color, InputMode mode)
+            : INHERITED(OptFlags(color, mode)), fColor(color), fMode(mode) {
         this->initClassID<GrConstColorProcessor>();
     }
 
@@ -54,6 +66,7 @@ private:
     bool onIsEqual(const GrFragmentProcessor&) const override;
 
     void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
+    GrColor4f constantOutputForConstantInput(GrColor4f input) const override;
 
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
 
index 2bcc79e4ccdabef43ee1ee1a2ed69249f0bdb080..167fd21b38ee6619fe9c9fb5543d202c1cdfad22 100644 (file)
@@ -345,9 +345,10 @@ public:
 
         typedef GrGLSLFragmentProcessor INHERITED;
     };
-
 private:
-    ColorMatrixEffect(const SkScalar matrix[20]) {
+    // We could implement the constant input->constant output optimization but haven't. Other
+    // optimizations would be matrix-dependent.
+    ColorMatrixEffect(const SkScalar matrix[20]) : INHERITED(kNone_OptimizationFlags) {
         memcpy(fMatrix, matrix, sizeof(SkScalar) * 20);
         this->initClassID<ColorMatrixEffect>();
     }
index bb2828a13e17c7be7b861686455fa477a074d4a4..4ed00576825fafbcfa1f963e62e6888682fc9ed9 100644 (file)
@@ -117,8 +117,8 @@ private:
 // premul'd.
 class LightingFP : public GrFragmentProcessor {
 public:
-    LightingFP(sk_sp<GrFragmentProcessor> normalFP, sk_sp<SkLights> lights) {
-
+    LightingFP(sk_sp<GrFragmentProcessor> normalFP, sk_sp<SkLights> lights)
+            : INHERITED(kPreservesOpaqueInput_OptimizationFlag) {
         // fuse all ambient lights into a single one
         fAmbientColor = lights->ambientLightColor();
         for (int i = 0; i < lights->numLights(); ++i) {
@@ -263,6 +263,8 @@ private:
 
     SkTArray<SkLights::Light> fDirectionalLights;
     SkColor3f                 fAmbientColor;
+
+    typedef GrFragmentProcessor INHERITED;
 };
 
 ////////////////////////////////////////////////////////////////////////////
index bcdb999c15432895612c3b9a93d5aa29803348e6..5d49253b011e470f645f2ac1e15b9c7291a51e1d 100644 (file)
 class NormalBevelFP : public GrFragmentProcessor {
 public:
     NormalBevelFP(SkNormalSource::BevelType bevelType, SkScalar bevelWidth, SkScalar bevelHeight)
-        : fBevelType(bevelType)
-        , fBevelWidth(bevelWidth)
-        , fBevelHeight(bevelHeight) {
+            : INHERITED(kNone_OptimizationFlags)
+            , fBevelType(bevelType)
+            , fBevelWidth(bevelWidth)
+            , fBevelHeight(bevelHeight) {
         this->initClassID<NormalBevelFP>();
 
-        fUsesDistanceVectorField = true;
+        this->setWillUseDistanceVectorField();
     }
 
     class GLSLNormalBevelFP : public GLSLNormalFP {
@@ -239,6 +240,8 @@ private:
     SkNormalSource::BevelType fBevelType;
     SkScalar fBevelWidth;
     SkScalar fBevelHeight;
+
+    typedef GrFragmentProcessor INHERITED;
 };
 
 sk_sp<GrFragmentProcessor> SkNormalBevelSourceImpl::asFragmentProcessor(
index 4fca57c1f385c9ed7eaabbbad644e3b9a7b8d24d..b4ed9772851af609f5cff4a7d7026912736c943c 100644 (file)
@@ -20,7 +20,7 @@
 
 class NormalFlatFP : public GrFragmentProcessor {
 public:
-    NormalFlatFP() {
+    NormalFlatFP() : INHERITED(kConstantOutputForConstantInput_OptimizationFlag) {
         this->initClassID<NormalFlatFP>();
     }
 
@@ -43,20 +43,23 @@ public:
                            const GrProcessor& proc) override {}
     };
 
+    const char* name() const override { return "NormalFlatFP"; }
+
+private:
     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
         GLSLNormalFlatFP::GenKey(*this, caps, b);
     }
-
-    const char* name() const override { return "NormalFlatFP"; }
-
     void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
         inout->setToUnknown();
     }
-
-private:
+    GrColor4f constantOutputForConstantInput(GrColor4f) const override {
+        return GrColor4f(0, 0, 1, 0);
+    }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalFlatFP; }
 
     bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
+
+    typedef GrFragmentProcessor INHERITED;
 };
 
 sk_sp<GrFragmentProcessor> SkNormalFlatSourceImpl::asFragmentProcessor(
index 71e5565ac8d0e2d8c19b7474e29de5e0c0468103..3a9f9cf76fb54b9f0050df6eee222f0a064acbd9 100644 (file)
@@ -26,7 +26,7 @@
 class NormalMapFP : public GrFragmentProcessor {
 public:
     NormalMapFP(sk_sp<GrFragmentProcessor> mapFP, const SkMatrix& invCTM)
-        : fInvCTM(invCTM) {
+            : INHERITED(kNone_OptimizationFlags), fInvCTM(invCTM) {
         this->registerChildProcessor(mapFP);
 
         this->initClassID<NormalMapFP>();
@@ -117,6 +117,8 @@ private:
     }
 
     SkMatrix fInvCTM;
+
+    typedef GrFragmentProcessor INHERITED;
 };
 
 sk_sp<GrFragmentProcessor> SkNormalMapSourceImpl::asFragmentProcessor(
index a2596074443c71c7ec6f1cdb64041cce68f9edee..8f9e45dc2b6e53a6ac57b375c2a7051eb0832e5c 100644 (file)
@@ -32,6 +32,14 @@ sk_sp<GrFragmentProcessor> GrAlphaThresholdFragmentProcessor::Make(
                                                                 bounds));
 }
 
+inline GrFragmentProcessor::OptimizationFlags GrAlphaThresholdFragmentProcessor::OptFlags(float outerThreshold) {
+    if (outerThreshold >= 1.f) {
+        return kPreservesOpaqueInput_OptimizationFlag | kModulatesInput_OptimizationFlag;
+    } else {
+        return kModulatesInput_OptimizationFlag;
+    }
+}
+
 GrAlphaThresholdFragmentProcessor::GrAlphaThresholdFragmentProcessor(
                                                            GrTexture* texture,
                                                            sk_sp<GrColorSpaceXform> colorSpaceXform,
@@ -39,16 +47,17 @@ GrAlphaThresholdFragmentProcessor::GrAlphaThresholdFragmentProcessor(
                                                            float innerThreshold,
                                                            float outerThreshold,
                                                            const SkIRect& bounds)
-    : fInnerThreshold(innerThreshold)
-    , fOuterThreshold(outerThreshold)
-    , fImageCoordTransform(SkMatrix::I(), texture, GrSamplerParams::kNone_FilterMode)
-    , fImageTextureSampler(texture)
-    , fColorSpaceXform(std::move(colorSpaceXform))
-    , fMaskCoordTransform(SkMatrix::MakeTrans(SkIntToScalar(-bounds.x()),
-                                              SkIntToScalar(-bounds.y())),
-                          maskTexture,
-                          GrSamplerParams::kNone_FilterMode)
-    , fMaskTextureSampler(maskTexture) {
+        : INHERITED(OptFlags(outerThreshold))
+        , fInnerThreshold(innerThreshold)
+        , fOuterThreshold(outerThreshold)
+        , fImageCoordTransform(SkMatrix::I(), texture, GrSamplerParams::kNone_FilterMode)
+        , fImageTextureSampler(texture)
+        , fColorSpaceXform(std::move(colorSpaceXform))
+        , fMaskCoordTransform(
+                  SkMatrix::MakeTrans(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y())),
+                  maskTexture,
+                  GrSamplerParams::kNone_FilterMode)
+        , fMaskTextureSampler(maskTexture) {
     this->initClassID<GrAlphaThresholdFragmentProcessor>();
     this->addCoordTransform(&fImageCoordTransform);
     this->addTextureSampler(&fImageTextureSampler);
index f7a2491aee584eb5650534f6d592c698c94dd047..f2c14c64bc2268a40bc78b4d742abf3bccece77a 100644 (file)
@@ -35,6 +35,8 @@ public:
     GrColorSpaceXform* colorSpaceXform() const { return fColorSpaceXform.get(); }
 
 private:
+    static OptimizationFlags OptFlags(float outerThreshold);
+
     GrAlphaThresholdFragmentProcessor(GrTexture* texture,
                                       sk_sp<GrColorSpaceXform> colorSpaceXform,
                                       GrTexture* maskTexture,
index d3eb325b34da02dc300032ba67db709c6bc481a1..91d17d6e6c5fb7ae488c5200449549fa88e5a169 100644 (file)
@@ -88,10 +88,11 @@ GrCircleBlurFragmentProcessor::GrCircleBlurFragmentProcessor(const SkRect& circl
                                                              float textureRadius,
                                                              float solidRadius,
                                                              GrTexture* blurProfile)
-    : fCircle(circle)
-    , fSolidRadius(solidRadius)
-    , fTextureRadius(textureRadius)
-    , fBlurProfileSampler(blurProfile, GrSamplerParams::kBilerp_FilterMode) {
+        : INHERITED(kModulatesInput_OptimizationFlag)
+        , fCircle(circle)
+        , fSolidRadius(solidRadius)
+        , fTextureRadius(textureRadius)
+        , fBlurProfileSampler(blurProfile, GrSamplerParams::kBilerp_FilterMode) {
     this->initClassID<GrCircleBlurFragmentProcessor>();
     this->addTextureSampler(&fBlurProfileSampler);
 }
index 8d80984bdf6f47b4a1e228dfc3e7f3eb23651cc9..a9a232554fc9051dd25401ae0870c0e616f00d8d 100644 (file)
@@ -290,9 +290,15 @@ private:
         inout->setToUnknown();
     }
 
+    // This could implement the const input -> const output optimization but it's unlikely to help.
     ArithmeticFP(float k1, float k2, float k3, float k4, bool enforcePMColor,
                  sk_sp<GrFragmentProcessor> dst)
-            : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) {
+            : INHERITED(kNone_OptimizationFlags)
+            , fK1(k1)
+            , fK2(k2)
+            , fK3(k3)
+            , fK4(k4)
+            , fEnforcePMColor(enforcePMColor) {
         this->initClassID<ArithmeticFP>();
         SkASSERT(dst);
         SkDEBUGCODE(int dstIndex =) this->registerChildProcessor(std::move(dst));
index b53fc41dead1015bfb96f700e6bfdabac15cbe21..bf544077df4700906e4e6572b13bfefb3f08b5f5 100644 (file)
@@ -974,12 +974,13 @@ GrTexture* GrRectBlurEffect::CreateBlurProfileTexture(GrTextureProvider* texture
     return blurProfile;
 }
 
-GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma, GrTexture *blurProfile,
+GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma, GrTextureblurProfile,
                                    GrSLPrecision precision)
-    : fRect(rect)
-    , fSigma(sigma)
-    , fBlurProfileSampler(blurProfile)
-    , fPrecision(precision) {
+        : INHERITED(kModulatesInput_OptimizationFlag)
+        , fRect(rect)
+        , fSigma(sigma)
+        , fBlurProfileSampler(blurProfile)
+        , fPrecision(precision) {
     this->initClassID<GrRectBlurEffect>();
     this->addTextureSampler(&fBlurProfileSampler);
 }
@@ -1206,10 +1207,11 @@ void GrRRectBlurEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const
     inout->mulByUnknownSingleComponent();
 }
 
-GrRRectBlurEffect::GrRRectBlurEffect(float sigma, const SkRRect& rrect, GrTexture *ninePatchTexture)
-    : fRRect(rrect),
-      fSigma(sigma),
-      fNinePatchSampler(ninePatchTexture) {
+GrRRectBlurEffect::GrRRectBlurEffect(float sigma, const SkRRect& rrect, GrTexture* ninePatchTexture)
+        : INHERITED(kModulatesInput_OptimizationFlag)
+        , fRRect(rrect)
+        , fSigma(sigma)
+        , fNinePatchSampler(ninePatchTexture) {
     this->initClassID<GrRRectBlurEffect>();
     this->addTextureSampler(&fNinePatchSampler);
 }
index d838e1e3472421e0d93b75e09d37142490f25fcb..cee47f4f3f20a3a8304aa17b5981948dc355844b 100644 (file)
@@ -487,24 +487,26 @@ void GrDisplacementMapEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
 }
 
 GrDisplacementMapEffect::GrDisplacementMapEffect(
-                             SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
-                             SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
-                             const SkVector& scale,
-                             GrTexture* displacement,
-                             const SkMatrix& offsetMatrix,
-                             GrTexture* color,
-                             sk_sp<GrColorSpaceXform> colorSpaceXform,
-                             const SkISize& colorDimensions)
-    : fDisplacementTransform(offsetMatrix, displacement, GrSamplerParams::kNone_FilterMode)
-    , fDisplacementSampler(displacement)
-    , fColorTransform(color, GrSamplerParams::kNone_FilterMode)
-    , fDomain(color, GrTextureDomain::MakeTexelDomain(SkIRect::MakeSize(colorDimensions)),
-              GrTextureDomain::kDecal_Mode)
-    , fColorSampler(color)
-    , fColorSpaceXform(std::move(colorSpaceXform))
-    , fXChannelSelector(xChannelSelector)
-    , fYChannelSelector(yChannelSelector)
-    , fScale(scale) {
+        SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
+        SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
+        const SkVector& scale,
+        GrTexture* displacement,
+        const SkMatrix& offsetMatrix,
+        GrTexture* color,
+        sk_sp<GrColorSpaceXform> colorSpaceXform,
+        const SkISize& colorDimensions)
+        : INHERITED(GrPixelConfigIsOpaque(color->config()) ? kPreservesOpaqueInput_OptimizationFlag
+                                                           : kNone_OptimizationFlags)
+        , fDisplacementTransform(offsetMatrix, displacement, GrSamplerParams::kNone_FilterMode)
+        , fDisplacementSampler(displacement)
+        , fColorTransform(color, GrSamplerParams::kNone_FilterMode)
+        , fDomain(color, GrTextureDomain::MakeTexelDomain(SkIRect::MakeSize(colorDimensions)),
+                  GrTextureDomain::kDecal_Mode)
+        , fColorSampler(color)
+        , fColorSpaceXform(std::move(colorSpaceXform))
+        , fXChannelSelector(xChannelSelector)
+        , fYChannelSelector(yChannelSelector)
+        , fScale(scale) {
     this->initClassID<GrDisplacementMapEffect>();
     this->addCoordTransform(&fDisplacementTransform);
     this->addTextureSampler(&fDisplacementSampler);
index 7405fd14d9f1264521437f6dabfa6e2aaf9eadd2..5bd7dca1246942742baccd752ca13d0e5918d4e2 100644 (file)
@@ -63,11 +63,11 @@ private:
 
 class GaussianEdgeFP : public GrFragmentProcessor {
 public:
-    GaussianEdgeFP() {
+    GaussianEdgeFP() : INHERITED(kNone_OptimizationFlags) {
         this->initClassID<GaussianEdgeFP>();
 
         // enable output of distance information for shape
-        fUsesDistanceVectorField = true;
+        this->setWillUseDistanceVectorField();
     }
 
     class GLSLGaussianEdgeFP : public GrGLSLFragmentProcessor {
@@ -123,6 +123,8 @@ private:
     }
 
     bool onIsEqual(const GrFragmentProcessor& proc) const override { return true; }
+
+    typedef GrFragmentProcessor INHERITED;
 };
 
 ////////////////////////////////////////////////////////////////////////////
index da4dcb8bdf9c1983d18455b48dbf62569efee496..3a03a1701c286e62a721f3526fa8ebc88fb7db98 100644 (file)
@@ -1625,7 +1625,7 @@ SkString emitNormalFunc(BoundaryMode mode,
 
 }
 
-class GrGLLightingEffect  : public GrGLSLFragmentProcessor {
+class GrGLLightingEffect : public GrGLSLFragmentProcessor {
 public:
     GrGLLightingEffect() : fLight(nullptr) { }
     virtual ~GrGLLightingEffect() { delete fLight; }
@@ -1702,12 +1702,13 @@ GrLightingEffect::GrLightingEffect(GrTexture* texture,
                                    const SkMatrix& matrix,
                                    BoundaryMode boundaryMode,
                                    const SkIRect* srcBounds)
-    : INHERITED(texture, nullptr, SkMatrix::I())
-    , fLight(light)
-    , fSurfaceScale(surfaceScale)
-    , fFilterMatrix(matrix)
-    , fBoundaryMode(boundaryMode)
-    , fDomain(create_domain(texture, srcBounds, GrTextureDomain::kDecal_Mode)) {
+        // Perhaps this could advertise the opaque or modulating optimizations?
+        : INHERITED(texture, nullptr, SkMatrix::I(), kNone_OptimizationFlags)
+        , fLight(light)
+        , fSurfaceScale(surfaceScale)
+        , fFilterMatrix(matrix)
+        , fBoundaryMode(boundaryMode)
+        , fDomain(create_domain(texture, srcBounds, GrTextureDomain::kDecal_Mode)) {
     fLight->ref();
 }
 
index a9516af63dbe7f5531066c3f8719137faf9d23a5..1792437e34945fbf2941a4eebd6f40546381dd49 100644 (file)
@@ -98,7 +98,7 @@ public:
     };
 
 private:
-    LumaColorFilterEffect() {
+    LumaColorFilterEffect() : INHERITED(kConstantOutputForConstantInput_OptimizationFlag) {
         this->initClassID<LumaColorFilterEffect>();
     }
 
@@ -117,6 +117,14 @@ private:
         // The output is always black. The alpha value for the color passed in is arbitrary.
         inout->setToOther(kRGB_GrColorComponentFlags, GrColorPackRGBA(0, 0, 0, 0));
     }
+    GrColor4f constantOutputForConstantInput(GrColor4f input) const override {
+        float luma = SK_ITU_BT709_LUM_COEFF_R * input.fRGBA[0] +
+                     SK_ITU_BT709_LUM_COEFF_G * input.fRGBA[1] +
+                     SK_ITU_BT709_LUM_COEFF_B * input.fRGBA[2];
+        return GrColor4f(0, 0, 0, luma);
+    }
+
+    typedef GrFragmentProcessor INHERITED;
 };
 
 sk_sp<GrFragmentProcessor> SkLumaColorFilter::asFragmentProcessor(GrContext*, SkColorSpace*) const {
index c8b32aee7015e6d0f0ebbb33dfb7965b7f433ad7..49f4fdddc3429854396e42280bbea36690a2b187 100644 (file)
@@ -27,7 +27,6 @@
 #include "../private/GrGLSL.h"
 
 class GrMagnifierEffect : public GrSingleTextureEffect {
-
 public:
     static sk_sp<GrFragmentProcessor> Make(GrTexture* texture,
                                            sk_sp<GrColorSpaceXform> colorSpaceXform,
@@ -71,14 +70,15 @@ private:
                       float yInvZoom,
                       float xInvInset,
                       float yInvInset)
-        : INHERITED(texture, std::move(colorSpaceXform), SkMatrix::I())
-        , fBounds(bounds)
-        , fXOffset(xOffset)
-        , fYOffset(yOffset)
-        , fXInvZoom(xInvZoom)
-        , fYInvZoom(yInvZoom)
-        , fXInvInset(xInvInset)
-        , fYInvInset(yInvInset) {
+            : INHERITED(texture, std::move(colorSpaceXform), SkMatrix::I(),
+                        ModulationFlags(texture->config()))
+            , fBounds(bounds)
+            , fXOffset(xOffset)
+            , fYOffset(yOffset)
+            , fXInvZoom(xInvZoom)
+            , fYInvZoom(yInvZoom)
+            , fXInvInset(xInvInset)
+            , fYInvInset(yInvInset) {
         this->initClassID<GrMagnifierEffect>();
     }
 
index 6e2a80507fe46ac240ee537934f83c00bbcf502d..febde203d5994853bbeb40cb4befd636d608c6a0 100644 (file)
@@ -140,9 +140,7 @@ void SkDilateImageFilter::toString(SkString* str) const {
  * color.
  */
 class GrMorphologyEffect : public Gr1DKernelEffect {
-
 public:
-
     enum MorphologyType {
         kErode_MorphologyType,
         kDilate_MorphologyType,
@@ -327,9 +325,9 @@ GrMorphologyEffect::GrMorphologyEffect(GrTexture* texture,
                                        Direction direction,
                                        int radius,
                                        MorphologyType type)
-    : INHERITED(texture, direction, radius)
-    , fType(type)
-    , fUseRange(false) {
+        : INHERITED(texture, direction, radius, ModulationFlags(texture->config()))
+        , fType(type)
+        , fUseRange(false) {
     this->initClassID<GrMorphologyEffect>();
 }
 
@@ -338,9 +336,9 @@ GrMorphologyEffect::GrMorphologyEffect(GrTexture* texture,
                                        int radius,
                                        MorphologyType type,
                                        const float range[2])
-    : INHERITED(texture, direction, radius)
-    , fType(type)
-    , fUseRange(true) {
+        : INHERITED(texture, direction, radius, ModulationFlags(texture->config()))
+        , fType(type)
+        , fUseRange(true) {
     this->initClassID<GrMorphologyEffect>();
     fRange[0] = range[0];
     fRange[1] = range[1];
index dea4f8b6deef51f13e73aa8dfe7c84dfadba15d6..243ef77cd0edcd37c23b03e62f8ac724770bf3d7 100644 (file)
@@ -59,7 +59,6 @@ public:
     static sk_sp<GrFragmentProcessor> Make(const SkPMColor* colors);
 
     const char* name() const override { return "Overdraw"; }
-
 private:
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
@@ -105,7 +104,10 @@ sk_sp<GrFragmentProcessor> OverdrawFragmentProcessor::Make(const SkPMColor* colo
     return sk_sp<OverdrawFragmentProcessor>(new OverdrawFragmentProcessor(grColors));
 }
 
-OverdrawFragmentProcessor::OverdrawFragmentProcessor(const GrColor4f* colors) {
+// This could implement the constant input -> constant output optimization, but we don't really
+// care given how this is used.
+OverdrawFragmentProcessor::OverdrawFragmentProcessor(const GrColor4f* colors)
+        : INHERITED(kNone_OptimizationFlags) {
     this->initClassID<OverdrawFragmentProcessor>();
     memcpy(fColors, colors, SkOverdrawColorFilter::kNumColors * sizeof(GrColor4f));
 }
index 3798a407ac131f352e483e9da617fadefba4bfe5..450fcaa4efb3df93c2400b2e1de2d7a955335028 100644 (file)
@@ -538,18 +538,18 @@ private:
         inout->setToUnknown();
     }
 
-    GrPerlinNoiseEffect(SkPerlinNoiseShader::Type type,
-                        int numOctaves, bool stitchTiles,
+    GrPerlinNoiseEffect(SkPerlinNoiseShader::Type type, int numOctaves, bool stitchTiles,
                         SkPerlinNoiseShader::PaintingData* paintingData,
                         GrTexture* permutationsTexture, GrTexture* noiseTexture,
                         const SkMatrix& matrix)
-      : fType(type)
-      , fCoordTransform(matrix)
-      , fNumOctaves(numOctaves)
-      , fStitchTiles(stitchTiles)
-      , fPermutationsSampler(permutationsTexture)
-      , fNoiseSampler(noiseTexture)
-      , fPaintingData(paintingData) {
+            : INHERITED(kNone_OptimizationFlags)
+            , fType(type)
+            , fCoordTransform(matrix)
+            , fNumOctaves(numOctaves)
+            , fStitchTiles(stitchTiles)
+            , fPermutationsSampler(permutationsTexture)
+            , fNoiseSampler(noiseTexture)
+            , fPaintingData(paintingData) {
         this->initClassID<GrPerlinNoiseEffect>();
         this->addTextureSampler(&fPermutationsSampler);
         this->addTextureSampler(&fNoiseSampler);
index 5da3ed1eb1ec862067192b769c2850377c3c75c1..223887bab9478aadce47b220f94ff2113f41437a 100644 (file)
@@ -207,9 +207,7 @@ public:
     };
 
     RRectsGaussianEdgeFP(const SkRRect& first, const SkRRect& second, SkScalar radius)
-        : fFirst(first)
-        , fSecond(second)
-        , fRadius(radius) {
+            : INHERITED(kNone_OptimizationFlags), fFirst(first), fSecond(second), fRadius(radius) {
         this->initClassID<RRectsGaussianEdgeFP>();
 
         fFirstMode = ComputeMode(fFirst);
index 1fd4c90eed84ff2075daf3bcae13967121d217f1..9198460c66eff45877222dd2518e7f34108ee73d 100644 (file)
@@ -512,10 +512,11 @@ sk_sp<GrFragmentProcessor> ColorTableEffect::Make(GrContext* context, SkBitmap b
 
 ColorTableEffect::ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row,
                                    unsigned flags)
-    : fTextureSampler(texture)
-    , fFlags(flags)
-    , fAtlas(atlas)
-    , fRow(row) {
+        : INHERITED(kNone_OptimizationFlags)  // Not bothering with table-specific optimizations.
+        , fTextureSampler(texture)
+        , fFlags(flags)
+        , fAtlas(atlas)
+        , fRow(row) {
     this->initClassID<ColorTableEffect>();
     this->addTextureSampler(&fTextureSampler);
 }
index b1d3e13a4677888202f8c75a5687747ea2134877..9a3438efe028136d9b35d740c830fbb7c0fadfdd 100644 (file)
@@ -1572,7 +1572,13 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui
 
 /////////////////////////////////////////////////////////////////////
 
-GrGradientEffect::GrGradientEffect(const CreateArgs& args) {
+inline GrFragmentProcessor::OptimizationFlags GrGradientEffect::OptFlags(bool isOpaque) {
+    return isOpaque ? kPreservesOpaqueInput_OptimizationFlag | kModulatesInput_OptimizationFlag
+                    : kModulatesInput_OptimizationFlag;
+}
+
+GrGradientEffect::GrGradientEffect(const CreateArgs& args, bool isOpaque)
+        : INHERITED(OptFlags(isOpaque)) {
     const SkGradientShaderBase& shader(*args.fShader);
 
     fIsOpaque = shader.isOpaque();
index 48ccbd50d0057ca82da0c02e472ef0f3c13b1421..6f46698ebae003a059b04aee8b75ed07e8ab4545 100644 (file)
@@ -352,8 +352,6 @@ public:
 
     class GLSLProcessor;
 
-    GrGradientEffect(const CreateArgs&);
-
     virtual ~GrGradientEffect();
 
     bool useAtlas() const { return SkToBool(-1 != fRow); }
@@ -402,6 +400,8 @@ public:
     }
 
 protected:
+    GrGradientEffect(const CreateArgs&, bool isOpaque);
+
     /** Helper struct that stores (and populates) parameters to construct a random gradient.
         If fUseColors4f is true, then the SkColor4f factory should be called, with fColors4f and
         fColorSpace. Otherwise, the SkColor factory should be called, with fColors. fColorCount
@@ -430,6 +430,8 @@ protected:
     const GrCoordTransform& getCoordTransform() const { return fCoordTransform; }
 
 private:
+    static OptimizationFlags OptFlags(bool isOpaque);
+
     // If we're in legacy mode, then fColors will be populated. If we're gamma-correct, then
     // fColors4f and fColorSpaceXform will be populated.
     SkTDArray<SkColor>       fColors;
index aab1ac787adfbfcd51d082567447c8ecf3d54301..07418e8010d9426a8423bc27902a179b5199d737 100644 (file)
@@ -426,8 +426,7 @@ public:
     const char* name() const override { return "Linear Gradient"; }
 
 private:
-    GrLinearGradient(const CreateArgs& args)
-        : INHERITED(args) {
+    GrLinearGradient(const CreateArgs& args) : INHERITED(args, args.fShader->colorsAreOpaque()) {
         this->initClassID<GrLinearGradient>();
     }
 
index 887410aa960ddea118eb9191aed7fb52598d925e..4eb3e6d93acc748a6fbf83d0cb421d7eed9d3e80 100644 (file)
@@ -256,8 +256,7 @@ public:
     const char* name() const override { return "Radial Gradient"; }
 
 private:
-    GrRadialGradient(const CreateArgs& args)
-        : INHERITED(args) {
+    GrRadialGradient(const CreateArgs& args) : INHERITED(args, args.fShader->colorsAreOpaque()) {
         this->initClassID<GrRadialGradient>();
     }
 
index 64778c3a547c9410928a383d99c67b9aaf1a34d1..7e93a21de4fafe2391c314cde0e053dafc096c16 100644 (file)
@@ -138,8 +138,7 @@ public:
     const char* name() const override { return "Sweep Gradient"; }
 
 private:
-    GrSweepGradient(const CreateArgs& args)
-    : INHERITED(args) {
+    GrSweepGradient(const CreateArgs& args) : INHERITED(args, args.fShader->colorsAreOpaque()) {
         this->initClassID<GrSweepGradient>();
     }
 
index 5f26dcdb133998ba9f63ef055fda147221dc6132..75b1cf7090a791580738a6baf096b755a0381bf9 100644 (file)
@@ -92,7 +92,7 @@ private:
     }
 
     Edge2PtConicalEffect(const CreateArgs& args)
-        : INHERITED(args) {
+            : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */) {
         const SkTwoPointConicalGradient& shader =
             *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
         fCenterX1 = shader.getCenterX1();
@@ -398,10 +398,15 @@ private:
                 this->fIsFlipped == s.fIsFlipped);
     }
 
+    static bool IsFlipped(const CreateArgs& args) {
+        // eww.
+        return static_cast<const SkTwoPointConicalGradient*>(args.fShader)->isFlippedGrad();
+    }
+
     FocalOutside2PtConicalEffect(const CreateArgs& args, SkScalar focalX)
-    : INHERITED(args)
-    , fFocalX(focalX)
-    , fIsFlipped(static_cast<const SkTwoPointConicalGradient*>(args.fShader)->isFlippedGrad()) {
+            : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */)
+            , fFocalX(focalX)
+            , fIsFlipped(IsFlipped(args)) {
         this->initClassID<FocalOutside2PtConicalEffect>();
     }
 
@@ -413,7 +418,7 @@ private:
     typedef GrGradientEffect INHERITED;
 };
 
-class FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor 
+class FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor
     : public GrGradientEffect::GLSLProcessor {
 public:
     GLSLFocalOutside2PtConicalProcessor(const GrProcessor&);
@@ -606,7 +611,7 @@ private:
     }
 
     FocalInside2PtConicalEffect(const CreateArgs& args, SkScalar focalX)
-        : INHERITED(args), fFocalX(focalX) {
+            : INHERITED(args, args.fShader->colorsAreOpaque()), fFocalX(focalX) {
         this->initClassID<FocalInside2PtConicalEffect>();
     }
 
@@ -847,7 +852,7 @@ private:
     }
 
     CircleInside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info)
-        : INHERITED(args), fInfo(info) {
+            : INHERITED(args, args.fShader->colorsAreOpaque()), fInfo(info) {
         this->initClassID<CircleInside2PtConicalEffect>();
     }
 
@@ -1064,7 +1069,8 @@ private:
     }
 
     CircleOutside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info)
-        : INHERITED(args), fInfo(info) {
+            : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */)
+            , fInfo(info) {
         this->initClassID<CircleOutside2PtConicalEffect>();
         const SkTwoPointConicalGradient& shader =
             *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
index d92a7b548ca8aaab4ab85040176e1cfee8c306f4..e7d8d31302ceb5a7e98de83b0616016829518a8a 100755 (executable)
@@ -140,9 +140,7 @@ void SkAmbientShadowMaskFilterImpl::flatten(SkWriteBuffer& buffer) const {
 //
 class ShadowEdgeFP : public GrFragmentProcessor {
 public:
-    ShadowEdgeFP() {
-        this->initClassID<ShadowEdgeFP>();
-    }
+    ShadowEdgeFP() : INHERITED(kNone_OptimizationFlags) { this->initClassID<ShadowEdgeFP>(); }
 
     class GLSLShadowEdgeFP : public GrGLSLFragmentProcessor {
     public:
@@ -179,6 +177,8 @@ private:
     }
 
     bool onIsEqual(const GrFragmentProcessor& proc) const override { return true; }
+
+    typedef GrFragmentProcessor INHERITED;
 };
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
index 0ad144a3be16ab2a6143c6d76f9b8e2007bad719..f294ac646d0d58ff793da0101b66d0d9936520c1 100644 (file)
@@ -58,7 +58,7 @@ GrGLSLFragmentProcessor* GrFragmentProcessor::createGLSLInstance() const {
 
 void GrFragmentProcessor::addCoordTransform(const GrCoordTransform* transform) {
     fCoordTransforms.push_back(transform);
-    fUsesLocalCoords = true;
+    fFlags |= kUsesLocalCoords_Flag;
     SkDEBUGCODE(transform->setInProcessor();)
 }
 
@@ -66,10 +66,10 @@ int GrFragmentProcessor::registerChildProcessor(sk_sp<GrFragmentProcessor> child
     this->combineRequiredFeatures(*child);
 
     if (child->usesLocalCoords()) {
-        fUsesLocalCoords = true;
+        fFlags |= kUsesLocalCoords_Flag;
     }
     if (child->usesDistanceVectorField()) {
-        fUsesDistanceVectorField = true;
+        fFlags |= kUsesDistanceVectorField_Flag;
     }
 
     int index = fChildProcessors.count();
@@ -111,12 +111,13 @@ sk_sp<GrFragmentProcessor> GrFragmentProcessor::PremulInput(sk_sp<GrFragmentProc
 
     class PremulInputFragmentProcessor : public GrFragmentProcessor {
     public:
-        PremulInputFragmentProcessor() {
+        PremulInputFragmentProcessor()
+                : INHERITED(kPreservesOpaqueInput_OptimizationFlag |
+                            kConstantOutputForConstantInput_OptimizationFlag) {
             this->initClassID<PremulInputFragmentProcessor>();
         }
 
         const char* name() const override { return "PremultiplyInput"; }
-
     private:
         GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
             class GLFP : public GrGLSLFragmentProcessor {
@@ -139,6 +140,11 @@ sk_sp<GrFragmentProcessor> GrFragmentProcessor::PremulInput(sk_sp<GrFragmentProc
         void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
             inout->premulFourChannelColor();
         }
+        GrColor4f constantOutputForConstantInput(GrColor4f input) const override {
+            return input.premul();
+        }
+
+        typedef GrFragmentProcessor INHERITED;
     };
     if (!fp) {
         return nullptr;
@@ -152,7 +158,8 @@ sk_sp<GrFragmentProcessor> GrFragmentProcessor::MulOutputByInputUnpremulColor(
 
     class PremulFragmentProcessor : public GrFragmentProcessor {
     public:
-        PremulFragmentProcessor(sk_sp<GrFragmentProcessor> processor) {
+        PremulFragmentProcessor(sk_sp<GrFragmentProcessor> processor)
+                : INHERITED(OptFlags(processor.get())) {
             this->initClassID<PremulFragmentProcessor>();
             this->registerChildProcessor(processor);
         }
@@ -178,6 +185,16 @@ sk_sp<GrFragmentProcessor> GrFragmentProcessor::MulOutputByInputUnpremulColor(
 
         bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
 
+        static OptimizationFlags OptFlags(const GrFragmentProcessor* inner) {
+            OptimizationFlags flags = kNone_OptimizationFlags;
+            if (inner->preservesOpaqueInput()) {
+                flags |= kPreservesOpaqueInput_OptimizationFlag;
+            }
+            if (inner->hasConstantOutputForConstantInput()) {
+                flags |= kConstantOutputForConstantInput_OptimizationFlag;
+            }
+            return flags;
+        }
         void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
             // TODO: Add a helper to GrInvariantOutput that handles multiplying by color with flags?
             if (!(inout->validFlags() & kA_GrColorComponentFlag)) {
@@ -210,6 +227,16 @@ sk_sp<GrFragmentProcessor> GrFragmentProcessor::MulOutputByInputUnpremulColor(
             }
             inout->setToOther(commonFlags, color);
         }
+        GrColor4f constantOutputForConstantInput(GrColor4f input) const override {
+            GrColor4f childColor = ConstantOutputForConstantInput(this->childProcessor(0),
+                                                                  GrColor4f::OpaqueWhite());
+            return GrColor4f(input.fRGBA[3] * input.fRGBA[0] * childColor.fRGBA[0],
+                             input.fRGBA[3] * input.fRGBA[1] * childColor.fRGBA[1],
+                             input.fRGBA[3] * input.fRGBA[2] * childColor.fRGBA[2],
+                             input.fRGBA[3] * childColor.fRGBA[3]);
+        }
+
+        typedef GrFragmentProcessor INHERITED;
     };
     if (!fp) {
         return nullptr;
@@ -224,7 +251,7 @@ sk_sp<GrFragmentProcessor> GrFragmentProcessor::OverrideInput(sk_sp<GrFragmentPr
     class ReplaceInputFragmentProcessor : public GrFragmentProcessor {
     public:
         ReplaceInputFragmentProcessor(sk_sp<GrFragmentProcessor> child, GrColor4f color)
-            : fColor(color) {
+                : INHERITED(OptFlags(child.get(), color)), fColor(color) {
             this->initClassID<ReplaceInputFragmentProcessor>();
             this->registerChildProcessor(std::move(child));
         }
@@ -264,6 +291,18 @@ sk_sp<GrFragmentProcessor> GrFragmentProcessor::OverrideInput(sk_sp<GrFragmentPr
         }
 
     private:
+        static OptimizationFlags OptFlags(const GrFragmentProcessor* child, GrColor4f color) {
+            OptimizationFlags childFlags = child->optimizationFlags();
+            OptimizationFlags flags = kNone_OptimizationFlags;
+            if (childFlags & kConstantOutputForConstantInput_OptimizationFlag) {
+                flags |= kConstantOutputForConstantInput_OptimizationFlag;
+            }
+            if ((childFlags & kPreservesOpaqueInput_OptimizationFlag) && color.isOpaque()) {
+                flags |= kPreservesOpaqueInput_OptimizationFlag;
+            }
+            return flags;
+        }
+
         void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override
         {}
 
@@ -276,7 +315,13 @@ sk_sp<GrFragmentProcessor> GrFragmentProcessor::OverrideInput(sk_sp<GrFragmentPr
             this->childProcessor(0).computeInvariantOutput(inout);
         }
 
+        GrColor4f constantOutputForConstantInput(GrColor4f) const override {
+            return ConstantOutputForConstantInput(this->childProcessor(0), fColor);
+        }
+
         GrColor4f fColor;
+
+        typedef GrFragmentProcessor INHERITED;
     };
 
     GrInvariantOutput childOut(0x0, kNone_GrColorComponentFlags);
@@ -288,7 +333,8 @@ sk_sp<GrFragmentProcessor> GrFragmentProcessor::RunInSeries(sk_sp<GrFragmentProc
                                                             int cnt) {
     class SeriesFragmentProcessor : public GrFragmentProcessor {
     public:
-        SeriesFragmentProcessor(sk_sp<GrFragmentProcessor>* children, int cnt){
+        SeriesFragmentProcessor(sk_sp<GrFragmentProcessor>* children, int cnt)
+                : INHERITED(OptFlags(children, cnt)) {
             SkASSERT(cnt > 1);
             this->initClassID<SeriesFragmentProcessor>();
             for (int i = 0; i < cnt; ++i) {
@@ -317,8 +363,14 @@ sk_sp<GrFragmentProcessor> GrFragmentProcessor::RunInSeries(sk_sp<GrFragmentProc
             };
             return new GLFP;
         }
-
     private:
+        static OptimizationFlags OptFlags(sk_sp<GrFragmentProcessor>* children, int cnt) {
+            OptimizationFlags flags = kAll_OptimizationFlags;
+            for (int i = 0; i < cnt && flags != kNone_OptimizationFlags; ++i) {
+                flags &= children[i]->optimizationFlags();
+            }
+            return flags;
+        }
         void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
 
         bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
@@ -328,6 +380,15 @@ sk_sp<GrFragmentProcessor> GrFragmentProcessor::RunInSeries(sk_sp<GrFragmentProc
                 this->childProcessor(i).computeInvariantOutput(inout);
             }
         }
+        GrColor4f constantOutputForConstantInput(GrColor4f color) const override {
+            int childCnt = this->numChildProcessors();
+            for (int i = 0; i < childCnt; ++i) {
+                color = ConstantOutputForConstantInput(this->childProcessor(i), color);
+            }
+            return color;
+        }
+
+        typedef GrFragmentProcessor INHERITED;
     };
 
     if (!cnt) {
index a4e39761266ca22260c3b67011414b90347d4105..9e2aad0ccdb6ac85c25fc7d8c53d70c017e545bb 100644 (file)
@@ -8,10 +8,11 @@
 #ifndef SkGrPriv_DEFINED
 #define SkGrPriv_DEFINED
 
-#include "GrTypes.h"
 #include "GrBlend.h"
+#include "GrTypes.h"
 #include "SkImageInfo.h"
 #include "SkMatrix.h"
+#include "SkPM4f.h"
 #include "SkXfermodePriv.h"
 
 class GrCaps;
@@ -102,6 +103,21 @@ bool SkPaintToGrPaintWithTexture(GrContext* context,
 
 //////////////////////////////////////////////////////////////////////////////
 
+static inline SkPM4f GrColor4fToSkPM4f(const GrColor4f& c) {
+    SkPM4f pm4f;
+    pm4f.fVec[SkPM4f::R] = c.fRGBA[0];
+    pm4f.fVec[SkPM4f::G] = c.fRGBA[1];
+    pm4f.fVec[SkPM4f::B] = c.fRGBA[2];
+    pm4f.fVec[SkPM4f::A] = c.fRGBA[3];
+    return pm4f;
+}
+
+static inline GrColor4f SkPM4fToGrColor4f(const SkPM4f& c) {
+    return GrColor4f{c.r(), c.g(), c.b(), c.a()};
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
 GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo&, const GrCaps&);
 
 bool GrPixelConfigToColorType(GrPixelConfig, SkColorType*);
index 29e0e5dec273ef144ca13763a7749d54e7f948b8..67cc771c614b51798883e52207ba0f928216488a 100644 (file)
@@ -28,12 +28,11 @@ public:
         kY_Direction,
     };
 
-    Gr1DKernelEffect(GrTexture* texture,
-                     Direction direction,
-                     int radius)
-        : INHERITED(texture, nullptr, SkMatrix::I())
-        , fDirection(direction)
-        , fRadius(radius) {}
+    Gr1DKernelEffect(GrTexture* texture, Direction direction, int radius,
+                     OptimizationFlags optFlags)
+            : INHERITED(texture, nullptr, SkMatrix::I(), optFlags)
+            , fDirection(direction)
+            , fRadius(radius) {}
 
     virtual ~Gr1DKernelEffect() {}
 
@@ -51,7 +50,6 @@ public:
     }
 
 private:
-
     Direction       fDirection;
     int             fRadius;
 
index 07d1c530110da11bc54101dc429423e7090628f7..cf3d2b5e79da6125f48bf850ae6167957fbb8be3 100644 (file)
@@ -132,21 +132,23 @@ void GrGLBicubicEffect::onSetData(const GrGLSLProgramDataManager& pdman,
 
 GrBicubicEffect::GrBicubicEffect(GrTexture* texture,
                                  sk_sp<GrColorSpaceXform> colorSpaceXform,
-                                 const SkMatrix &matrix,
+                                 const SkMatrixmatrix,
                                  const SkShader::TileMode tileModes[2])
-  : INHERITED(texture, std::move(colorSpaceXform), matrix,
-              GrSamplerParams(tileModes, GrSamplerParams::kNone_FilterMode))
-  , fDomain(GrTextureDomain::IgnoredDomain()) {
+        : INHERITED(texture, std::move(colorSpaceXform), matrix,
+                    GrSamplerParams(tileModes, GrSamplerParams::kNone_FilterMode),
+                    ModulationFlags(texture->config()))
+        , fDomain(GrTextureDomain::IgnoredDomain()) {
     this->initClassID<GrBicubicEffect>();
 }
 
 GrBicubicEffect::GrBicubicEffect(GrTexture* texture,
                                  sk_sp<GrColorSpaceXform> colorSpaceXform,
-                                 const SkMatrix &matrix,
+                                 const SkMatrixmatrix,
                                  const SkRect& domain)
-  : INHERITED(texture, std::move(colorSpaceXform), matrix,
-              GrSamplerParams(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode))
-  , fDomain(texture, domain, GrTextureDomain::kClamp_Mode) {
+        : INHERITED(texture, std::move(colorSpaceXform), matrix,
+                    GrSamplerParams(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode),
+                    ModulationFlags(texture->config()))
+        , fDomain(texture, domain, GrTextureDomain::kClamp_Mode) {
     this->initClassID<GrBicubicEffect>();
 }
 
index 2380ad343599a1a55b55629a28ac0b82197193b4..74cf2ca44f6a59e970c1f0bfe4e066c95207dd39 100644 (file)
@@ -98,9 +98,9 @@ GrConfigConversionEffect::GrConfigConversionEffect(GrTexture* texture,
                                                    const GrSwizzle& swizzle,
                                                    PMConversion pmConversion,
                                                    const SkMatrix& matrix)
-    : INHERITED(texture, nullptr, matrix)
-    , fSwizzle(swizzle)
-    , fPMConversion(pmConversion) {
+        : INHERITED(texture, nullptr, matrix, ModulationFlags(texture->config()))
+        , fSwizzle(swizzle)
+        , fPMConversion(pmConversion) {
     this->initClassID<GrConfigConversionEffect>();
     // We expect to get here with non-BGRA/RGBA only if we're doing not doing a premul/unpremul
     // conversion.
@@ -116,7 +116,7 @@ GrConfigConversionEffect::GrConfigConversionEffect(GrContext* context,
                                                    const GrSwizzle& swizzle,
                                                    PMConversion pmConversion,
                                                    const SkMatrix& matrix)
-    : INHERITED(context, proxy, nullptr, matrix)
+    : INHERITED(context, ModulationFlags(proxy->config()), proxy, nullptr, matrix)
     , fSwizzle(swizzle)
     , fPMConversion(pmConversion) {
     this->initClassID<GrConfigConversionEffect>();
index 46180bb2f2a9c9c08a558e0322edb4e49189f892..151365b9b08f6f758b3dc68d8ab281b39adc4fe6 100644 (file)
@@ -52,7 +52,6 @@ public:
     static void TestForPreservingPMConversions(GrContext* context,
                                                PMConversion* PMToUPMRule,
                                                PMConversion* UPMToPMRule);
-
 private:
     GrConfigConversionEffect(GrTexture*, const GrSwizzle&, PMConversion, const SkMatrix& matrix);
 
index e6568793dfed9e72052cb19bb8bb2870b1db559d..3875ffcaa05e7b0289481d9bd7145bb9203a9dd9 100644 (file)
@@ -85,6 +85,19 @@ void GrConstColorProcessor::onComputeInvariantOutput(GrInvariantOutput* inout) c
     }
 }
 
+GrColor4f GrConstColorProcessor::constantOutputForConstantInput(GrColor4f input) const {
+    switch (fMode) {
+        case kIgnore_InputMode:
+            return fColor;
+        case kModulateA_InputMode:
+            return fColor.mulByScalar(input.fRGBA[3]);
+        case kModulateRGBA_InputMode:
+            return fColor.modulate(input);
+    }
+    SkFAIL("Unexpected mode");
+    return GrColor4f::TransparentBlack();
+}
+
 void GrConstColorProcessor::onGetGLSLProcessorKey(const GrShaderCaps&,
                                                   GrProcessorKeyBuilder* b) const {
     b->add32(fMode);
index 65ed87b6871bdf380285a72c59a2821321adadf8..4100a0fce25c0c4b14b34f0ccc2190e1e509ca02 100644 (file)
@@ -32,7 +32,7 @@ public:
 
 private:
     AARectEffect(GrPrimitiveEdgeType edgeType, const SkRect& rect)
-        : fRect(rect), fEdgeType(edgeType) {
+            : INHERITED(kModulatesInput_OptimizationFlag), fRect(rect), fEdgeType(edgeType) {
         this->initClassID<AARectEffect>();
     }
 
@@ -339,8 +339,7 @@ GrGLSLFragmentProcessor* GrConvexPolyEffect::onCreateGLSLInstance() const  {
 }
 
 GrConvexPolyEffect::GrConvexPolyEffect(GrPrimitiveEdgeType edgeType, int n, const SkScalar edges[])
-    : fEdgeType(edgeType)
-    , fEdgeCount(n) {
+        : INHERITED(kModulatesInput_OptimizationFlag), fEdgeType(edgeType), fEdgeCount(n) {
     this->initClassID<GrConvexPolyEffect>();
     // Factory function should have already ensured this.
     SkASSERT(n <= kMaxEdges);
index 2ba47d2e09474e90f8edd5346a6e061bdac144c2..24e3ba6d50fbd7fc8b65b5700409698e91d13781 100644 (file)
@@ -26,9 +26,7 @@ public:
     const char* name() const override { return "Dither"; }
 
 private:
-    DitherEffect() {
-        this->initClassID<DitherEffect>();
-    }
+    DitherEffect() : INHERITED(kNone_OptimizationFlags) { this->initClassID<DitherEffect>(); }
 
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
 
index 91301ff9ac914622c02ba167a1629839f44eb8d6..be6d4d83026b1dfc190bdd7c35c208c15eacc3cb 100644 (file)
@@ -150,7 +150,8 @@ GrGaussianConvolutionFragmentProcessor::GrGaussianConvolutionFragmentProcessor(G
                                                                                float gaussianSigma,
                                                                                bool useBounds,
                                                                                float bounds[2])
-        : INHERITED(texture, direction, radius), fUseBounds(useBounds) {
+        : INHERITED(texture, direction, radius, ModulationFlags(texture->config()))
+        , fUseBounds(useBounds) {
     this->initClassID<GrGaussianConvolutionFragmentProcessor>();
     SkASSERT(radius <= kMaxKernelRadius);
     int width = this->width();
index 01fc6cec9cd5a28bfc840d4591148bbf7110d99c..9b670e120ff99eddc813924afb17c96b3ca5b854 100644 (file)
@@ -156,12 +156,14 @@ GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(GrTexture* texture,
                                                      const SkIPoint& kernelOffset,
                                                      GrTextureDomain::Mode tileMode,
                                                      bool convolveAlpha)
-  : INHERITED(texture, nullptr, SkMatrix::I()),
-    fKernelSize(kernelSize),
-    fGain(SkScalarToFloat(gain)),
-    fBias(SkScalarToFloat(bias) / 255.0f),
-    fConvolveAlpha(convolveAlpha),
-    fDomain(texture, GrTextureDomain::MakeTexelDomainForMode(bounds, tileMode), tileMode) {
+        // To advertise either the modulation or opaqueness optimizations we'd have to examine the
+        // parameters.
+        : INHERITED(texture, nullptr, SkMatrix::I(), kNone_OptimizationFlags)
+        , fKernelSize(kernelSize)
+        , fGain(SkScalarToFloat(gain))
+        , fBias(SkScalarToFloat(bias) / 255.0f)
+        , fConvolveAlpha(convolveAlpha)
+        , fDomain(texture, GrTextureDomain::MakeTexelDomainForMode(bounds, tileMode), tileMode) {
     this->initClassID<GrMatrixConvolutionEffect>();
     for (int i = 0; i < kernelSize.width() * kernelSize.height(); i++) {
         fKernel[i] = SkScalarToFloat(kernel[i]);
index 21a4ba00e5086a1547e10ca10df8e9fd44e3ebb3..3b0a8871c4e662cdc6a8215f87bb8fcd54a74bb4 100644 (file)
@@ -64,9 +64,7 @@ void CircleEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
 }
 
 CircleEffect::CircleEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar r)
-    : fCenter(c)
-    , fRadius(r)
-    , fEdgeType(edgeType) {
+        : INHERITED(kModulatesInput_OptimizationFlag), fCenter(c), fRadius(r), fEdgeType(edgeType) {
     this->initClassID<CircleEffect>();
 }
 
@@ -230,10 +228,12 @@ void EllipseEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
     inout->mulByUnknownSingleComponent();
 }
 
-EllipseEffect::EllipseEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar rx, SkScalar ry)
-    : fCenter(c)
-    , fRadii(SkVector::Make(rx, ry))
-    , fEdgeType(edgeType) {
+EllipseEffect::EllipseEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar rx,
+                             SkScalar ry)
+        : INHERITED(kModulatesInput_OptimizationFlag)
+        , fCenter(c)
+        , fRadii(SkVector::Make(rx, ry))
+        , fEdgeType(edgeType) {
     this->initClassID<EllipseEffect>();
 }
 
index adebc245a692b9b3f7c71beb2f66ce7bd864a222..4397fcf9300fd1aaff7336c3d065f08bb1ebf8c5 100644 (file)
@@ -95,9 +95,10 @@ void CircularRRectEffect::onComputeInvariantOutput(GrInvariantOutput* inout) con
 
 CircularRRectEffect::CircularRRectEffect(GrPrimitiveEdgeType edgeType, uint32_t circularCornerFlags,
                                          const SkRRect& rrect)
-    : fRRect(rrect)
-    , fEdgeType(edgeType)
-    , fCircularCornerFlags(circularCornerFlags) {
+        : INHERITED(kModulatesInput_OptimizationFlag)
+        , fRRect(rrect)
+        , fEdgeType(edgeType)
+        , fCircularCornerFlags(circularCornerFlags) {
     this->initClassID<CircularRRectEffect>();
 }
 
@@ -410,8 +411,8 @@ private:
 
     void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
 
-    SkRRect             fRRect;
-    GrPrimitiveEdgeType    fEdgeType;
+    SkRRect fRRect;
+    GrPrimitiveEdgeType fEdgeType;
 
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
 
@@ -431,8 +432,7 @@ void EllipticalRRectEffect::onComputeInvariantOutput(GrInvariantOutput* inout) c
 }
 
 EllipticalRRectEffect::EllipticalRRectEffect(GrPrimitiveEdgeType edgeType, const SkRRect& rrect)
-    : fRRect(rrect)
-    , fEdgeType(edgeType) {
+        : INHERITED(kModulatesInput_OptimizationFlag), fRRect(rrect), fEdgeType(edgeType) {
     this->initClassID<EllipticalRRectEffect>();
 }
 
index 67600ef3206b26aa9c7089304b54be12573aa55f..92795865840eae28ca8cf1d2cf9bfe88cfb49280 100644 (file)
@@ -71,7 +71,9 @@ private:
 ///////////////////////////////////////////////////////////////////////////////
 
 GrSRGBEffect::GrSRGBEffect(Mode mode)
-    : fMode(mode) {
+        : INHERITED(kPreservesOpaqueInput_OptimizationFlag |
+                    kConstantOutputForConstantInput_OptimizationFlag)
+        , fMode(mode) {
     this->initClassID<GrSRGBEffect>();
 }
 
@@ -84,6 +86,26 @@ void GrSRGBEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
     inout->setToUnknown();
 }
 
+static inline float srgb_to_linear(float srgb) {
+    return (srgb <= 0.04045f) ? srgb / 12.92f : powf((srgb + 0.055f) / 1.055f, 2.4f);
+}
+static inline float linear_to_srgb(float linear) {
+    return (linear <= 0.0031308) ? linear * 12.92f : 1.055f * powf(linear, 1.f / 2.4f) - 0.055f;
+}
+
+GrColor4f GrSRGBEffect::constantOutputForConstantInput(GrColor4f input) const {
+    switch (fMode) {
+        case Mode::kLinearToSRGB:
+            return GrColor4f(linear_to_srgb(input.fRGBA[0]), linear_to_srgb(input.fRGBA[1]),
+                             linear_to_srgb(input.fRGBA[2]), input.fRGBA[3]);
+        case Mode::kSRGBToLinear:
+            return GrColor4f(srgb_to_linear(input.fRGBA[0]), srgb_to_linear(input.fRGBA[1]),
+                             srgb_to_linear(input.fRGBA[2]), input.fRGBA[3]);
+    }
+    SkFAIL("Unexpected mode");
+    return GrColor4f::TransparentBlack();
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSRGBEffect);
index 2952689c4ecc5fab97e01367cb0c9c177f60f508..3d05dd646bfeb68e69ff632bc8a0c1e08e3bcbe4 100644 (file)
@@ -33,6 +33,7 @@ private:
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
     bool onIsEqual(const GrFragmentProcessor&) const override;
     void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
+    GrColor4f constantOutputForConstantInput(GrColor4f input) const override;
 
     Mode fMode;
 
index bf013e9c83c4811cf82156174e84669b77c18d3c..c44ce44121d1de6f38bd2b88147d630bb1bcbcc4 100644 (file)
 
 class GrInvariantOutput;
 
+// In a few places below we rely on braced initialization order being defined by the C++ spec (left
+// to right). We use operator-> on a sk_sp and then in a later argument std::move() the sk_sp. GCC
+// 4.9.0 and earlier has a bug where the left to right order evaluation isn't implemented correctly.
+#if defined(__GNUC__) && !defined(__clang__)
+#   define GCC_VERSION (__GNUC__ * 10000  + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#   if (GCC_VERSION > 40900)
+#       define GCC_EVAL_ORDER_BUG 0
+#   else
+#       define GCC_EVAL_ORDER_BUG 1
+#   endif
+#   undef GCC_VERSION
+#else
+#   define GCC_EVAL_ORDER_BUG 0
+#endif
+
+#if GCC_EVAL_ORDER_BUG
+#   define PROXY_MOVE(X) (X)
+#else
+#   define PROXY_MOVE(X) (std::move(X))
+#endif
+
+#undef GCC_EVAL_ORDER_BUG
+
 /**
  * The output color of this effect is a modulation of the input color and a sample from a texture.
  * It allows explicit specification of the filtering and wrap modes (GrSamplerParams) and accepts
@@ -81,32 +104,41 @@ private:
                           sk_sp<GrColorSpaceXform> colorSpaceXform,
                           const SkMatrix& matrix,
                           GrSamplerParams::FilterMode filterMode)
-        : GrSingleTextureEffect(texture, std::move(colorSpaceXform), matrix, filterMode) {
+            : INHERITED(texture, std::move(colorSpaceXform), matrix, filterMode,
+                        ModulationFlags(texture->config())) {
         this->initClassID<GrSimpleTextureEffect>();
     }
 
     GrSimpleTextureEffect(GrContext* ctx, sk_sp<GrTextureProxy> proxy,
-                          sk_sp<GrColorSpaceXform> colorSpaceXform,
-                          const SkMatrix& matrix,
+                          sk_sp<GrColorSpaceXform> colorSpaceXform, const SkMatrix& matrix,
                           GrSamplerParams::FilterMode filterMode)
-        : GrSingleTextureEffect(ctx, std::move(proxy), std::move(colorSpaceXform),
-                                matrix, filterMode) {
+            : INHERITED{ctx,
+                        ModulationFlags(proxy->config()),
+                        PROXY_MOVE(proxy),
+                        std::move(colorSpaceXform),
+                        matrix,
+                        filterMode} {
         this->initClassID<GrSimpleTextureEffect>();
     }
 
     GrSimpleTextureEffect(GrTexture* texture,
-                          sk_sp<GrColorSpaceXform> colorSpaceXform,
+                          sk_sp<GrColorSpaceXform>colorSpaceXform,
                           const SkMatrix& matrix,
                           const GrSamplerParams& params)
-        : GrSingleTextureEffect(texture, std::move(colorSpaceXform), matrix, params) {
+            : INHERITED(texture, std::move(colorSpaceXform), matrix, params,
+                        ModulationFlags(texture->config())) {
         this->initClassID<GrSimpleTextureEffect>();
     }
 
     GrSimpleTextureEffect(GrContext* ctx, sk_sp<GrTextureProxy> proxy,
-                          sk_sp<GrColorSpaceXform> colorSpaceXform,
-                          const SkMatrix& matrix,
+                          sk_sp<GrColorSpaceXform> colorSpaceXform, const SkMatrix& matrix,
                           const GrSamplerParams& params)
-        : GrSingleTextureEffect(ctx, std::move(proxy), std::move(colorSpaceXform), matrix, params) {
+            : INHERITED{ctx,
+                        ModulationFlags(proxy->config()),
+                        PROXY_MOVE(proxy),
+                        std::move(colorSpaceXform),
+                        matrix,
+                        params} {
         this->initClassID<GrSimpleTextureEffect>();
     }
 
@@ -123,4 +155,6 @@ private:
     typedef GrSingleTextureEffect INHERITED;
 };
 
+#undef PROXY_MOVE
+
 #endif
index c493920d3d63303f17fbc56a68e378f7277ea56f..acfc0d142d1b574d3ee8a511d82a2e636117c5c1 100644 (file)
 
 GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture,
                                              sk_sp<GrColorSpaceXform> colorSpaceXform,
-                                             const SkMatrix& m)
-    : fCoordTransform(m, texture, GrSamplerParams::kNone_FilterMode)
-    , fTextureSampler(texture)
-    , fColorSpaceXform(std::move(colorSpaceXform)) {
+                                             const SkMatrix& m, OptimizationFlags optFlags)
+        : INHERITED(optFlags)
+        , fCoordTransform(m, texture, GrSamplerParams::kNone_FilterMode)
+        , fTextureSampler(texture)
+        , fColorSpaceXform(std::move(colorSpaceXform)) {
     this->addCoordTransform(&fCoordTransform);
     this->addTextureSampler(&fTextureSampler);
 }
@@ -23,56 +24,61 @@ GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture,
 GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture,
                                              sk_sp<GrColorSpaceXform> colorSpaceXform,
                                              const SkMatrix& m,
-                                             GrSamplerParams::FilterMode filterMode)
-    : fCoordTransform(m, texture, filterMode)
-    , fTextureSampler(texture, filterMode)
-    , fColorSpaceXform(std::move(colorSpaceXform)) {
+                                             GrSamplerParams::FilterMode filterMode,
+                                             OptimizationFlags optFlags)
+        : INHERITED(optFlags)
+        , fCoordTransform(m, texture, filterMode)
+        , fTextureSampler(texture, filterMode)
+        , fColorSpaceXform(std::move(colorSpaceXform)) {
     this->addCoordTransform(&fCoordTransform);
     this->addTextureSampler(&fTextureSampler);
 }
 
 GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture,
                                              sk_sp<GrColorSpaceXform> colorSpaceXform,
-                                             const SkMatrix& m,
-                                             const GrSamplerParams& params)
-    : fCoordTransform(m, texture, params.filterMode())
-    , fTextureSampler(texture, params)
-    , fColorSpaceXform(std::move(colorSpaceXform)) {
+                                             const SkMatrix& m, const GrSamplerParams& params,
+                                             OptimizationFlags optFlags)
+        : INHERITED(optFlags)
+        , fCoordTransform(m, texture, params.filterMode())
+        , fTextureSampler(texture, params)
+        , fColorSpaceXform(std::move(colorSpaceXform)) {
     this->addCoordTransform(&fCoordTransform);
     this->addTextureSampler(&fTextureSampler);
 }
 
-GrSingleTextureEffect::GrSingleTextureEffect(GrContext* ctx, sk_sp<GrTextureProxy> proxy,
+GrSingleTextureEffect::GrSingleTextureEffect(GrContext* ctx, OptimizationFlags optFlags,
+                                             sk_sp<GrTextureProxy> proxy,
                                              sk_sp<GrColorSpaceXform> colorSpaceXform,
                                              const SkMatrix& m)
-    : fCoordTransform(ctx, m, proxy.get(), GrSamplerParams::kNone_FilterMode)
-    , fTextureSampler(ctx->textureProvider(), std::move(proxy))
-    , fColorSpaceXform(std::move(colorSpaceXform)) {
+        : INHERITED(optFlags)
+        , fCoordTransform(ctx, m, proxy.get(), GrSamplerParams::kNone_FilterMode)
+        , fTextureSampler(ctx->textureProvider(), std::move(proxy))
+        , fColorSpaceXform(std::move(colorSpaceXform)) {
     this->addCoordTransform(&fCoordTransform);
     this->addTextureSampler(&fTextureSampler);
 }
 
-GrSingleTextureEffect::GrSingleTextureEffect(GrContext* ctx, sk_sp<GrTextureProxy> proxy,
+GrSingleTextureEffect::GrSingleTextureEffect(GrContext* ctx, OptimizationFlags optFlags,
+                                             sk_sp<GrTextureProxy> proxy,
                                              sk_sp<GrColorSpaceXform> colorSpaceXform,
                                              const SkMatrix& m,
                                              GrSamplerParams::FilterMode filterMode)
-    : fCoordTransform(ctx, m, proxy.get(), filterMode)
-    , fTextureSampler(ctx->textureProvider(), std::move(proxy), filterMode)
-    , fColorSpaceXform(std::move(colorSpaceXform)) {
+        : INHERITED(optFlags)
+        , fCoordTransform(ctx, m, proxy.get(), filterMode)
+        , fTextureSampler(ctx->textureProvider(), std::move(proxy), filterMode)
+        , fColorSpaceXform(std::move(colorSpaceXform)) {
     this->addCoordTransform(&fCoordTransform);
     this->addTextureSampler(&fTextureSampler);
 }
 
-GrSingleTextureEffect::GrSingleTextureEffect(GrContext* ctx, sk_sp<GrTextureProxy> proxy,
+GrSingleTextureEffect::GrSingleTextureEffect(GrContext* ctx, OptimizationFlags optFlags,
+                                             sk_sp<GrTextureProxy> proxy,
                                              sk_sp<GrColorSpaceXform> colorSpaceXform,
-                                             const SkMatrix& m,
-                                             const GrSamplerParams& params)
-    : fCoordTransform(ctx, m, proxy.get(), params.filterMode())
-    , fTextureSampler(ctx->textureProvider(), std::move(proxy), params)
-    , fColorSpaceXform(std::move(colorSpaceXform)) {
+                                             const SkMatrix& m, const GrSamplerParams& params)
+        : INHERITED(optFlags)
+        , fCoordTransform(ctx, m, proxy.get(), params.filterMode())
+        , fTextureSampler(ctx->textureProvider(), std::move(proxy), params)
+        , fColorSpaceXform(std::move(colorSpaceXform)) {
     this->addCoordTransform(&fCoordTransform);
     this->addTextureSampler(&fTextureSampler);
 }
-
-GrSingleTextureEffect::~GrSingleTextureEffect() {
-}
index 1d0f27a4ff25644b678b9fb6dbfb08509cd9af6e..29105b5cda55627c28d4352c30e9c637d21f980b 100644 (file)
@@ -23,8 +23,6 @@ class GrTextureProxy;
  */
 class GrSingleTextureEffect : public GrFragmentProcessor {
 public:
-    ~GrSingleTextureEffect() override;
-
     SkString dumpInfo() const override {
         SkString str;
         str.appendf("Texture: %d", fTextureSampler.texture()->uniqueID().asUInt());
@@ -35,25 +33,26 @@ public:
 
 protected:
     /** unfiltered, clamp mode */
-    GrSingleTextureEffect(GrTexture*, sk_sp<GrColorSpaceXform>, const SkMatrix&);
+    GrSingleTextureEffect(GrTexture*, sk_sp<GrColorSpaceXform>, const SkMatrix&,
+                          OptimizationFlags optFlags);
     /** clamp mode */
     GrSingleTextureEffect(GrTexture*, sk_sp<GrColorSpaceXform>, const SkMatrix&,
-                          GrSamplerParams::FilterMode filterMode);
+                          GrSamplerParams::FilterMode filterMode, OptimizationFlags optFlags);
     GrSingleTextureEffect(GrTexture*,
                           sk_sp<GrColorSpaceXform>,
                           const SkMatrix&,
-                          const GrSamplerParams&);
+                          const GrSamplerParams&,
+                          OptimizationFlags optFlags);
 
     /** unfiltered, clamp mode */
-    GrSingleTextureEffect(GrContext*,
-                          sk_sp<GrTextureProxy>, sk_sp<GrColorSpaceXform>, const SkMatrix&);
+    GrSingleTextureEffect(GrContext*, OptimizationFlags, sk_sp<GrTextureProxy>,
+                          sk_sp<GrColorSpaceXform>, const SkMatrix&);
     /** clamp mode */
-    GrSingleTextureEffect(GrContext*,
-                          sk_sp<GrTextureProxy>, sk_sp<GrColorSpaceXform>, const SkMatrix&,
+    GrSingleTextureEffect(GrContext*, OptimizationFlags, sk_sp<GrTextureProxy>,
+                          sk_sp<GrColorSpaceXform>, const SkMatrix&,
                           GrSamplerParams::FilterMode filterMode);
-    GrSingleTextureEffect(GrContext*,
-                          sk_sp<GrTextureProxy>, sk_sp<GrColorSpaceXform>, const SkMatrix&,
-                          const GrSamplerParams&);
+    GrSingleTextureEffect(GrContext*, OptimizationFlags, sk_sp<GrTextureProxy>,
+                          sk_sp<GrColorSpaceXform>, const SkMatrix&, const GrSamplerParams&);
 
     /**
      * Can be used as a helper to implement subclass onComputeInvariantOutput(). It assumes that
@@ -71,6 +70,19 @@ protected:
         }
     }
 
+    /**
+     * Can be used as a helper to implement subclass onOptimizationFlags(). It assumes that
+     * the subclass output color will be a modulation of the input color with a value read from the
+     * texture.
+     */
+    static OptimizationFlags ModulationFlags(GrPixelConfig config) {
+        if (GrPixelConfigIsOpaque(config)) {
+            return kModulatesInput_OptimizationFlag | kPreservesOpaqueInput_OptimizationFlag;
+        } else {
+            return kModulatesInput_OptimizationFlag;
+        }
+    }
+
 private:
     GrCoordTransform fCoordTransform;
     TextureSampler fTextureSampler;
index 095f1005937a54ca0ff158801a703df21eab4007..7ab598fd1fb68b1b699a4f400adfe12557a6acb4 100644 (file)
@@ -208,14 +208,25 @@ sk_sp<GrFragmentProcessor> GrTextureDomainEffect::Make(GrTexture* texture,
     }
 }
 
+inline GrFragmentProcessor::OptimizationFlags GrTextureDomainEffect::OptFlags(
+        GrTexture* texture, GrTextureDomain::Mode mode) {
+    if (mode == GrTextureDomain::kDecal_Mode || !GrPixelConfigIsOpaque(texture->config())) {
+        return GrFragmentProcessor::kModulatesInput_OptimizationFlag;
+    } else {
+        return GrFragmentProcessor::kModulatesInput_OptimizationFlag |
+               GrFragmentProcessor::kPreservesOpaqueInput_OptimizationFlag;
+    }
+}
+
 GrTextureDomainEffect::GrTextureDomainEffect(GrTexture* texture,
                                              sk_sp<GrColorSpaceXform> colorSpaceXform,
                                              const SkMatrix& matrix,
                                              const SkRect& domain,
                                              GrTextureDomain::Mode mode,
                                              GrSamplerParams::FilterMode filterMode)
-    : GrSingleTextureEffect(texture, std::move(colorSpaceXform), matrix, filterMode)
-    , fTextureDomain(texture, domain, mode) {
+        : GrSingleTextureEffect(texture, std::move(colorSpaceXform), matrix, filterMode,
+                                OptFlags(texture, mode))
+        , fTextureDomain(texture, domain, mode) {
     SkASSERT(mode != GrTextureDomain::kRepeat_Mode ||
             filterMode == GrSamplerParams::kNone_FilterMode);
     this->initClassID<GrTextureDomainEffect>();
@@ -323,7 +334,8 @@ sk_sp<GrFragmentProcessor> GrDeviceSpaceTextureDecalFragmentProcessor::Make(GrTe
 
 GrDeviceSpaceTextureDecalFragmentProcessor::GrDeviceSpaceTextureDecalFragmentProcessor(
         GrTexture* texture, const SkIRect& subset, const SkIPoint& deviceSpaceOffset)
-        : fTextureSampler(texture, GrSamplerParams::ClampNoFilter())
+        : INHERITED(kModulatesInput_OptimizationFlag)
+        , fTextureSampler(texture, GrSamplerParams::ClampNoFilter())
         , fTextureDomain(texture, GrTextureDomain::MakeTexelDomain(subset),
                          GrTextureDomain::kDecal_Mode) {
     this->addTextureSampler(&fTextureSampler);
index 66bd2201e3a687d61979d84ce98e6183c9420064..6758d9045eeaaee91655d2fe29f97d0e60e18eb6 100644 (file)
@@ -178,6 +178,8 @@ private:
                           GrTextureDomain::Mode,
                           GrSamplerParams::FilterMode);
 
+    static OptimizationFlags OptFlags(GrTexture* texture, GrTextureDomain::Mode mode);
+
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
 
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
index d98478747a5ca7ba25fdb6bcbabbd2aeb4910e18..af32adec8b1b68340b2a0d0bdb4f761c842e1d7c 100644 (file)
@@ -19,7 +19,7 @@ class ComposeTwoFragmentProcessor : public GrFragmentProcessor {
 public:
     ComposeTwoFragmentProcessor(sk_sp<GrFragmentProcessor> src, sk_sp<GrFragmentProcessor> dst,
                                 SkBlendMode mode)
-        : fMode(mode) {
+            : INHERITED(OptFlags(src.get(), dst.get(), mode)), fMode(mode) {
         this->initClassID<ComposeTwoFragmentProcessor>();
         SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(std::move(src));
         SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(std::move(dst));
@@ -35,7 +35,18 @@ public:
 
     SkBlendMode getMode() const { return fMode; }
 
-protected:
+private:
+    static OptimizationFlags OptFlags(const GrFragmentProcessor* src,
+                                      const GrFragmentProcessor* dst, SkBlendMode mode) {
+        // We only attempt the constant output optimization.
+        // The CPU and GPU implementations differ significantly for the advanced modes.
+        if (mode <= SkBlendMode::kLastSeparableMode && src->hasConstantOutputForConstantInput() &&
+            dst->hasConstantOutputForConstantInput()) {
+            return kConstantOutputForConstantInput_OptimizationFlag;
+        }
+        return kNone_OptimizationFlags;
+    }
+
     bool onIsEqual(const GrFragmentProcessor& other) const override {
         const ComposeTwoFragmentProcessor& cs = other.cast<ComposeTwoFragmentProcessor>();
         return fMode == cs.fMode;
@@ -45,7 +56,17 @@ protected:
         inout->setToUnknown();
     }
 
-private:
+    GrColor4f constantOutputForConstantInput(GrColor4f input) const override {
+        float alpha = input.fRGBA[3];
+        input = input.opaque();
+        GrColor4f srcColor = ConstantOutputForConstantInput(this->childProcessor(0), input);
+        GrColor4f dstColor = ConstantOutputForConstantInput(this->childProcessor(1), input);
+        SkPM4f src = GrColor4fToSkPM4f(srcColor);
+        SkPM4f dst = GrColor4fToSkPM4f(dstColor);
+        auto proc = SkXfermode::GetProc4f(fMode);
+        return SkPM4fToGrColor4f(proc(src, dst)).mulByScalar(alpha);
+    }
+
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
 
     SkBlendMode fMode;
@@ -145,8 +166,7 @@ public:
     };
 
     ComposeOneFragmentProcessor(sk_sp<GrFragmentProcessor> dst, SkBlendMode mode, Child child)
-        : fMode(mode)
-        , fChild(child) {
+            : INHERITED(OptFlags(dst.get(), mode)), fMode(mode), fChild(child) {
         this->initClassID<ComposeOneFragmentProcessor>();
         SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(std::move(dst));
         SkASSERT(0 == dstIndex);
@@ -172,7 +192,16 @@ public:
 
     Child child() const { return fChild; }
 
-protected:
+private:
+    OptimizationFlags OptFlags(const GrFragmentProcessor* child, SkBlendMode mode) {
+        // We only attempt the constant output optimization.
+        // The CPU and GPU implementations differ significantly for the advanced modes.
+        if (mode <= SkBlendMode::kLastSeparableMode && child->hasConstantOutputForConstantInput()) {
+            return kConstantOutputForConstantInput_OptimizationFlag;
+        }
+        return kNone_OptimizationFlags;
+    }
+
     bool onIsEqual(const GrFragmentProcessor& that) const override {
         return fMode == that.cast<ComposeOneFragmentProcessor>().fMode;
     }
@@ -203,6 +232,21 @@ protected:
         }
     }
 
+    GrColor4f constantOutputForConstantInput(GrColor4f inputColor) const override {
+        GrColor4f childColor =
+                ConstantOutputForConstantInput(this->childProcessor(0), GrColor4f::OpaqueWhite());
+        SkPM4f src, dst;
+        if (kSrc_Child == fChild) {
+            src = GrColor4fToSkPM4f(childColor);
+            dst = GrColor4fToSkPM4f(inputColor);
+        } else {
+            src = GrColor4fToSkPM4f(inputColor);
+            dst = GrColor4fToSkPM4f(childColor);
+        }
+        auto proc = SkXfermode::GetProc4f(fMode);
+        return SkPM4fToGrColor4f(proc(src, dst));
+    }
+
 private:
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
 
index 254cdffd2b2d87e78b291694774bb31405026c4d..6d917f36d5910cfeea4764568d776ff9cea8008f 100644 (file)
@@ -155,19 +155,17 @@ public:
     };
 
 private:
-    YUVtoRGBEffect(GrContext* ctx,
-                   sk_sp<GrTextureProxy> yProxy,
-                   sk_sp<GrTextureProxy> uProxy,
-                   sk_sp<GrTextureProxy> vProxy,
-                   const SkMatrix yuvMatrix[3], GrSamplerParams::FilterMode uvFilterMode,
-                   SkYUVColorSpace colorSpace, bool nv12)
-        : fYTransform(ctx, yuvMatrix[0], yProxy.get(), GrSamplerParams::kNone_FilterMode)
-        , fYSampler(ctx->textureProvider(), std::move(yProxy))
-        , fUTransform(ctx, yuvMatrix[1], uProxy.get(), uvFilterMode)
-        , fUSampler(ctx->textureProvider(), std::move(uProxy), uvFilterMode)
-        , fVSampler(ctx->textureProvider(), vProxy, uvFilterMode)
-        , fColorSpace(colorSpace)
-        , fNV12(nv12) {
+    YUVtoRGBEffect(GrContext* ctx, sk_sp<GrTextureProxy> yProxy, sk_sp<GrTextureProxy> uProxy,
+                   sk_sp<GrTextureProxy> vProxy, const SkMatrix yuvMatrix[3],
+                   GrSamplerParams::FilterMode uvFilterMode, SkYUVColorSpace colorSpace, bool nv12)
+            : INHERITED(kPreservesOpaqueInput_OptimizationFlag)
+            , fYTransform(ctx, yuvMatrix[0], yProxy.get(), GrSamplerParams::kNone_FilterMode)
+            , fYSampler(ctx->textureProvider(), std::move(yProxy))
+            , fUTransform(ctx, yuvMatrix[1], uProxy.get(), uvFilterMode)
+            , fUSampler(ctx->textureProvider(), std::move(uProxy), uvFilterMode)
+            , fVSampler(ctx->textureProvider(), vProxy, uvFilterMode)
+            , fColorSpace(colorSpace)
+            , fNV12(nv12) {
         this->initClassID<YUVtoRGBEffect>();
         this->addCoordTransform(&fYTransform);
         this->addTextureSampler(&fYSampler);
@@ -228,8 +226,10 @@ public:
 
     RGBToYUVEffect(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace,
                    OutputChannels output)
-        : fColorSpace(colorSpace)
-        , fOutputChannels(output) {
+            // This could advertise kConstantOutputForConstantInput, but doesn't seem useful.
+            : INHERITED(kPreservesOpaqueInput_OptimizationFlag)
+            , fColorSpace(colorSpace)
+            , fOutputChannels(output) {
         this->initClassID<RGBToYUVEffect>();
         this->registerChildProcessor(std::move(rgbFP));
     }
index b9f31e613f009a5293b2d2780e2436487f98cf1f..e6d738dd59af8d42d905a71cc614bbdd5497ba76 100644 (file)
@@ -78,9 +78,7 @@ public:
     }
 
 private:
-    BigKeyProcessor() {
-        this->initClassID<BigKeyProcessor>();
-    }
+    BigKeyProcessor() : INHERITED(kNone_OptimizationFlags) { this->initClassID<BigKeyProcessor>(); }
     virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
                                        GrProcessorKeyBuilder* b) const override {
         GLBigKeyProcessor::GenKey(*this, caps, b);
@@ -122,7 +120,8 @@ private:
         typedef GrGLSLFragmentProcessor INHERITED;
     };
 
-    BlockInputFragmentProcessor(sk_sp<GrFragmentProcessor> child) {
+    BlockInputFragmentProcessor(sk_sp<GrFragmentProcessor> child)
+            : INHERITED(kNone_OptimizationFlags) {
         this->initClassID<BlockInputFragmentProcessor>();
         this->registerChildProcessor(std::move(child));
     }
index 59d134df745cbbf55e28083af03fb7569a1dba1a..aa34831d1ed013df880d2333a995f414d72234b3 100644 (file)
@@ -28,7 +28,8 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageStorageLoad, reporter, ctxInfo) {
 
     private:
         TestFP(sk_sp<GrTexture> texture, GrSLMemoryModel mm, GrSLRestrict restrict)
-                : fImageStorageAccess(std::move(texture), kRead_GrIOType, mm, restrict) {
+                : INHERITED(kNone_OptimizationFlags)
+                , fImageStorageAccess(std::move(texture), kRead_GrIOType, mm, restrict) {
             this->initClassID<TestFP>();
             this->addImageStorageAccess(&fImageStorageAccess);
         }
@@ -73,6 +74,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageStorageLoad, reporter, ctxInfo) {
         }
 
         ImageStorageAccess fImageStorageAccess;
+        typedef GrFragmentProcessor INHERITED;
     };
 
     static constexpr int kS = 256;
index 398e702f7e108b4b982f534966ef15ddba9a86ee..ff31e49619724a11fcf999baa6037d8120c8f7dc 100644 (file)
@@ -70,7 +70,7 @@ public:
 private:
     TestFP(const SkTArray<sk_sp<GrTexture>>& textures, const SkTArray<sk_sp<GrBuffer>>& buffers,
            const SkTArray<Image>& images)
-            : fSamplers(4), fBuffers(4), fImages(4) {
+            : INHERITED(kNone_OptimizationFlags), fSamplers(4), fBuffers(4), fImages(4) {
         for (const auto& texture : textures) {
             this->addTextureSampler(&fSamplers.emplace_back(texture.get()));
         }
@@ -83,7 +83,8 @@ private:
         }
     }
 
-    TestFP(sk_sp<GrFragmentProcessor> child) : fSamplers(4), fBuffers(4), fImages(4) {
+    TestFP(sk_sp<GrFragmentProcessor> child)
+            : INHERITED(kNone_OptimizationFlags), fSamplers(4), fBuffers(4), fImages(4) {
         this->registerChildProcessor(std::move(child));
     }
 
@@ -106,6 +107,7 @@ private:
     GrTAllocator<TextureSampler> fSamplers;
     GrTAllocator<BufferAccess> fBuffers;
     GrTAllocator<ImageStorageAccess> fImages;
+    typedef GrFragmentProcessor INHERITED;
 };
 }
 
@@ -230,4 +232,144 @@ DEF_GPUTEST_FOR_ALL_CONTEXTS(ProcessorRefTest, reporter, ctxInfo) {
         }
     }
 }
+
+// This test uses the random GrFragmentProcessor test factory, which relies on static initializers.
+#if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+
+static GrColor texel_color(int i, int j) {
+    SkASSERT((unsigned)i < 256 && (unsigned)j < 256);
+    GrColor color = GrColorPackRGBA(j, (uint8_t)(i + j), (uint8_t)(2 * j - i), i);
+    return GrPremulColor(color);
+}
+
+static GrColor4f texel_color4f(int i, int j) { return GrColor4f::FromGrColor(texel_color(i, j)); }
+
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ProcessorOptimizationValidationTest, reporter, ctxInfo) {
+    // This tests code under development but not used in skia lib. Leaving this disabled until
+    // some platform-specific issues are addressed.
+    if (1) {
+        return;
+    }
+    GrContext* context = ctxInfo.grContext();
+    using FPFactory = GrProcessorTestFactory<GrFragmentProcessor>;
+    SkRandom random;
+    sk_sp<GrRenderTargetContext> rtc = context->makeRenderTargetContext(
+            SkBackingFit::kExact, 256, 256, kRGBA_8888_GrPixelConfig, nullptr);
+    GrSurfaceDesc desc;
+    desc.fWidth = 256;
+    desc.fHeight = 256;
+    desc.fFlags = kRenderTarget_GrSurfaceFlag;
+    desc.fConfig = kRGBA_8888_GrPixelConfig;
+    sk_sp<GrTexture> tex0(context->textureProvider()->createTexture(desc, SkBudgeted::kYes));
+    desc.fConfig = kAlpha_8_GrPixelConfig;
+    sk_sp<GrTexture> tex1(context->textureProvider()->createTexture(desc, SkBudgeted::kYes));
+    GrTexture* textures[] = {tex0.get(), tex1.get()};
+    GrProcessorTestData testData(&random, context, rtc.get(), textures);
+
+    std::unique_ptr<GrColor> data(new GrColor[256 * 256]);
+    for (int y = 0; y < 256; ++y) {
+        for (int x = 0; x < 256; ++x) {
+            data.get()[256 * y + x] = texel_color(x, y);
+        }
+    }
+    desc.fConfig = kRGBA_8888_GrPixelConfig;
+    sk_sp<GrTexture> dataTexture(context->textureProvider()->createTexture(
+            desc, SkBudgeted::kYes, data.get(), 256 * sizeof(GrColor)));
+
+    // Because processors factories configure themselves in random ways, this is not exhaustive.
+    for (int i = 0; i < FPFactory::Count(); ++i) {
+        int timesToInvokeFactory = 5;
+        // Increase the number of attempts if the FP has child FPs since optimizations likely depend
+        // on child optimizations being present.
+        sk_sp<GrFragmentProcessor> fp = FPFactory::MakeIdx(i, &testData);
+        for (int j = 0; j < fp->numChildProcessors(); ++j) {
+            // This value made a reasonable trade off between time and coverage when this test was
+            // written.
+            timesToInvokeFactory *= FPFactory::Count() / 2;
+        }
+        for (int j = 0; j < timesToInvokeFactory; ++j) {
+            fp = FPFactory::MakeIdx(i, &testData);
+            if (!fp->hasConstantOutputForConstantInput() && !fp->preservesOpaqueInput() &&
+                !fp->modulatesInput()) {
+                continue;
+            }
+            GrPaint paint;
+            paint.addColorTextureProcessor(dataTexture.get(), nullptr, SkMatrix::I());
+            paint.addColorFragmentProcessor(fp);
+            paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
+            rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
+                          SkRect::MakeWH(256.f, 256.f));
+            memset(data.get(), 0x0, sizeof(GrColor) * 256 * 256);
+            rtc->readPixels(
+                    SkImageInfo::Make(256, 256, kRGBA_8888_SkColorType, kPremul_SkAlphaType),
+                    data.get(), 0, 0, 0);
+            bool passing = true;
+            if (0) {  // Useful to see what FPs are being tested.
+                SkString children;
+                for (int c = 0; c < fp->numChildProcessors(); ++c) {
+                    if (!c) {
+                        children.append("(");
+                    }
+                    children.append(fp->childProcessor(c).name());
+                    children.append(c == fp->numChildProcessors() - 1 ? ")" : ", ");
+                }
+                SkDebugf("%s %s\n", fp->name(), children.c_str());
+            }
+            for (int y = 0; y < 256 && passing; ++y) {
+                for (int x = 0; x < 256 && passing; ++x) {
+                    GrColor input = texel_color(x, y);
+                    GrColor output = data.get()[y * 256 + x];
+                    if (fp->modulatesInput()) {
+                        // A modulating processor is allowed to modulate either the input color or
+                        // just the input alpha.
+                        bool legalColorModulation =
+                                GrColorUnpackA(output) <= GrColorUnpackA(input) &&
+                                GrColorUnpackR(output) <= GrColorUnpackR(input) &&
+                                GrColorUnpackG(output) <= GrColorUnpackG(input) &&
+                                GrColorUnpackB(output) <= GrColorUnpackB(input);
+                        bool legalAlphaModulation =
+                                GrColorUnpackA(output) <= GrColorUnpackA(input) &&
+                                GrColorUnpackR(output) <= GrColorUnpackA(input) &&
+                                GrColorUnpackG(output) <= GrColorUnpackA(input) &&
+                                GrColorUnpackB(output) <= GrColorUnpackA(input);
+                        if (!legalColorModulation && !legalAlphaModulation) {
+                            ERRORF(reporter,
+                                   "\"Modulating\" processor %s made color/alpha value larger. "
+                                   "Input: 0x%0x8, Output: 0x%08x.",
+                                   fp->name(), input, output);
+                            passing = false;
+                        }
+                    }
+                    GrColor4f input4f = texel_color4f(x, y);
+                    GrColor4f output4f = GrColor4f::FromGrColor(output);
+                    GrColor4f expected4f;
+                    if (fp->hasConstantOutputForConstantInput(input4f, &expected4f)) {
+                        float rDiff = fabsf(output4f.fRGBA[0] - expected4f.fRGBA[0]);
+                        float gDiff = fabsf(output4f.fRGBA[1] - expected4f.fRGBA[1]);
+                        float bDiff = fabsf(output4f.fRGBA[2] - expected4f.fRGBA[2]);
+                        float aDiff = fabsf(output4f.fRGBA[3] - expected4f.fRGBA[3]);
+                        static constexpr float kTol = 3 / 255.f;
+                        if (rDiff > kTol || gDiff > kTol || bDiff > kTol || aDiff > kTol) {
+                            ERRORF(reporter,
+                                   "Processor %s claimed output for const input doesn't match "
+                                   "actual output.",
+                                   fp->name());
+                            passing = false;
+                        }
+                    }
+                    if (GrColorIsOpaque(input) && fp->preservesOpaqueInput() &&
+                        !GrColorIsOpaque(output)) {
+                        ERRORF(reporter,
+                               "Processor %s claimed opaqueness is preserved but it is not. Input: "
+                               "0x%0x8, Output: 0x%08x.",
+                               fp->name(), input, output);
+                        passing = false;
+                    }
+                }
+            }
+        }
+    }
+}
+#endif
+
 #endif