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 name()34 const char* name() const override { return "MatrixConvolution"; } 35 36 std::unique_ptr<GrFragmentProcessor> clone() const override; 37 38 private: 39 class Impl; 40 41 /** 42 * Small kernels are represented as float-arrays and uploaded as uniforms. 43 * Large kernels go over the uniform limit and are uploaded as textures and sampled. 44 * If Float16 textures are supported, we use those. Otherwise we use A8. 45 */ 46 class KernelWrapper { 47 public: 48 struct BiasAndGain { 49 // Only used in A8 mode. Applied before any other math. 50 float fBias; 51 // Only used in A8 mode. Premultiplied in with user gain to save time. 52 float fGain; 53 bool operator==(const BiasAndGain&) const; 54 }; 55 using MakeResult = std::tuple<KernelWrapper, std::unique_ptr<GrFragmentProcessor>>; 56 static MakeResult Make(GrRecordingContext*, SkISize, const GrCaps&, const float* values); 57 58 KernelWrapper() = default; KernelWrapper(const KernelWrapper & that)59 KernelWrapper(const KernelWrapper& that) : fSize(that.fSize) { 60 if (that.isSampled()) { 61 fBiasAndGain = that.fBiasAndGain; 62 } else { 63 new (&fArray) std::array<float, kMaxUniformSize>(that.fArray); 64 } 65 } 66 isValid()67 bool isValid() const { return !fSize.isEmpty(); } size()68 SkISize size() const { return fSize; } isSampled()69 bool isSampled() const { return fSize.area() > kMaxUniformSize; } array()70 const std::array<float, kMaxUniformSize>& array() const { 71 SkASSERT(!this->isSampled()); 72 return fArray; 73 } biasAndGain()74 const BiasAndGain& biasAndGain() const { 75 SkASSERT(this->isSampled()); 76 return fBiasAndGain; 77 } 78 bool operator==(const KernelWrapper&) const; 79 80 private: KernelWrapper(SkISize size)81 KernelWrapper(SkISize size) : fSize(size) { 82 if (this->isSampled()) { 83 fBiasAndGain = {0.f , 1.f}; 84 } 85 } 86 87 SkISize fSize = {}; 88 union { 89 std::array<float, kMaxUniformSize> fArray; 90 BiasAndGain fBiasAndGain; 91 }; 92 }; 93 94 GrMatrixConvolutionEffect(std::unique_ptr<GrFragmentProcessor> child, 95 const KernelWrapper& kernel, 96 std::unique_ptr<GrFragmentProcessor> kernelFP, 97 SkScalar gain, 98 SkScalar bias, 99 const SkIPoint& kernelOffset, 100 bool convolveAlpha); 101 102 explicit GrMatrixConvolutionEffect(const GrMatrixConvolutionEffect&); 103 104 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override; 105 106 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 107 108 bool onIsEqual(const GrFragmentProcessor&) const override; 109 110 KernelWrapper fKernel; 111 float fGain; 112 float fBias; 113 SkVector fKernelOffset; 114 bool fConvolveAlpha; 115 116 GR_DECLARE_FRAGMENT_PROCESSOR_TEST 117 118 using INHERITED = GrFragmentProcessor; 119 }; 120 121 #endif 122