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