OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrConvolutionEffect.h" | 8 #include "GrConvolutionEffect.h" |
9 #include "gl/GrGLProcessor.h" | 9 #include "gl/GrGLProcessor.h" |
10 #include "gl/GrGLTexture.h" | 10 #include "gl/GrGLTexture.h" |
11 #include "gl/builders/GrGLProgramBuilder.h" | 11 #include "gl/builders/GrGLProgramBuilder.h" |
12 | 12 |
13 // For brevity | 13 // For brevity |
14 typedef GrGLProgramDataManager::UniformHandle UniformHandle; | 14 typedef GrGLProgramDataManager::UniformHandle UniformHandle; |
15 | 15 |
16 /** | |
17 * Base class with shared functionality for GrGLBoundedConvolutionEffect and | |
18 * GrGLBilerpConvolutionEffect. | |
19 */ | |
16 class GrGLConvolutionEffect : public GrGLFragmentProcessor { | 20 class GrGLConvolutionEffect : public GrGLFragmentProcessor { |
17 public: | 21 public: |
18 GrGLConvolutionEffect(const GrProcessor&); | 22 GrGLConvolutionEffect(const GrProcessor&); |
23 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessor KeyBuilder*); | |
24 | |
25 protected: | |
26 int radius() const { return fRadius; } | |
27 int width() const { return Gr1DKernelEffect::WidthFromRadius(fRadius); } | |
28 Gr1DKernelEffect::Direction direction() const { return fDirection; } | |
29 void getImageIncrement(const GrConvolutionEffect&, float (*)[2]) const; | |
30 | |
31 private: | |
32 int fRadius; | |
33 Gr1DKernelEffect::Direction fDirection; | |
34 | |
35 typedef GrGLFragmentProcessor INHERITED; | |
36 }; | |
37 | |
38 GrGLConvolutionEffect::GrGLConvolutionEffect(const GrProcessor& processor) { | |
39 const GrConvolutionEffect& c = processor.cast<GrConvolutionEffect>(); | |
40 fRadius = c.radius(); | |
41 fDirection = c.direction(); | |
42 } | |
43 | |
44 void GrGLConvolutionEffect::GenKey(const GrProcessor& processor, | |
45 const GrGLSLCaps&, | |
46 GrProcessorKeyBuilder* b) { | |
47 const GrConvolutionEffect& conv = processor.cast<GrConvolutionEffect>(); | |
48 uint32_t key = conv.radius(); | |
49 key <<= 2; | |
50 if (conv.useBounds()) { | |
51 key |= 0x2; | |
52 key |= GrConvolutionEffect::kY_Direction == conv.direction() ? 0x1 : 0x0 ; | |
53 } | |
54 b->add32(key); | |
55 } | |
56 | |
57 void GrGLConvolutionEffect::getImageIncrement(const GrConvolutionEffect& conv, | |
58 float (*imageIncrement)[2]) const { | |
59 GrTexture& texture = *conv.texture(0); | |
60 (*imageIncrement)[0] = (*imageIncrement)[1] = 0; | |
61 float ySign = texture.origin() != kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f; | |
62 switch (conv.direction()) { | |
63 case Gr1DKernelEffect::kX_Direction: | |
64 (*imageIncrement)[0] = 1.0f / texture.width(); | |
65 break; | |
66 case Gr1DKernelEffect::kY_Direction: | |
67 (*imageIncrement)[1] = ySign / texture.height(); | |
68 break; | |
69 default: | |
70 SkFAIL("Unknown filter direction."); | |
71 } | |
72 } | |
73 | |
74 /////////////////////////////////////////////////////////////////////////////// | |
75 | |
76 /** | |
77 * Applies a convolution effect which restricts samples to the provided bounds | |
78 * using shader logic. | |
79 */ | |
80 class GrGLBoundedConvolutionEffect : public GrGLConvolutionEffect { | |
81 public: | |
82 GrGLBoundedConvolutionEffect(const GrProcessor& processor) : INHERITED(proce ssor) {} | |
19 | 83 |
20 virtual void emitCode(GrGLFPBuilder*, | 84 virtual void emitCode(GrGLFPBuilder*, |
21 const GrFragmentProcessor&, | 85 const GrFragmentProcessor&, |
22 const char* outputColor, | 86 const char* outputColor, |
23 const char* inputColor, | 87 const char* inputColor, |
24 const TransformedCoordsArray&, | 88 const TransformedCoordsArray&, |
25 const TextureSamplerArray&) override; | 89 const TextureSamplerArray&) override; |
26 | 90 |
27 void setData(const GrGLProgramDataManager& pdman, const GrProcessor&) overri de; | 91 void setData(const GrGLProgramDataManager& pdman, const GrProcessor&) overri de; |
28 | 92 |
29 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessor KeyBuilder*); | |
30 | |
31 private: | 93 private: |
32 int width() const { return Gr1DKernelEffect::WidthFromRadius(fRadius); } | |
33 bool useBounds() const { return fUseBounds; } | |
34 Gr1DKernelEffect::Direction direction() const { return fDirection; } | |
35 | |
36 int fRadius; | |
37 bool fUseBounds; | |
38 Gr1DKernelEffect::Direction fDirection; | |
39 UniformHandle fKernelUni; | 94 UniformHandle fKernelUni; |
40 UniformHandle fImageIncrementUni; | 95 UniformHandle fImageIncrementUni; |
41 UniformHandle fBoundsUni; | 96 UniformHandle fBoundsUni; |
42 | 97 |
43 typedef GrGLFragmentProcessor INHERITED; | 98 typedef GrGLConvolutionEffect INHERITED; |
44 }; | 99 }; |
45 | 100 |
46 GrGLConvolutionEffect::GrGLConvolutionEffect(const GrProcessor& processor) { | 101 void GrGLBoundedConvolutionEffect::emitCode(GrGLFPBuilder* builder, |
47 const GrConvolutionEffect& c = processor.cast<GrConvolutionEffect>(); | 102 const GrFragmentProcessor& processor , |
48 fRadius = c.radius(); | 103 const char* outputColor, |
49 fUseBounds = c.useBounds(); | 104 const char* inputColor, |
50 fDirection = c.direction(); | 105 const TransformedCoordsArray& coords , |
51 } | 106 const TextureSamplerArray& samplers) { |
107 fImageIncrementUni = | |
108 builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec2f_GrS LType, | |
109 kDefault_GrSLPrecision, "ImageIncrement"); | |
52 | 110 |
53 void GrGLConvolutionEffect::emitCode(GrGLFPBuilder* builder, | 111 fBoundsUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, k Vec2f_GrSLType, |
54 const GrFragmentProcessor&, | 112 kDefault_GrSLPrecision, "Bounds"); |
55 const char* outputColor, | 113 |
56 const char* inputColor, | 114 fKernelUni = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibili ty, kFloat_GrSLType, |
57 const TransformedCoordsArray& coords, | 115 kDefault_GrSLPrecision, "Kernel", this ->width()); |
58 const TextureSamplerArray& samplers) { | |
59 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visib ility, | |
60 kVec2f_GrSLType, kDefault_GrSLPreci sion, | |
61 "ImageIncrement"); | |
62 if (this->useBounds()) { | |
63 fBoundsUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibilit y, | |
64 kVec2f_GrSLType, kDefault_GrSLPrecision , | |
65 "Bounds"); | |
66 } | |
67 fKernelUni = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibili ty, | |
68 kFloat_GrSLType, kDefault_GrSLPrecisio n, | |
69 "Kernel", this->width()); | |
70 | 116 |
71 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); | 117 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); |
72 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0); | 118 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0); |
73 | 119 |
74 fsBuilder->codeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor); | 120 fsBuilder->codeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor); |
75 | 121 |
76 int width = this->width(); | 122 int width = this->width(); |
77 const GrGLShaderVar& kernel = builder->getUniformVariable(fKernelUni); | 123 const GrGLShaderVar& kernel = builder->getUniformVariable(fKernelUni); |
78 const char* imgInc = builder->getUniformCStr(fImageIncrementUni); | 124 const char* imgInc = builder->getUniformCStr(fImageIncrementUni); |
79 | 125 |
80 fsBuilder->codeAppendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords2D.c_str( ), fRadius, imgInc); | 126 fsBuilder->codeAppendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords2D.c_str( ), this->radius(), |
127 imgInc); | |
81 | 128 |
82 // Manually unroll loop because some drivers don't; yields 20-30% speedup. | 129 // Manually unroll loop because some drivers don't; yields 20-30% speedup. |
83 for (int i = 0; i < width; i++) { | 130 for (int i = 0; i < width; i++) { |
84 SkString index; | 131 SkString index; |
85 SkString kernelIndex; | 132 SkString kernelIndex; |
86 index.appendS32(i); | 133 index.appendS32(i); |
87 kernel.appendArrayAccess(index.c_str(), &kernelIndex); | 134 kernel.appendArrayAccess(index.c_str(), &kernelIndex); |
88 fsBuilder->codeAppendf("\t\t%s += ", outputColor); | 135 fsBuilder->codeAppendf("\t\t%s += ", outputColor); |
89 fsBuilder->appendTextureLookup(samplers[0], "coord"); | 136 fsBuilder->appendTextureLookup(samplers[0], "coord"); |
90 if (this->useBounds()) { | 137 const char* bounds = builder->getUniformCStr(fBoundsUni); |
91 const char* bounds = builder->getUniformCStr(fBoundsUni); | 138 const char* component = this->direction() == Gr1DKernelEffect::kY_Direct ion ? "y" : "x"; |
92 const char* component = this->direction() == Gr1DKernelEffect::kY_Di rection ? "y" : "x"; | 139 fsBuilder->codeAppendf(" * float(coord.%s >= %s.x && coord.%s <= %s.y)", component, bounds, |
93 fsBuilder->codeAppendf(" * float(coord.%s >= %s.x && coord.%s <= %s. y)", | 140 component, bounds); |
94 component, bounds, component, bounds); | |
95 } | |
96 fsBuilder->codeAppendf(" * %s;\n", kernelIndex.c_str()); | 141 fsBuilder->codeAppendf(" * %s;\n", kernelIndex.c_str()); |
97 fsBuilder->codeAppendf("\t\tcoord += %s;\n", imgInc); | 142 fsBuilder->codeAppendf("\t\tcoord += %s;\n", imgInc); |
98 } | 143 } |
99 | 144 |
100 SkString modulate; | 145 SkString modulate; |
101 GrGLSLMulVarBy4f(&modulate, outputColor, inputColor); | 146 GrGLSLMulVarBy4f(&modulate, outputColor, inputColor); |
102 fsBuilder->codeAppend(modulate.c_str()); | 147 fsBuilder->codeAppend(modulate.c_str()); |
103 } | 148 } |
104 | 149 |
105 void GrGLConvolutionEffect::setData(const GrGLProgramDataManager& pdman, | 150 void GrGLBoundedConvolutionEffect::setData(const GrGLProgramDataManager& pdman, |
106 const GrProcessor& processor) { | 151 const GrProcessor& processor) { |
107 const GrConvolutionEffect& conv = processor.cast<GrConvolutionEffect>(); | 152 const GrConvolutionEffect& conv = processor.cast<GrConvolutionEffect>(); |
153 | |
154 // the code we generated was for a specific kernel radius | |
155 SkASSERT(conv.radius() == this->radius()); | |
156 | |
157 // the code we generated was for a specific bounding mode. | |
158 SkASSERT(conv.useBounds() == true); | |
159 | |
108 GrTexture& texture = *conv.texture(0); | 160 GrTexture& texture = *conv.texture(0); |
109 // the code we generated was for a specific kernel radius | 161 float imageIncrement[2]; |
110 SkASSERT(conv.radius() == fRadius); | 162 getImageIncrement(conv, &imageIncrement); |
111 float imageIncrement[2] = { 0 }; | |
112 float ySign = texture.origin() != kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f; | |
113 switch (conv.direction()) { | |
114 case Gr1DKernelEffect::kX_Direction: | |
115 imageIncrement[0] = 1.0f / texture.width(); | |
116 break; | |
117 case Gr1DKernelEffect::kY_Direction: | |
118 imageIncrement[1] = ySign / texture.height(); | |
119 break; | |
120 default: | |
121 SkFAIL("Unknown filter direction."); | |
122 } | |
123 pdman.set2fv(fImageIncrementUni, 1, imageIncrement); | 163 pdman.set2fv(fImageIncrementUni, 1, imageIncrement); |
124 if (conv.useBounds()) { | 164 const float* bounds = conv.bounds(); |
125 const float* bounds = conv.bounds(); | 165 if (Gr1DKernelEffect::kY_Direction == conv.direction() && |
126 if (Gr1DKernelEffect::kY_Direction == conv.direction() && | 166 texture.origin() != kTopLeft_GrSurfaceOrigin) { |
127 texture.origin() != kTopLeft_GrSurfaceOrigin) { | 167 pdman.set2f(fBoundsUni, 1.0f - bounds[1], 1.0f - bounds[0]); |
128 pdman.set2f(fBoundsUni, 1.0f - bounds[1], 1.0f - bounds[0]); | 168 } else { |
129 } else { | 169 pdman.set2f(fBoundsUni, bounds[0], bounds[1]); |
130 pdman.set2f(fBoundsUni, bounds[0], bounds[1]); | |
131 } | |
132 } | 170 } |
133 pdman.set1fv(fKernelUni, this->width(), conv.kernel()); | 171 pdman.set1fv(fKernelUni, this->width(), conv.kernel()); |
134 } | 172 } |
135 | 173 |
136 void GrGLConvolutionEffect::GenKey(const GrProcessor& processor, const GrGLSLCap s&, | 174 /////////////////////////////////////////////////////////////////////////////// |
137 GrProcessorKeyBuilder* b) { | 175 |
176 /** | |
177 * Applies a convolution effect which applies the convolution using a bilinear | |
178 * sampling optimization to use half as many samples. | |
179 */ | |
180 class GrGLBilerpConvolutionEffect : public GrGLConvolutionEffect { | |
Stephen White
2015/06/26 21:28:31
<bikeshed> is this really a bilinear fetch? Or ess
ericrk
2015/06/29 17:33:21
yup - that's better :D
| |
181 public: | |
182 GrGLBilerpConvolutionEffect(const GrProcessor& processor) : INHERITED(proces sor) {} | |
183 | |
184 virtual void emitCode(GrGLFPBuilder*, | |
185 const GrFragmentProcessor&, | |
186 const char* outputColor, | |
187 const char* inputColor, | |
188 const TransformedCoordsArray&, | |
189 const TextureSamplerArray&) override; | |
190 | |
191 void setData(const GrGLProgramDataManager& pdman, const GrProcessor&) overri de; | |
192 | |
193 private: | |
194 int bilerpSampleCount() const; | |
195 | |
196 // Bounded uniforms | |
197 UniformHandle fSampleWeightUni; | |
198 UniformHandle fSampleOffsetUni; | |
199 | |
200 typedef GrGLConvolutionEffect INHERITED; | |
201 }; | |
202 | |
203 void GrGLBilerpConvolutionEffect::emitCode(GrGLFPBuilder* builder, | |
204 const GrFragmentProcessor& processor, | |
205 const char* outputColor, | |
206 const char* inputColor, | |
207 const TransformedCoordsArray& coords, | |
208 const TextureSamplerArray& samplers) { | |
209 int sampleCount = bilerpSampleCount(); | |
210 | |
211 fSampleOffsetUni = | |
Stephen White
2015/06/26 21:28:31
How many uniform values does this add up to? You m
ericrk
2015/06/29 17:33:21
I think we're safe (assuming we keep the limit of
Stephen White
2015/06/29 19:04:06
Yep; makes sense. Thanks!
| |
212 builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility, kVec2 f_GrSLType, | |
213 kDefault_GrSLPrecision, "SampleOffset", sampleC ount); | |
214 fSampleWeightUni = | |
215 builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility, kFloa t_GrSLType, | |
216 kDefault_GrSLPrecision, "SampleWeight", sampleC ount); | |
217 | |
218 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); | |
219 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0); | |
220 | |
221 fsBuilder->codeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor); | |
bsalomon
2015/06/26 21:07:33
You don't really need the \t's anymore (we now "pr
ericrk
2015/06/26 21:28:22
removed the \t\ts throughout the file
| |
222 | |
223 const GrGLShaderVar& kernel = builder->getUniformVariable(fSampleWeightUni); | |
224 const GrGLShaderVar& imgInc = builder->getUniformVariable(fSampleOffsetUni); | |
225 | |
226 fsBuilder->codeAppendf("\t\tvec2 coord; \n"); | |
227 | |
228 // Manually unroll loop because some drivers don't; yields 20-30% speedup. | |
229 for (int i = 0; i < sampleCount; i++) { | |
230 SkString index; | |
231 SkString weightIndex; | |
232 SkString offsetIndex; | |
233 index.appendS32(i); | |
234 kernel.appendArrayAccess(index.c_str(), &weightIndex); | |
235 imgInc.appendArrayAccess(index.c_str(), &offsetIndex); | |
236 fsBuilder->codeAppendf("\t\tcoord = %s + %s;\n", coords2D.c_str(), offse tIndex.c_str()); | |
237 fsBuilder->codeAppendf("\t\t%s += ", outputColor); | |
238 fsBuilder->appendTextureLookup(samplers[0], "coord"); | |
239 fsBuilder->codeAppendf(" * %s;\n", weightIndex.c_str()); | |
240 } | |
241 | |
242 SkString modulate; | |
243 GrGLSLMulVarBy4f(&modulate, outputColor, inputColor); | |
244 fsBuilder->codeAppend(modulate.c_str()); | |
245 } | |
246 | |
247 void GrGLBilerpConvolutionEffect::setData(const GrGLProgramDataManager& pdman, | |
248 const GrProcessor& processor) { | |
138 const GrConvolutionEffect& conv = processor.cast<GrConvolutionEffect>(); | 249 const GrConvolutionEffect& conv = processor.cast<GrConvolutionEffect>(); |
139 uint32_t key = conv.radius(); | 250 |
140 key <<= 2; | 251 // the code we generated was for a specific kernel radius |
141 if (conv.useBounds()) { | 252 SkASSERT(conv.radius() == this->radius()); |
142 key |= 0x2; | 253 |
143 key |= GrConvolutionEffect::kY_Direction == conv.direction() ? 0x1 : 0x0 ; | 254 // the code we generated was for a specific bounding mode. |
255 SkASSERT(conv.useBounds() == false); | |
bsalomon
2015/06/26 21:07:34
!conv.useBounds()?
ericrk
2015/06/26 21:28:22
yup
| |
256 | |
257 int sampleCount = bilerpSampleCount(); | |
258 SkAutoTArray<float> imageIncrements(sampleCount * 2); // X and Y floats per sample. | |
259 SkAutoTArray<float> kernel(sampleCount); | |
260 | |
261 float baseImageIncrement[2]; | |
262 getImageIncrement(conv, &baseImageIncrement); | |
263 | |
264 for (int i = 0; i < sampleCount; i++) { | |
265 int sampleIndex1 = i * 2; | |
266 int sampleIndex2 = sampleIndex1 + 1; | |
267 | |
268 // If we have an odd number of samples in our filter, the last sample wo n't use | |
269 // the bilinear optimization (it will be pixel aligned). | |
270 if (sampleIndex2 >= this->width()) { | |
271 sampleIndex2 = sampleIndex1; | |
272 } | |
273 | |
274 float kernelWeight1 = conv.kernel()[sampleIndex1]; | |
275 float kernelWeight2 = conv.kernel()[sampleIndex2]; | |
276 | |
277 float totalKernalWeight = | |
Stephen White
2015/06/26 21:28:31
Nit: kernal -> kernel?
| |
278 (sampleIndex1 == sampleIndex2) ? kernelWeight1 : (kernelWeight1 + ke rnelWeight2); | |
279 | |
280 float sampleRatio = | |
281 (sampleIndex1 == sampleIndex2) ? 0 : kernelWeight2 / (kernelWeight1 + kernelWeight2); | |
282 | |
283 imageIncrements[i * 2] = (-this->radius() + i * 2 + sampleRatio) * baseI mageIncrement[0]; | |
284 imageIncrements[i * 2 + 1] = | |
285 (-this->radius() + i * 2 + sampleRatio) * baseImageIncrement[1]; | |
286 | |
287 kernel[i] = totalKernalWeight; | |
144 } | 288 } |
145 b->add32(key); | 289 pdman.set2fv(fSampleOffsetUni, sampleCount, imageIncrements.get()); |
290 pdman.set1fv(fSampleWeightUni, sampleCount, kernel.get()); | |
291 } | |
292 | |
293 int GrGLBilerpConvolutionEffect::bilerpSampleCount() const { | |
294 // We use a bilinear optimization to only sample once for each two pixel ali gned | |
295 // samples in the kernel. If we have an odd number of samples, we will have to | |
296 // skip this optimization for the last sample. Because of this we always rou nd | |
297 // up our sample count (by adding 1 before dividing). | |
298 return (this->width() + 1) / 2; | |
146 } | 299 } |
147 | 300 |
148 /////////////////////////////////////////////////////////////////////////////// | 301 /////////////////////////////////////////////////////////////////////////////// |
149 | 302 |
150 GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture, | 303 GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture, |
151 Direction direction, | 304 Direction direction, |
152 int radius, | 305 int radius, |
153 const float* kernel, | 306 const float* kernel, |
154 bool useBounds, | 307 bool useBounds, |
155 float bounds[2]) | 308 float bounds[2]) |
156 : Gr1DKernelEffect(texture, direction, radius), fUseBounds(useBounds) { | 309 : Gr1DKernelEffect(texture, |
310 direction, | |
311 radius, | |
312 useBounds ? GrTextureParams::FilterMode::kNone_FilterMode | |
313 : GrTextureParams::FilterMode::kBilerp_FilterMo de) | |
314 , fUseBounds(useBounds) { | |
157 this->initClassID<GrConvolutionEffect>(); | 315 this->initClassID<GrConvolutionEffect>(); |
158 SkASSERT(radius <= kMaxKernelRadius); | 316 SkASSERT(radius <= kMaxKernelRadius); |
159 SkASSERT(kernel); | 317 SkASSERT(kernel); |
160 int width = this->width(); | 318 int width = this->width(); |
161 for (int i = 0; i < width; i++) { | 319 for (int i = 0; i < width; i++) { |
162 fKernel[i] = kernel[i]; | 320 fKernel[i] = kernel[i]; |
163 } | 321 } |
164 memcpy(fBounds, bounds, sizeof(fBounds)); | 322 memcpy(fBounds, bounds, sizeof(fBounds)); |
165 } | 323 } |
166 | 324 |
167 GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture, | 325 GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture, |
168 Direction direction, | 326 Direction direction, |
169 int radius, | 327 int radius, |
170 float gaussianSigma, | 328 float gaussianSigma, |
171 bool useBounds, | 329 bool useBounds, |
172 float bounds[2]) | 330 float bounds[2]) |
173 : Gr1DKernelEffect(texture, direction, radius), fUseBounds(useBounds) { | 331 : Gr1DKernelEffect(texture, |
332 direction, | |
333 radius, | |
334 useBounds ? GrTextureParams::FilterMode::kNone_FilterMode | |
335 : GrTextureParams::FilterMode::kBilerp_FilterMo de) | |
336 , fUseBounds(useBounds) { | |
174 this->initClassID<GrConvolutionEffect>(); | 337 this->initClassID<GrConvolutionEffect>(); |
175 SkASSERT(radius <= kMaxKernelRadius); | 338 SkASSERT(radius <= kMaxKernelRadius); |
176 int width = this->width(); | 339 int width = this->width(); |
177 | 340 |
178 float sum = 0.0f; | 341 float sum = 0.0f; |
179 float denom = 1.0f / (2.0f * gaussianSigma * gaussianSigma); | 342 float denom = 1.0f / (2.0f * gaussianSigma * gaussianSigma); |
180 for (int i = 0; i < width; ++i) { | 343 for (int i = 0; i < width; ++i) { |
181 float x = static_cast<float>(i - this->radius()); | 344 float x = static_cast<float>(i - this->radius()); |
182 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian | 345 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian |
183 // is dropped here, since we renormalize the kernel below. | 346 // is dropped here, since we renormalize the kernel below. |
(...skipping 10 matching lines...) Expand all Loading... | |
194 | 357 |
195 GrConvolutionEffect::~GrConvolutionEffect() { | 358 GrConvolutionEffect::~GrConvolutionEffect() { |
196 } | 359 } |
197 | 360 |
198 void GrConvolutionEffect::getGLProcessorKey(const GrGLSLCaps& caps, | 361 void GrConvolutionEffect::getGLProcessorKey(const GrGLSLCaps& caps, |
199 GrProcessorKeyBuilder* b) const { | 362 GrProcessorKeyBuilder* b) const { |
200 GrGLConvolutionEffect::GenKey(*this, caps, b); | 363 GrGLConvolutionEffect::GenKey(*this, caps, b); |
201 } | 364 } |
202 | 365 |
203 GrGLFragmentProcessor* GrConvolutionEffect::createGLInstance() const { | 366 GrGLFragmentProcessor* GrConvolutionEffect::createGLInstance() const { |
204 return SkNEW_ARGS(GrGLConvolutionEffect, (*this)); | 367 // We support a bilinear optimization which (when feasible) uses half the nu mber |
368 // of samples to apply the kernel. This is not always applicable, as the | |
369 // bilinear sampling optimization does not support bounded sampling. | |
370 if (this->useBounds()) { | |
371 return SkNEW_ARGS(GrGLBoundedConvolutionEffect, (*this)); | |
372 } else { | |
373 return SkNEW_ARGS(GrGLBilerpConvolutionEffect, (*this)); | |
374 } | |
205 } | 375 } |
206 | 376 |
207 bool GrConvolutionEffect::onIsEqual(const GrFragmentProcessor& sBase) const { | 377 bool GrConvolutionEffect::onIsEqual(const GrFragmentProcessor& sBase) const { |
208 const GrConvolutionEffect& s = sBase.cast<GrConvolutionEffect>(); | 378 const GrConvolutionEffect& s = sBase.cast<GrConvolutionEffect>(); |
209 return (this->radius() == s.radius() && | 379 return (this->radius() == s.radius() && |
210 this->direction() == s.direction() && | 380 this->direction() == s.direction() && |
211 this->useBounds() == s.useBounds() && | 381 this->useBounds() == s.useBounds() && |
212 0 == memcmp(fBounds, s.fBounds, sizeof(fBounds)) && | 382 0 == memcmp(fBounds, s.fBounds, sizeof(fBounds)) && |
213 0 == memcmp(fKernel, s.fKernel, this->width() * sizeof(float))); | 383 0 == memcmp(fKernel, s.fKernel, this->width() * sizeof(float))); |
214 } | 384 } |
(...skipping 20 matching lines...) Expand all Loading... | |
235 } | 405 } |
236 | 406 |
237 bool useBounds = random->nextBool(); | 407 bool useBounds = random->nextBool(); |
238 return GrConvolutionEffect::Create(textures[texIdx], | 408 return GrConvolutionEffect::Create(textures[texIdx], |
239 dir, | 409 dir, |
240 radius, | 410 radius, |
241 kernel, | 411 kernel, |
242 useBounds, | 412 useBounds, |
243 bounds); | 413 bounds); |
244 } | 414 } |
OLD | NEW |