/* * Copyright 2014 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef GrMatrixConvolutionEffect_DEFINED #define GrMatrixConvolutionEffect_DEFINED #include "src/gpu/GrFragmentProcessor.h" #include #include class GrMatrixConvolutionEffect : public GrFragmentProcessor { public: // A little bit less than the minimum # uniforms required by DX9SM2 (32). // Allows for a 5x5 kernel (or 28x1, for that matter). // Must be a multiple of 4, since we upload these in vec4s. inline static constexpr int kMaxUniformSize = 28; static std::unique_ptr Make(GrRecordingContext*, GrSurfaceProxyView srcView, const SkIRect& srcBounds, const SkISize& kernelSize, const SkScalar* kernel, SkScalar gain, SkScalar bias, const SkIPoint& kernelOffset, GrSamplerState::WrapMode, bool convolveAlpha, const GrCaps&); const char* name() const override { return "MatrixConvolution"; } SkString getShaderDfxInfo() const override; std::unique_ptr clone() const override; private: class Impl; /** * Small kernels are represented as float-arrays and uploaded as uniforms. * Large kernels go over the uniform limit and are uploaded as textures and sampled. * If Float16 textures are supported, we use those. Otherwise we use A8. */ class KernelWrapper { public: struct BiasAndGain { // Only used in A8 mode. Applied before any other math. float fBias; // Only used in A8 mode. Premultiplied in with user gain to save time. float fGain; bool operator==(const BiasAndGain&) const; }; using MakeResult = std::tuple>; static MakeResult Make(GrRecordingContext*, SkISize, const GrCaps&, const float* values); KernelWrapper() = default; KernelWrapper(const KernelWrapper& that) : fSize(that.fSize) { if (that.isSampled()) { fBiasAndGain = that.fBiasAndGain; } else { new (&fArray) std::array(that.fArray); } } bool isValid() const { return !fSize.isEmpty(); } SkISize size() const { return fSize; } bool isSampled() const { return fSize.area() > kMaxUniformSize; } const std::array& array() const { SkASSERT(!this->isSampled()); return fArray; } const BiasAndGain& biasAndGain() const { SkASSERT(this->isSampled()); return fBiasAndGain; } bool operator==(const KernelWrapper&) const; private: KernelWrapper(SkISize size) : fSize(size) { if (this->isSampled()) { fBiasAndGain = {0.f , 1.f}; } } SkISize fSize = {}; union { std::array fArray; BiasAndGain fBiasAndGain; }; }; GrMatrixConvolutionEffect(std::unique_ptr child, const KernelWrapper& kernel, std::unique_ptr kernelFP, SkScalar gain, SkScalar bias, const SkIPoint& kernelOffset, bool convolveAlpha); explicit GrMatrixConvolutionEffect(const GrMatrixConvolutionEffect&); std::unique_ptr onMakeProgramImpl() const override; void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; KernelWrapper fKernel; float fGain; float fBias; SkVector fKernelOffset; bool fConvolveAlpha; GR_DECLARE_FRAGMENT_PROCESSOR_TEST using INHERITED = GrFragmentProcessor; }; #endif