| 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 |