/* * 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 "GrCoordTransform.h" #include "GrFragmentProcessor.h" #include "GrTextureDomain.h" /** * 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 static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy, Direction dir, int halfWidth, float gaussianSigma, GrTextureDomain::Mode mode, int* bounds) { return std::unique_ptr<GrFragmentProcessor>(new GrGaussianConvolutionFragmentProcessor( std::move(proxy), dir, halfWidth, gaussianSigma, mode, bounds)); } const float* kernel() const { return fKernel; } const int* bounds() const { return fBounds; } bool useBounds() const { return fMode != GrTextureDomain::kIgnore_Mode; } int radius() const { return fRadius; } int width() const { return 2 * fRadius + 1; } Direction direction() const { return fDirection; } GrTextureDomain::Mode mode() const { return fMode; } const char* name() const override { return "GaussianConvolution"; } #ifdef SK_DEBUG SkString dumpInfo() const override { SkString str; str.appendf("dir: %s radius: %d bounds: [%d %d]", Direction::kX == fDirection ? "X" : "Y", fRadius, fBounds[0], fBounds[1]); return str; } #endif 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. static const int kMaxKernelRadius = 12; // With a C++11 we could have a constexpr version of WidthFromRadius() // and not have to duplicate this calculation. static const int kMaxKernelWidth = 2 * kMaxKernelRadius + 1; private: /// Convolve with a Gaussian kernel GrGaussianConvolutionFragmentProcessor(sk_sp<GrTextureProxy>, Direction, int halfWidth, float gaussianSigma, GrTextureDomain::Mode mode, int bounds[2]); explicit GrGaussianConvolutionFragmentProcessor(const GrGaussianConvolutionFragmentProcessor&); GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; const TextureSampler& onTextureSampler(int) const override { return fTextureSampler; } GR_DECLARE_FRAGMENT_PROCESSOR_TEST GrCoordTransform fCoordTransform; TextureSampler fTextureSampler; // TODO: Inline the kernel constants into the generated shader code. This may involve pulling // some of the logic from SkGpuBlurUtils into this class related to radius/sigma calculations. float fKernel[kMaxKernelWidth]; int fBounds[2]; int fRadius; Direction fDirection; GrTextureDomain::Mode fMode; typedef GrFragmentProcessor INHERITED; }; #endif