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