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