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