blob: 5716fed76db31b619ecc781f063561254dd8c9a6 [file] [log] [blame]
/*
* 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 "include/core/SkM44.h"
#include "src/gpu/ganesh/GrFragmentProcessor.h"
#include "src/gpu/ganesh/GrProcessorUnitTest.h"
#include "src/gpu/ganesh/GrSamplerState.h"
class GrSurfaceProxyView;
/**
* 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. Bounds limits the coords sampled by the effect along the
* axis indicated by Direction. The WrapMode is applied to the subset. If present, the
* pixelDomain indicates the domain of pixels that this effect will be called with. It should
* not account for outsetting due to the filter radius, this effect will handle that. It is
* assumed that the effect is only invoked at pixel centers within the pixelDomain, the
* effect will optimize for that, and may produce incorrect results if it is not the case. If
* pixelDomain is null then the effect will work correctly with any sample coordinates.
*/
static std::unique_ptr<GrFragmentProcessor> Make(GrSurfaceProxyView,
SkAlphaType,
Direction,
int halfWidth,
float gaussianSigma,
GrSamplerState::WrapMode,
const SkIRect& subset,
const SkIRect* pixelDomain,
const GrCaps&);
const char* name() const override { return "GaussianConvolution"; }
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.
inline static constexpr int kMaxKernelRadius = 12;
private:
class Impl;
GrGaussianConvolutionFragmentProcessor(std::unique_ptr<GrFragmentProcessor>,
Direction,
int halfWidth,
float gaussianSigma);
explicit GrGaussianConvolutionFragmentProcessor(const GrGaussianConvolutionFragmentProcessor&);
#if GR_TEST_UTILS
SkString onDumpInfo() const override {
return SkStringPrintf("(dir=%s, radius=%d)",
Direction::kX == fDirection ? "X" : "Y", fRadius);
}
#endif
std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override;
void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override;
bool onIsEqual(const GrFragmentProcessor&) const override;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
inline static const constexpr int kMaxKernelWidth = kMaxKernelRadius + 1;
SkV2 fOffsetsAndKernel[kMaxKernelWidth];
int fRadius;
Direction fDirection;
using INHERITED = GrFragmentProcessor;
};
#endif