180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/*
280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2012 Google Inc.
380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *
480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be
580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file.
680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */
780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#ifndef GrConvolutionEffect_DEFINED
980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#define GrConvolutionEffect_DEFINED
1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "Gr1DKernelEffect.h"
1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruclass GrGLConvolutionEffect;
1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/**
1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * A convolution effect. The kernel is specified as an array of 2 * half-width
1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * + 1 weights. Each texel is multiplied by it's weight and summed to determine
1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * the output color. The output color is modulated by the input color.
1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */
2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruclass GrConvolutionEffect : public Gr1DKernelEffect {
2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querupublic:
2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    /// Convolve with an arbitrary user-specified kernel
2558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    static GrEffectRef* Create(GrTexture* tex,
2658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                               Direction dir,
2758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                               int halfWidth,
2858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                               const float* kernel,
29e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger                               bool useBounds,
30e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger                               float bounds[2]) {
31d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        AutoEffectUnref effect(SkNEW_ARGS(GrConvolutionEffect, (tex,
32d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                                                                dir,
33d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                                                                halfWidth,
3458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                                                                kernel,
35e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger                                                                useBounds,
36e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger                                                                bounds)));
37d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        return CreateEffectRef(effect);
38d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    }
3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
40363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    /// Convolve with a Gaussian kernel
41d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    static GrEffectRef* CreateGaussian(GrTexture* tex,
42d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                                       Direction dir,
43d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                                       int halfWidth,
4458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                                       float gaussianSigma,
45e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger                                       bool useBounds,
46e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger                                       float bounds[2]) {
47d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        AutoEffectUnref effect(SkNEW_ARGS(GrConvolutionEffect, (tex,
48d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                                                                dir,
49d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                                                                halfWidth,
5058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                                                                gaussianSigma,
51e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger                                                                useBounds,
52e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger                                                                bounds)));
53d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        return CreateEffectRef(effect);
54d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    }
55d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    virtual ~GrConvolutionEffect();
5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    const float* kernel() const { return fKernel; }
5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
60e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger    const float* bounds() const { return fBounds; }
61e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger    bool useBounds() const { return fUseBounds; }
6258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    static const char* Name() { return "Convolution"; }
6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
65363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    typedef GrGLConvolutionEffect GLEffect;
6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
67363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
68d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
69096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    virtual void getConstantColorComponents(GrColor*, uint32_t* validFlags) const {
70d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        // If the texture was opaque we could know that the output color if we knew the sum of the
71d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        // kernel values.
72d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        *validFlags = 0;
73d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    }
7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    enum {
7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // This was decided based on the min allowed value for the max texture
7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // samples per fragment program run in DX9SM2 (32). A sigma param of 4.0
7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // on a blur filter gives a kernel width of 25 while a sigma of 5.0
7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // would exceed a 32 wide kernel.
8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        kMaxKernelRadius = 12,
8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // With a C++11 we could have a constexpr version of WidthFromRadius()
8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // and not have to duplicate this calculation.
8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        kMaxKernelWidth = 2 * kMaxKernelRadius + 1,
8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    };
8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruprotected:
8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    float fKernel[kMaxKernelWidth];
89e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger    bool fUseBounds;
90e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger    float fBounds[2];
9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruprivate:
93d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    GrConvolutionEffect(GrTexture*, Direction,
9458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                        int halfWidth,
9558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                        const float* kernel,
96e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger                        bool useBounds,
97e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger                        float bounds[2]);
98d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
99d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    /// Convolve with a Gaussian kernel
100d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    GrConvolutionEffect(GrTexture*, Direction,
101d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                        int halfWidth,
10258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                        float gaussianSigma,
103e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger                        bool useBounds,
104e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger                        float bounds[2]);
105d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
106d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
107d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
108363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    GR_DECLARE_EFFECT_TEST;
10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    typedef Gr1DKernelEffect INHERITED;
11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru};
11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
114