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