| 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 GrGaussianConvolutionFragmentProcessor_DEFINED |
| 9 | #define GrGaussianConvolutionFragmentProcessor_DEFINED |
| 10 | |
| 11 | #include "src/gpu/GrFragmentProcessor.h" |
| 12 | |
| 13 | /** |
| 14 | * A 1D Gaussian convolution effect. The kernel is computed as an array of 2 * half-width weights. |
| 15 | * Each texel is multiplied by it's weight and summed to determine the filtered color. The output |
| 16 | * color is set to a modulation of the filtered and input colors. |
| 17 | */ |
| 18 | class GrGaussianConvolutionFragmentProcessor : public GrFragmentProcessor { |
| 19 | public: |
| 20 | enum class Direction { kX, kY }; |
| 21 | |
| 22 | /** |
| 23 | * Convolve with a Gaussian kernel. Bounds limits the coords sampled by the effect along the |
| 24 | * axis indicated by Direction. The WrapMode is applied to the subset. If present, the |
| 25 | * pixelDomain indicates the domain of pixels that this effect will be called with. It should |
| 26 | * not account for outsetting due to the filter radius, this effect will handle that. It is |
| 27 | * assumed that the effect is only invoked at pixel centers within the pixelDomain, the |
| 28 | * effect will optimize for that, and may produce incorrect results if it is not the case. If |
| 29 | * pixelDomain is null then the effect will work correctly with any sample coordinates. |
| 30 | */ |
| 31 | static std::unique_ptr<GrFragmentProcessor> Make(GrSurfaceProxyView, |
| 32 | SkAlphaType, |
| 33 | Direction, |
| 34 | int halfWidth, |
| 35 | float gaussianSigma, |
| 36 | GrSamplerState::WrapMode, |
| 37 | const SkIRect& subset, |
| 38 | const SkIRect* pixelDomain, |
| 39 | const GrCaps&); |
| 40 | |
| 41 | const char* name() const override { return "GaussianConvolution" ; } |
| 42 | |
| 43 | std::unique_ptr<GrFragmentProcessor> clone() const override { |
| 44 | return std::unique_ptr<GrFragmentProcessor>( |
| 45 | new GrGaussianConvolutionFragmentProcessor(*this)); |
| 46 | } |
| 47 | |
| 48 | // This was decided based on the min allowed value for the max texture |
| 49 | // samples per fragment program run in DX9SM2 (32). A sigma param of 4.0 |
| 50 | // on a blur filter gives a kernel width of 25 while a sigma of 5.0 |
| 51 | // would exceed a 32 wide kernel. |
| 52 | static constexpr int kMaxKernelRadius = 12; |
| 53 | |
| 54 | private: |
| 55 | GrGaussianConvolutionFragmentProcessor(std::unique_ptr<GrFragmentProcessor>, |
| 56 | Direction, |
| 57 | int halfWidth, |
| 58 | float gaussianSigma); |
| 59 | |
| 60 | explicit GrGaussianConvolutionFragmentProcessor(const GrGaussianConvolutionFragmentProcessor&); |
| 61 | |
| 62 | #if GR_TEST_UTILS |
| 63 | SkString onDumpInfo() const override { |
| 64 | return SkStringPrintf("(dir=%s, radius=%d)" , |
| 65 | Direction::kX == fDirection ? "X" : "Y" , fRadius); |
| 66 | } |
| 67 | #endif |
| 68 | |
| 69 | GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; |
| 70 | |
| 71 | void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; |
| 72 | |
| 73 | bool onIsEqual(const GrFragmentProcessor&) const override; |
| 74 | |
| 75 | GR_DECLARE_FRAGMENT_PROCESSOR_TEST |
| 76 | |
| 77 | static constexpr int kMaxKernelWidth = 2*kMaxKernelRadius + 1; |
| 78 | |
| 79 | // The array size must be a multiple of 4 because we pass it as an array of float4 uniform |
| 80 | // values. |
| 81 | float fKernel[SkAlign4(kMaxKernelWidth)]; |
| 82 | int fRadius; |
| 83 | Direction fDirection; |
| 84 | |
| 85 | class Impl; |
| 86 | |
| 87 | typedef GrFragmentProcessor INHERITED; |
| 88 | }; |
| 89 | |
| 90 | #endif |
| 91 | |