OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 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 #include "GrMatrixConvolutionEffect.h" | 7 #include "GrMatrixConvolutionEffect.h" |
8 #include "gl/GrGLShaderBuilder.h" | 8 #include "gl/GrGLShaderBuilder.h" |
9 #include "gl/GrGLEffect.h" | 9 #include "gl/GrGLEffect.h" |
10 #include "gl/GrGLSL.h" | 10 #include "gl/GrGLSL.h" |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
77 kFloat_GrSLType, "Bias"); | 77 kFloat_GrSLType, "Bias"); |
78 | 78 |
79 const char* kernelOffset = builder->getUniformCStr(fKernelOffsetUni); | 79 const char* kernelOffset = builder->getUniformCStr(fKernelOffsetUni); |
80 const char* imgInc = builder->getUniformCStr(fImageIncrementUni); | 80 const char* imgInc = builder->getUniformCStr(fImageIncrementUni); |
81 const char* kernel = builder->getUniformCStr(fKernelUni); | 81 const char* kernel = builder->getUniformCStr(fKernelUni); |
82 const char* gain = builder->getUniformCStr(fGainUni); | 82 const char* gain = builder->getUniformCStr(fGainUni); |
83 const char* bias = builder->getUniformCStr(fBiasUni); | 83 const char* bias = builder->getUniformCStr(fBiasUni); |
84 int kWidth = fKernelSize.width(); | 84 int kWidth = fKernelSize.width(); |
85 int kHeight = fKernelSize.height(); | 85 int kHeight = fKernelSize.height(); |
86 | 86 |
87 builder->fsCodeAppend("\t\tvec4 sum = vec4(0, 0, 0, 0);\n"); | 87 builder->fsCodeAppend("vec4 sum = vec4(0, 0, 0, 0);"); |
88 builder->fsCodeAppendf("\t\tvec2 coord = %s - %s * %s;\n", coords2D.c_str(),
kernelOffset, | 88 builder->fsCodeAppendf("vec2 coord = %s - %s * %s;", coords2D.c_str(), kerne
lOffset, |
89 imgInc); | 89 imgInc); |
90 builder->fsCodeAppend("\t\tvec4 c;\n"); | 90 builder->fsCodeAppend("vec4 c;"); |
91 | 91 |
92 for (int y = 0; y < kHeight; y++) { | 92 for (int y = 0; y < kHeight; y++) { |
93 for (int x = 0; x < kWidth; x++) { | 93 for (int x = 0; x < kWidth; x++) { |
94 GrGLShaderBuilder::FSBlock block(builder); | 94 GrGLShaderBuilder::FSBlock block(builder); |
95 builder->fsCodeAppendf("\t\tfloat k = %s[%d * %d + %d];\n", kernel,
y, kWidth, x); | 95 builder->fsCodeAppendf("float k = %s[%d * %d + %d];", kernel, y, kWi
dth, x); |
96 SkString coord; | 96 SkString coord; |
97 coord.printf("coord + vec2(%d, %d) * %s", x, y, imgInc); | 97 coord.printf("coord + vec2(%d, %d) * %s", x, y, imgInc); |
98 fDomain.sampleTexture(builder, domain, "c", coord, samplers[0]); | 98 fDomain.sampleTexture(builder, domain, "c", coord, samplers[0]); |
99 if (!fConvolveAlpha) { | 99 if (!fConvolveAlpha) { |
100 builder->fsCodeAppend("\t\tc.rgb /= c.a;\n"); | 100 builder->fsCodeAppend("c.rgb /= c.a;"); |
101 } | 101 } |
102 builder->fsCodeAppend("\t\tsum += c * k;\n"); | 102 builder->fsCodeAppend("sum += c * k;"); |
103 } | 103 } |
104 } | 104 } |
105 if (fConvolveAlpha) { | 105 if (fConvolveAlpha) { |
106 builder->fsCodeAppendf("\t\t%s = sum * %s + %s;\n", outputColor, gain, b
ias); | 106 builder->fsCodeAppendf("%s = sum * %s + %s;", outputColor, gain, bias); |
107 builder->fsCodeAppendf("\t\t%s.rgb = clamp(%s.rgb, 0.0, %s.a);\n", | 107 builder->fsCodeAppendf("%s.rgb = clamp(%s.rgb, 0.0, %s.a);", |
108 outputColor, outputColor, outputColor); | 108 outputColor, outputColor, outputColor); |
109 } else { | 109 } else { |
110 fDomain.sampleTexture(builder, domain, "c", coords2D, samplers[0]); | 110 fDomain.sampleTexture(builder, domain, "c", coords2D, samplers[0]); |
111 builder->fsCodeAppendf("\t\t%s.a = c.a;\n", outputColor); | 111 builder->fsCodeAppendf("%s.a = c.a;", outputColor); |
112 builder->fsCodeAppendf("\t\t%s.rgb = sum.rgb * %s + %s;\n", outputColor,
gain, bias); | 112 builder->fsCodeAppendf("%s.rgb = sum.rgb * %s + %s;", outputColor, gain,
bias); |
113 builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor
); | 113 builder->fsCodeAppendf("%s.rgb *= %s.a;", outputColor, outputColor); |
114 } | 114 } |
| 115 |
| 116 SkString modulate; |
| 117 GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor); |
| 118 builder->fsCodeAppend(modulate.c_str()); |
115 } | 119 } |
116 | 120 |
117 void GrGLMatrixConvolutionEffect::GenKey(const GrDrawEffect& drawEffect, | 121 void GrGLMatrixConvolutionEffect::GenKey(const GrDrawEffect& drawEffect, |
118 const GrGLCaps&, GrEffectKeyBuilder* b)
{ | 122 const GrGLCaps&, GrEffectKeyBuilder* b)
{ |
119 const GrMatrixConvolutionEffect& m = drawEffect.castEffect<GrMatrixConvoluti
onEffect>(); | 123 const GrMatrixConvolutionEffect& m = drawEffect.castEffect<GrMatrixConvoluti
onEffect>(); |
120 SkASSERT(m.kernelSize().width() <= 0x7FFF && m.kernelSize().height() <= 0xFF
FF); | 124 SkASSERT(m.kernelSize().width() <= 0x7FFF && m.kernelSize().height() <= 0xFF
FF); |
121 uint32_t key = m.kernelSize().width() << 16 | m.kernelSize().height(); | 125 uint32_t key = m.kernelSize().width() << 16 | m.kernelSize().height(); |
122 key |= m.convolveAlpha() ? 1 << 31 : 0; | 126 key |= m.convolveAlpha() ? 1 << 31 : 0; |
123 b->add32(key); | 127 b->add32(key); |
124 b->add32(GrTextureDomain::GLDomain::DomainKey(m.domain())); | 128 b->add32(GrTextureDomain::GLDomain::DomainKey(m.domain())); |
(...skipping 25 matching lines...) Expand all Loading... |
150 SkScalar bias, | 154 SkScalar bias, |
151 const SkIPoint& kernelOffse
t, | 155 const SkIPoint& kernelOffse
t, |
152 GrTextureDomain::Mode tileM
ode, | 156 GrTextureDomain::Mode tileM
ode, |
153 bool convolveAlpha) | 157 bool convolveAlpha) |
154 : INHERITED(texture, MakeDivByTextureWHMatrix(texture)), | 158 : INHERITED(texture, MakeDivByTextureWHMatrix(texture)), |
155 fKernelSize(kernelSize), | 159 fKernelSize(kernelSize), |
156 fGain(SkScalarToFloat(gain)), | 160 fGain(SkScalarToFloat(gain)), |
157 fBias(SkScalarToFloat(bias) / 255.0f), | 161 fBias(SkScalarToFloat(bias) / 255.0f), |
158 fConvolveAlpha(convolveAlpha), | 162 fConvolveAlpha(convolveAlpha), |
159 fDomain(GrTextureDomain::MakeTexelDomain(texture, bounds), tileMode) { | 163 fDomain(GrTextureDomain::MakeTexelDomain(texture, bounds), tileMode) { |
160 fKernel = new float[kernelSize.width() * kernelSize.height()]; | |
161 for (int i = 0; i < kernelSize.width() * kernelSize.height(); i++) { | 164 for (int i = 0; i < kernelSize.width() * kernelSize.height(); i++) { |
162 fKernel[i] = SkScalarToFloat(kernel[i]); | 165 fKernel[i] = SkScalarToFloat(kernel[i]); |
163 } | 166 } |
164 fKernelOffset[0] = static_cast<float>(kernelOffset.x()); | 167 fKernelOffset[0] = static_cast<float>(kernelOffset.x()); |
165 fKernelOffset[1] = static_cast<float>(kernelOffset.y()); | 168 fKernelOffset[1] = static_cast<float>(kernelOffset.y()); |
166 this->setWillNotUseInputColor(); | |
167 } | 169 } |
168 | 170 |
169 GrMatrixConvolutionEffect::~GrMatrixConvolutionEffect() { | 171 GrMatrixConvolutionEffect::~GrMatrixConvolutionEffect() { |
170 delete[] fKernel; | |
171 } | 172 } |
172 | 173 |
173 const GrBackendEffectFactory& GrMatrixConvolutionEffect::getFactory() const { | 174 const GrBackendEffectFactory& GrMatrixConvolutionEffect::getFactory() const { |
174 return GrTBackendEffectFactory<GrMatrixConvolutionEffect>::getInstance(); | 175 return GrTBackendEffectFactory<GrMatrixConvolutionEffect>::getInstance(); |
175 } | 176 } |
176 | 177 |
177 bool GrMatrixConvolutionEffect::onIsEqual(const GrEffect& sBase) const { | 178 bool GrMatrixConvolutionEffect::onIsEqual(const GrEffect& sBase) const { |
178 const GrMatrixConvolutionEffect& s = CastEffect<GrMatrixConvolutionEffect>(s
Base); | 179 const GrMatrixConvolutionEffect& s = CastEffect<GrMatrixConvolutionEffect>(s
Base); |
179 return this->texture(0) == s.texture(0) && | 180 return this->texture(0) == s.texture(0) && |
180 fKernelSize == s.kernelSize() && | 181 fKernelSize == s.kernelSize() && |
181 !memcmp(fKernel, s.kernel(), | 182 !memcmp(fKernel, s.kernel(), |
182 fKernelSize.width() * fKernelSize.height() * sizeof(float)) &
& | 183 fKernelSize.width() * fKernelSize.height() * sizeof(float)) &
& |
183 fGain == s.gain() && | 184 fGain == s.gain() && |
184 fBias == s.bias() && | 185 fBias == s.bias() && |
185 fKernelOffset == s.kernelOffset() && | 186 fKernelOffset == s.kernelOffset() && |
186 fConvolveAlpha == s.convolveAlpha() && | 187 fConvolveAlpha == s.convolveAlpha() && |
187 fDomain == s.domain(); | 188 fDomain == s.domain(); |
188 } | 189 } |
189 | 190 |
| 191 // Static function to create a 2D convolution |
| 192 GrEffect* GrMatrixConvolutionEffect::CreateGaussian(GrTexture* texture, |
| 193 const SkIRect& bounds, |
| 194 const SkISize& kernelSize, |
| 195 SkScalar gain, |
| 196 SkScalar bias, |
| 197 const SkIPoint& kernelOffset
, |
| 198 GrTextureDomain::Mode tileMo
de, |
| 199 bool convolveAlpha, |
| 200 SkScalar sigmaX, |
| 201 SkScalar sigmaY) { |
| 202 float kernel[MAX_KERNEL_SIZE]; |
| 203 int width = kernelSize.width(); |
| 204 int height = kernelSize.height(); |
| 205 SkASSERT(width * height <= MAX_KERNEL_SIZE); |
| 206 float sum = 0.0f; |
| 207 float sigmaXDenom = 1.0f / (2.0f * SkScalarToFloat(SkScalarSquare(sigmaX))); |
| 208 float sigmaYDenom = 1.0f / (2.0f * SkScalarToFloat(SkScalarSquare(sigmaY))); |
| 209 int xRadius = width / 2; |
| 210 int yRadius = height / 2; |
| 211 for (int x = 0; x < width; x++) { |
| 212 float xTerm = static_cast<float>(x - xRadius); |
| 213 xTerm = xTerm * xTerm * sigmaXDenom; |
| 214 for (int y = 0; y < height; y++) { |
| 215 float yTerm = static_cast<float>(y - yRadius); |
| 216 float xyTerm = sk_float_exp(-(xTerm + yTerm * yTerm * sigmaYDenom)); |
| 217 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian |
| 218 // is dropped here, since we renormalize the kernel below. |
| 219 kernel[y * width + x] = xyTerm; |
| 220 sum += xyTerm; |
| 221 } |
| 222 } |
| 223 // Normalize the kernel |
| 224 float scale = 1.0f / sum; |
| 225 for (int i = 0; i < width * height; ++i) { |
| 226 kernel[i] *= scale; |
| 227 } |
| 228 return SkNEW_ARGS(GrMatrixConvolutionEffect, (texture, |
| 229 bounds, |
| 230 kernelSize, |
| 231 kernel, |
| 232 gain, |
| 233 bias, |
| 234 kernelOffset, |
| 235 tileMode, |
| 236 convolveAlpha)); |
| 237 } |
| 238 |
190 GR_DEFINE_EFFECT_TEST(GrMatrixConvolutionEffect); | 239 GR_DEFINE_EFFECT_TEST(GrMatrixConvolutionEffect); |
191 | 240 |
192 GrEffect* GrMatrixConvolutionEffect::TestCreate(SkRandom* random, | 241 GrEffect* GrMatrixConvolutionEffect::TestCreate(SkRandom* random, |
193 GrContext* context, | 242 GrContext* context, |
194 const GrDrawTargetCaps&, | 243 const GrDrawTargetCaps&, |
195 GrTexture* textures[]) { | 244 GrTexture* textures[]) { |
196 int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx : | 245 int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx : |
197 GrEffectUnitTest::kAlphaTextureIdx; | 246 GrEffectUnitTest::kAlphaTextureIdx; |
198 int width = random->nextRangeU(1, MAX_KERNEL_SIZE); | 247 int width = random->nextRangeU(1, MAX_KERNEL_SIZE); |
199 int height = random->nextRangeU(1, MAX_KERNEL_SIZE / width); | 248 int height = random->nextRangeU(1, MAX_KERNEL_SIZE / width); |
(...skipping 15 matching lines...) Expand all Loading... |
215 return GrMatrixConvolutionEffect::Create(textures[texIdx], | 264 return GrMatrixConvolutionEffect::Create(textures[texIdx], |
216 bounds, | 265 bounds, |
217 kernelSize, | 266 kernelSize, |
218 kernel.get(), | 267 kernel.get(), |
219 gain, | 268 gain, |
220 bias, | 269 bias, |
221 kernelOffset, | 270 kernelOffset, |
222 tileMode, | 271 tileMode, |
223 convolveAlpha); | 272 convolveAlpha); |
224 } | 273 } |
OLD | NEW |