1 /*
2  * Copyright 2012 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef GrConvolutionEffect_DEFINED
9 #define GrConvolutionEffect_DEFINED
10 
11 #include "Gr1DKernelEffect.h"
12 #include "GrInvariantOutput.h"
13 
14 /**
15  * A convolution effect. The kernel is specified as an array of 2 * half-width
16  * + 1 weights. Each texel is multiplied by it's weight and summed to determine
17  * the output color. The output color is modulated by the input color.
18  */
19 class GrConvolutionEffect : public Gr1DKernelEffect {
20 
21 public:
22 
23     /// Convolve with an arbitrary user-specified kernel
Create(GrTexture * tex,Direction dir,int halfWidth,const float * kernel,bool useBounds,float bounds[2])24     static GrFragmentProcessor* Create(GrTexture* tex,
25                                        Direction dir,
26                                        int halfWidth,
27                                        const float* kernel,
28                                        bool useBounds,
29                                        float bounds[2]) {
30         return SkNEW_ARGS(GrConvolutionEffect, (tex,
31                                                 dir,
32                                                 halfWidth,
33                                                 kernel,
34                                                 useBounds,
35                                                 bounds));
36     }
37 
38     /// Convolve with a Gaussian kernel
CreateGaussian(GrTexture * tex,Direction dir,int halfWidth,float gaussianSigma,bool useBounds,float bounds[2])39     static GrFragmentProcessor* CreateGaussian(GrTexture* tex,
40                                                Direction dir,
41                                                int halfWidth,
42                                                float gaussianSigma,
43                                                bool useBounds,
44                                                float bounds[2]) {
45         return SkNEW_ARGS(GrConvolutionEffect, (tex,
46                                                 dir,
47                                                 halfWidth,
48                                                 gaussianSigma,
49                                                 useBounds,
50                                                 bounds));
51     }
52 
53     virtual ~GrConvolutionEffect();
54 
kernel()55     const float* kernel() const { return fKernel; }
56 
bounds()57     const float* bounds() const { return fBounds; }
useBounds()58     bool useBounds() const { return fUseBounds; }
59 
name()60     const char* name() const override { return "Convolution"; }
61 
62     void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
63 
64     GrGLFragmentProcessor* createGLInstance() const override;
65 
66     enum {
67         // This was decided based on the min allowed value for the max texture
68         // samples per fragment program run in DX9SM2 (32). A sigma param of 4.0
69         // on a blur filter gives a kernel width of 25 while a sigma of 5.0
70         // would exceed a 32 wide kernel.
71         kMaxKernelRadius = 12,
72         // With a C++11 we could have a constexpr version of WidthFromRadius()
73         // and not have to duplicate this calculation.
74         kMaxKernelWidth = 2 * kMaxKernelRadius + 1,
75     };
76 
77 protected:
78 
79     float fKernel[kMaxKernelWidth];
80     bool fUseBounds;
81     float fBounds[2];
82 
83 private:
84     GrConvolutionEffect(GrTexture*, Direction,
85                         int halfWidth,
86                         const float* kernel,
87                         bool useBounds,
88                         float bounds[2]);
89 
90     /// Convolve with a Gaussian kernel
91     GrConvolutionEffect(GrTexture*, Direction,
92                         int halfWidth,
93                         float gaussianSigma,
94                         bool useBounds,
95                         float bounds[2]);
96 
97     bool onIsEqual(const GrFragmentProcessor&) const override;
98 
onComputeInvariantOutput(GrInvariantOutput * inout)99     void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
100         // If the texture was opaque we could know that the output color if we knew the sum of the
101         // kernel values.
102         inout->mulByUnknownFourComponents();
103     }
104 
105     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
106 
107     typedef Gr1DKernelEffect INHERITED;
108 };
109 
110 #endif
111