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 "GrCoordTransform.h" 12 #include "GrFragmentProcessor.h" 13 #include "GrTextureDomain.h" 14 15 /** 16 * A 1D Gaussian convolution effect. The kernel is computed as an array of 2 * half-width weights. 17 * Each texel is multiplied by it's weight and summed to determine the filtered color. The output 18 * color is set to a modulation of the filtered and input colors. 19 */ 20 class GrGaussianConvolutionFragmentProcessor : public GrFragmentProcessor { 21 public: 22 enum class Direction { kX, kY }; 23 24 /// Convolve with a Gaussian kernel Make(sk_sp<GrTextureProxy> proxy,Direction dir,int halfWidth,float gaussianSigma,GrTextureDomain::Mode mode,int * bounds)25 static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy, 26 Direction dir, 27 int halfWidth, 28 float gaussianSigma, 29 GrTextureDomain::Mode mode, 30 int* bounds) { 31 return std::unique_ptr<GrFragmentProcessor>(new GrGaussianConvolutionFragmentProcessor( 32 std::move(proxy), dir, halfWidth, gaussianSigma, mode, bounds)); 33 } 34 kernel()35 const float* kernel() const { return fKernel; } 36 bounds()37 const int* bounds() const { return fBounds; } useBounds()38 bool useBounds() const { return fMode != GrTextureDomain::kIgnore_Mode; } radius()39 int radius() const { return fRadius; } width()40 int width() const { return 2 * fRadius + 1; } direction()41 Direction direction() const { return fDirection; } 42 mode()43 GrTextureDomain::Mode mode() const { return fMode; } 44 name()45 const char* name() const override { return "GaussianConvolution"; } 46 47 #ifdef SK_DEBUG dumpInfo()48 SkString dumpInfo() const override { 49 SkString str; 50 str.appendf("dir: %s radius: %d bounds: [%d %d]", 51 Direction::kX == fDirection ? "X" : "Y", 52 fRadius, 53 fBounds[0], fBounds[1]); 54 return str; 55 } 56 #endif 57 clone()58 std::unique_ptr<GrFragmentProcessor> clone() const override { 59 return std::unique_ptr<GrFragmentProcessor>( 60 new GrGaussianConvolutionFragmentProcessor(*this)); 61 } 62 63 // This was decided based on the min allowed value for the max texture 64 // samples per fragment program run in DX9SM2 (32). A sigma param of 4.0 65 // on a blur filter gives a kernel width of 25 while a sigma of 5.0 66 // would exceed a 32 wide kernel. 67 static const int kMaxKernelRadius = 12; 68 // With a C++11 we could have a constexpr version of WidthFromRadius() 69 // and not have to duplicate this calculation. 70 static const int kMaxKernelWidth = 2 * kMaxKernelRadius + 1; 71 72 private: 73 /// Convolve with a Gaussian kernel 74 GrGaussianConvolutionFragmentProcessor(sk_sp<GrTextureProxy>, Direction, 75 int halfWidth, float gaussianSigma, 76 GrTextureDomain::Mode mode, int bounds[2]); 77 78 explicit GrGaussianConvolutionFragmentProcessor(const GrGaussianConvolutionFragmentProcessor&); 79 80 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; 81 82 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 83 84 bool onIsEqual(const GrFragmentProcessor&) const override; 85 onTextureSampler(int)86 const TextureSampler& onTextureSampler(int) const override { return fTextureSampler; } 87 88 GR_DECLARE_FRAGMENT_PROCESSOR_TEST 89 90 GrCoordTransform fCoordTransform; 91 TextureSampler fTextureSampler; 92 // TODO: Inline the kernel constants into the generated shader code. This may involve pulling 93 // some of the logic from SkGpuBlurUtils into this class related to radius/sigma calculations. 94 float fKernel[kMaxKernelWidth]; 95 int fBounds[2]; 96 int fRadius; 97 Direction fDirection; 98 GrTextureDomain::Mode fMode; 99 100 typedef GrFragmentProcessor INHERITED; 101 }; 102 103 #endif 104