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