blob: 469e287d70697dd910817ad81cc0c3c54ae8cb09 [file] [log] [blame]
Brian Salomonaee504b2017-01-24 12:29:36 -05001/*
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
Brian Salomonb133ffe2017-07-27 11:53:21 -040011#include "GrCoordTransform.h"
12#include "GrFragmentProcessor.h"
wutao039a7c72017-06-30 10:44:45 -070013#include "GrTextureDomain.h"
Brian Salomonaee504b2017-01-24 12:29:36 -050014
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 */
Brian Salomonb133ffe2017-07-27 11:53:21 -040020class GrGaussianConvolutionFragmentProcessor : public GrFragmentProcessor {
Brian Salomonaee504b2017-01-24 12:29:36 -050021public:
Brian Salomonb133ffe2017-07-27 11:53:21 -040022 enum class Direction { kX, kY };
23
Brian Salomonaee504b2017-01-24 12:29:36 -050024 /// Convolve with a Gaussian kernel
Brian Salomonaff329b2017-08-11 09:40:37 -040025 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));
Robert Phillips40fd7c92017-01-30 08:06:27 -050033 }
34
Brian Salomonaee504b2017-01-24 12:29:36 -050035 const float* kernel() const { return fKernel; }
36
Robert Phillips08c5ec72017-01-30 12:26:47 -050037 const int* bounds() const { return fBounds; }
wutao039a7c72017-06-30 10:44:45 -070038 bool useBounds() const { return fMode != GrTextureDomain::kIgnore_Mode; }
Brian Salomonb133ffe2017-07-27 11:53:21 -040039 int radius() const { return fRadius; }
40 int width() const { return 2 * fRadius + 1; }
41 Direction direction() const { return fDirection; }
wutao039a7c72017-06-30 10:44:45 -070042
43 GrTextureDomain::Mode mode() const { return fMode; }
Brian Salomonaee504b2017-01-24 12:29:36 -050044
45 const char* name() const override { return "GaussianConvolution"; }
46
Brian Osman9a390ac2018-11-12 09:47:48 -050047#ifdef SK_DEBUG
Robert Phillipsce3c28f2018-07-18 13:52:40 -040048 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 }
Brian Osman9a390ac2018-11-12 09:47:48 -050056#endif
Robert Phillipsce3c28f2018-07-18 13:52:40 -040057
Brian Salomonaff329b2017-08-11 09:40:37 -040058 std::unique_ptr<GrFragmentProcessor> clone() const override {
59 return std::unique_ptr<GrFragmentProcessor>(
60 new GrGaussianConvolutionFragmentProcessor(*this));
Brian Salomon3f6f9652017-07-28 07:34:05 -040061 }
62
Brian Salomonaee504b2017-01-24 12:29:36 -050063 // 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
72private:
73 /// Convolve with a Gaussian kernel
Robert Phillipsfbcef6e2017-06-15 12:07:18 -040074 GrGaussianConvolutionFragmentProcessor(sk_sp<GrTextureProxy>, Direction,
wutao039a7c72017-06-30 10:44:45 -070075 int halfWidth, float gaussianSigma,
76 GrTextureDomain::Mode mode, int bounds[2]);
Robert Phillips40fd7c92017-01-30 08:06:27 -050077
Brian Salomon3f6f9652017-07-28 07:34:05 -040078 explicit GrGaussianConvolutionFragmentProcessor(const GrGaussianConvolutionFragmentProcessor&);
79
Brian Salomonaee504b2017-01-24 12:29:36 -050080 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
81
82 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
83
84 bool onIsEqual(const GrFragmentProcessor&) const override;
85
Brian Salomonf7dcd762018-07-30 14:48:15 -040086 const TextureSampler& onTextureSampler(int) const override { return fTextureSampler; }
87
Brian Salomon0c26a9d2017-07-06 10:09:38 -040088 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Brian Salomonaee504b2017-01-24 12:29:36 -050089
Robert Phillipsce3c28f2018-07-18 13:52:40 -040090 GrCoordTransform fCoordTransform;
91 TextureSampler fTextureSampler;
Brian Salomonaee504b2017-01-24 12:29:36 -050092 // 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.
Robert Phillipsce3c28f2018-07-18 13:52:40 -040094 float fKernel[kMaxKernelWidth];
95 int fBounds[2];
96 int fRadius;
97 Direction fDirection;
wutao039a7c72017-06-30 10:44:45 -070098 GrTextureDomain::Mode fMode;
Brian Salomonaee504b2017-01-24 12:29:36 -050099
Brian Salomonb133ffe2017-07-27 11:53:21 -0400100 typedef GrFragmentProcessor INHERITED;
Brian Salomonaee504b2017-01-24 12:29:36 -0500101};
102
103#endif