1 /* 2 * Copyright 2014 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 GrMatrixConvolutionEffect_DEFINED 9 #define GrMatrixConvolutionEffect_DEFINED 10 11 #include "src/gpu/GrFragmentProcessor.h" 12 #include <array> 13 #include <new> 14 15 class GrMatrixConvolutionEffect : public GrFragmentProcessor { 16 public: 17 // A little bit less than the minimum # uniforms required by DX9SM2 (32). 18 // Allows for a 5x5 kernel (or 28x1, for that matter). 19 // Must be a multiple of 4, since we upload these in vec4s. 20 inline static constexpr int kMaxUniformSize = 28; 21 22 static std::unique_ptr<GrFragmentProcessor> Make(GrRecordingContext*, 23 GrSurfaceProxyView srcView, 24 const SkIRect& srcBounds, 25 const SkISize& kernelSize, 26 const SkScalar* kernel, 27 SkScalar gain, 28 SkScalar bias, 29 const SkIPoint& kernelOffset, 30 GrSamplerState::WrapMode, 31 bool convolveAlpha, 32 const GrCaps&); 33 34 const char* name() const override { return "MatrixConvolution"; } 35 36 SkString getShaderDfxInfo() const override; 37 38 std::unique_ptr<GrFragmentProcessor> clone() const override; 39 40 private: 41 class Impl; 42 43 /** 44 * Small kernels are represented as float-arrays and uploaded as uniforms. 45 * Large kernels go over the uniform limit and are uploaded as textures and sampled. 46 * If Float16 textures are supported, we use those. Otherwise we use A8. 47 */ 48 class KernelWrapper { 49 public: 50 struct BiasAndGain { 51 // Only used in A8 mode. Applied before any other math. 52 float fBias; 53 // Only used in A8 mode. Premultiplied in with user gain to save time. 54 float fGain; 55 bool operator==(const BiasAndGain&) const; 56 }; 57 using MakeResult = std::tuple<KernelWrapper, std::unique_ptr<GrFragmentProcessor>>; 58 static MakeResult Make(GrRecordingContext*, SkISize, const GrCaps&, const float* values); 59 60 KernelWrapper() = default; KernelWrapper(const KernelWrapper& that)61 KernelWrapper(const KernelWrapper& that) : fSize(that.fSize) { 62 if (that.isSampled()) { 63 fBiasAndGain = that.fBiasAndGain; 64 } else { 65 new (&fArray) std::array<float, kMaxUniformSize>(that.fArray); 66 } 67 } 68 isValid() const69 bool isValid() const { return !fSize.isEmpty(); } size() const70 SkISize size() const { return fSize; } isSampled() const71 bool isSampled() const { return fSize.area() > kMaxUniformSize; } array() const72 const std::array<float, kMaxUniformSize>& array() const { 73 SkASSERT(!this->isSampled()); 74 return fArray; 75 } biasAndGain() const76 const BiasAndGain& biasAndGain() const { 77 SkASSERT(this->isSampled()); 78 return fBiasAndGain; 79 } 80 bool operator==(const KernelWrapper&) const; 81 82 private: KernelWrapper(SkISize size)83 KernelWrapper(SkISize size) : fSize(size) { 84 if (this->isSampled()) { 85 fBiasAndGain = {0.f , 1.f}; 86 } 87 } 88 89 SkISize fSize = {}; 90 union { 91 std::array<float, kMaxUniformSize> fArray; 92 BiasAndGain fBiasAndGain; 93 }; 94 }; 95 96 GrMatrixConvolutionEffect(std::unique_ptr<GrFragmentProcessor> child, 97 const KernelWrapper& kernel, 98 std::unique_ptr<GrFragmentProcessor> kernelFP, 99 SkScalar gain, 100 SkScalar bias, 101 const SkIPoint& kernelOffset, 102 bool convolveAlpha); 103 104 explicit GrMatrixConvolutionEffect(const GrMatrixConvolutionEffect&); 105 106 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override; 107 108 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 109 110 bool onIsEqual(const GrFragmentProcessor&) const override; 111 112 KernelWrapper fKernel; 113 float fGain; 114 float fBias; 115 SkVector fKernelOffset; 116 bool fConvolveAlpha; 117 118 GR_DECLARE_FRAGMENT_PROCESSOR_TEST 119 120 using INHERITED = GrFragmentProcessor; 121 }; 122 123 #endif 124