| /* |
| * Copyright 2012 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef GrGaussianConvolutionFragmentProcessor_DEFINED |
| #define GrGaussianConvolutionFragmentProcessor_DEFINED |
| |
| #include "include/core/SkM44.h" |
| #include "src/gpu/ganesh/GrFragmentProcessor.h" |
| #include "src/gpu/ganesh/GrProcessorUnitTest.h" |
| #include "src/gpu/ganesh/GrSamplerState.h" |
| |
| class GrSurfaceProxyView; |
| |
| /** |
| * A 1D Gaussian convolution effect. The kernel is computed as an array of 2 * half-width weights. |
| * Each texel is multiplied by it's weight and summed to determine the filtered color. The output |
| * color is set to a modulation of the filtered and input colors. |
| */ |
| class GrGaussianConvolutionFragmentProcessor : public GrFragmentProcessor { |
| public: |
| enum class Direction { kX, kY }; |
| |
| /** |
| * Convolve with a Gaussian kernel. Bounds limits the coords sampled by the effect along the |
| * axis indicated by Direction. The WrapMode is applied to the subset. If present, the |
| * pixelDomain indicates the domain of pixels that this effect will be called with. It should |
| * not account for outsetting due to the filter radius, this effect will handle that. It is |
| * assumed that the effect is only invoked at pixel centers within the pixelDomain, the |
| * effect will optimize for that, and may produce incorrect results if it is not the case. If |
| * pixelDomain is null then the effect will work correctly with any sample coordinates. |
| */ |
| static std::unique_ptr<GrFragmentProcessor> Make(GrSurfaceProxyView, |
| SkAlphaType, |
| Direction, |
| int halfWidth, |
| float gaussianSigma, |
| GrSamplerState::WrapMode, |
| const SkIRect& subset, |
| const SkIRect* pixelDomain, |
| const GrCaps&); |
| |
| const char* name() const override { return "GaussianConvolution"; } |
| |
| std::unique_ptr<GrFragmentProcessor> clone() const override { |
| return std::unique_ptr<GrFragmentProcessor>( |
| new GrGaussianConvolutionFragmentProcessor(*this)); |
| } |
| |
| // This was decided based on the min allowed value for the max texture |
| // samples per fragment program run in DX9SM2 (32). A sigma param of 4.0 |
| // on a blur filter gives a kernel width of 25 while a sigma of 5.0 |
| // would exceed a 32 wide kernel. |
| inline static constexpr int kMaxKernelRadius = 12; |
| |
| private: |
| class Impl; |
| |
| GrGaussianConvolutionFragmentProcessor(std::unique_ptr<GrFragmentProcessor>, |
| Direction, |
| int halfWidth, |
| float gaussianSigma); |
| |
| explicit GrGaussianConvolutionFragmentProcessor(const GrGaussianConvolutionFragmentProcessor&); |
| |
| #if GR_TEST_UTILS |
| SkString onDumpInfo() const override { |
| return SkStringPrintf("(dir=%s, radius=%d)", |
| Direction::kX == fDirection ? "X" : "Y", fRadius); |
| } |
| #endif |
| |
| std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override; |
| |
| void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override; |
| |
| bool onIsEqual(const GrFragmentProcessor&) const override; |
| |
| GR_DECLARE_FRAGMENT_PROCESSOR_TEST |
| |
| inline static const constexpr int kMaxKernelWidth = kMaxKernelRadius + 1; |
| |
| SkV2 fOffsetsAndKernel[kMaxKernelWidth]; |
| int fRadius; |
| Direction fDirection; |
| |
| using INHERITED = GrFragmentProcessor; |
| }; |
| |
| #endif |