Chromium Code Reviews| Index: src/gpu/effects/GrMatrixConvolutionEffect.cpp |
| diff --git a/src/gpu/effects/GrMatrixConvolutionEffect.cpp b/src/gpu/effects/GrMatrixConvolutionEffect.cpp |
| index 283138e1338eeffe7b1fd3d9cb88989dc7ed66ea..29a26f1be73f9f4a075fe901fdc5e86574aa1cb3 100644 |
| --- a/src/gpu/effects/GrMatrixConvolutionEffect.cpp |
| +++ b/src/gpu/effects/GrMatrixConvolutionEffect.cpp |
| @@ -33,6 +33,7 @@ private: |
| SkISize fKernelSize; |
| TileMode fTileMode; |
| bool fConvolveAlpha; |
| + bool fUseBounds; |
| UniformHandle fBoundsUni; |
| UniformHandle fKernelUni; |
| @@ -51,6 +52,7 @@ GrGLMatrixConvolutionEffect::GrGLMatrixConvolutionEffect(const GrBackendEffectFa |
| fKernelSize = m.kernelSize(); |
| fTileMode = m.tileMode(); |
| fConvolveAlpha = m.convolveAlpha(); |
| + fUseBounds = m.useBounds(); |
| } |
| static void appendTextureLookup(GrGLShaderBuilder* builder, |
| @@ -59,18 +61,22 @@ static void appendTextureLookup(GrGLShaderBuilder* builder, |
| const char* bounds, |
| GrMatrixConvolutionEffect::TileMode tileMode) { |
| SkString clampedCoord; |
| - switch (tileMode) { |
| - case GrMatrixConvolutionEffect::kClamp_TileMode: |
| - clampedCoord.printf("clamp(%s, %s.xy, %s.zw)", coord, bounds, bounds); |
| - coord = clampedCoord.c_str(); |
| - break; |
| - case GrMatrixConvolutionEffect::kRepeat_TileMode: |
| - clampedCoord.printf("mod(%s - %s.xy, %s.zw - %s.xy) + %s.xy", coord, bounds, bounds, bounds, bounds); |
| - coord = clampedCoord.c_str(); |
| - break; |
| - case GrMatrixConvolutionEffect::kClampToBlack_TileMode: |
| - builder->fsCodeAppendf("clamp(%s, %s.xy, %s.zw) != %s ? vec4(0, 0, 0, 0) : ", coord, bounds, bounds, coord); |
| - break; |
| + if (bounds != NULL) { |
| + switch (tileMode) { |
| + case GrMatrixConvolutionEffect::kClamp_TileMode: |
| + clampedCoord.printf("clamp(%s, %s.xy, %s.zw)", coord, bounds, bounds); |
| + coord = clampedCoord.c_str(); |
| + break; |
| + case GrMatrixConvolutionEffect::kRepeat_TileMode: |
| + clampedCoord.printf("mod(%s - %s.xy, %s.zw - %s.xy) + %s.xy", coord, bounds, bounds, |
| + bounds, bounds); |
| + coord = clampedCoord.c_str(); |
| + break; |
| + case GrMatrixConvolutionEffect::kClampToBlack_TileMode: |
| + builder->fsCodeAppendf("clamp(%s, %s.xy, %s.zw) != %s ? vec4(0, 0, 0, 0) : ", coord, |
| + bounds, bounds, coord); |
| + break; |
| + } |
| } |
| builder->fsAppendTextureLookup(sampler, coord); |
| } |
| @@ -84,8 +90,10 @@ void GrGLMatrixConvolutionEffect::emitCode(GrGLShaderBuilder* builder, |
| const TextureSamplerArray& samplers) { |
| sk_ignore_unused_variable(inputColor); |
| SkString coords2D = builder->ensureFSCoords2D(coords, 0); |
| - fBoundsUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
| - kVec4f_GrSLType, "Bounds"); |
| + if (fUseBounds) { |
| + fBoundsUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
| + kVec4f_GrSLType, "Bounds"); |
| + } |
| fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
| kVec2f_GrSLType, "ImageIncrement"); |
| fKernelUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibility, |
| @@ -99,7 +107,10 @@ void GrGLMatrixConvolutionEffect::emitCode(GrGLShaderBuilder* builder, |
| fBiasUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
| kFloat_GrSLType, "Bias"); |
| - const char* bounds = builder->getUniformCStr(fBoundsUni); |
| + const char* bounds = NULL; |
| + if (fUseBounds) { |
| + bounds = builder->getUniformCStr(fBoundsUni); |
| + } |
| const char* kernelOffset = builder->getUniformCStr(fKernelOffsetUni); |
| const char* imgInc = builder->getUniformCStr(fImageIncrementUni); |
| const char* kernel = builder->getUniformCStr(fKernelUni); |
| @@ -109,26 +120,31 @@ void GrGLMatrixConvolutionEffect::emitCode(GrGLShaderBuilder* builder, |
| int kHeight = fKernelSize.height(); |
| builder->fsCodeAppend("\t\tvec4 sum = vec4(0, 0, 0, 0);\n"); |
| - builder->fsCodeAppendf("\t\tvec2 coord = %s - %s * %s;\n", coords2D.c_str(), kernelOffset, imgInc); |
| - builder->fsCodeAppendf("\t\tfor (int y = 0; y < %d; y++) {\n", kHeight); |
| - builder->fsCodeAppendf("\t\t\tfor (int x = 0; x < %d; x++) {\n", kWidth); |
| - builder->fsCodeAppendf("\t\t\t\tfloat k = %s[y * %d + x];\n", kernel, kWidth); |
| - builder->fsCodeAppendf("\t\t\t\tvec2 coord2 = coord + vec2(x, y) * %s;\n", imgInc); |
| - builder->fsCodeAppend("\t\t\t\tvec4 c = "); |
| - appendTextureLookup(builder, samplers[0], "coord2", bounds, fTileMode); |
| - builder->fsCodeAppend(";\n"); |
| - if (!fConvolveAlpha) { |
| - builder->fsCodeAppend("\t\t\t\tc.rgb /= c.a;\n"); |
| + builder->fsCodeAppendf("\t\tvec2 coord = %s - %s * %s;\n", coords2D.c_str(), kernelOffset, |
| + imgInc); |
| + builder->fsCodeAppend("\t\tfloat k;\n"); |
| + builder->fsCodeAppend("\t\tvec2 coord2;\n"); |
| + builder->fsCodeAppend("\t\tvec4 c;\n"); |
| + |
| + for (int y = 0; y < kHeight; y++) { |
| + for (int x = 0; x < kWidth; x++) { |
| + builder->fsCodeAppendf("\t\tk = %s[%d * %d + %d];\n", kernel, y, kWidth, x); |
| + builder->fsCodeAppendf("\t\tcoord2 = coord + vec2(%d, %d) * %s;\n", x, y, imgInc); |
| + builder->fsCodeAppend("\t\tc = "); |
| + appendTextureLookup(builder, samplers[0], "coord2", bounds, fTileMode); |
| + builder->fsCodeAppend(";\n"); |
| + if (!fConvolveAlpha) { |
| + builder->fsCodeAppend("\t\tc.rgb /= c.a;\n"); |
| + } |
| + builder->fsCodeAppend("\t\tsum += c * k;\n"); |
| + } |
| } |
| - builder->fsCodeAppend("\t\t\t\tsum += c * k;\n"); |
| - builder->fsCodeAppend("\t\t\t}\n"); |
| - builder->fsCodeAppend("\t\t}\n"); |
| if (fConvolveAlpha) { |
| builder->fsCodeAppendf("\t\t%s = sum * %s + %s;\n", outputColor, gain, bias); |
| builder->fsCodeAppendf("\t\t%s.rgb = clamp(%s.rgb, 0.0, %s.a);\n", |
| outputColor, outputColor, outputColor); |
| } else { |
| - builder->fsCodeAppend("\t\tvec4 c = "); |
| + builder->fsCodeAppend("\t\tc = "); |
| appendTextureLookup(builder, samplers[0], coords2D.c_str(), bounds, fTileMode); |
| builder->fsCodeAppend(";\n"); |
| builder->fsCodeAppendf("\t\t%s.a = c.a;\n", outputColor); |
| @@ -155,6 +171,7 @@ void GrGLMatrixConvolutionEffect::GenKey(const GrDrawEffect& drawEffect, |
| uint32_t key = encodeXY(m.kernelSize().width(), m.kernelSize().height()); |
|
bsalomon
2014/07/28 15:20:41
When this was originally written we had a really r
|
| key |= m.tileMode() << 7; |
| key |= m.convolveAlpha() ? 1 << 9 : 0; |
| + key |= m.useBounds() ? 1 << 10 : 0; |
| b->add32(key); |
| } |
| @@ -174,15 +191,17 @@ void GrGLMatrixConvolutionEffect::setData(const GrGLUniformManager& uman, |
| uman.set1fv(fKernelUni, fKernelSize.width() * fKernelSize.height(), conv.kernel()); |
| uman.set1f(fGainUni, conv.gain()); |
| uman.set1f(fBiasUni, conv.bias()); |
| - const SkIRect& bounds = conv.bounds(); |
| - float left = (float) bounds.left() / texture.width(); |
| - float top = (float) bounds.top() / texture.height(); |
| - float right = (float) bounds.right() / texture.width(); |
| - float bottom = (float) bounds.bottom() / texture.height(); |
| - if (texture.origin() == kBottomLeft_GrSurfaceOrigin) { |
| - uman.set4f(fBoundsUni, left, 1.0f - bottom, right, 1.0f - top); |
| - } else { |
| - uman.set4f(fBoundsUni, left, top, right, bottom); |
| + if (fUseBounds) { |
| + const SkIRect& bounds = conv.bounds(); |
| + float left = (float) bounds.left() / texture.width(); |
| + float top = (float) bounds.top() / texture.height(); |
| + float right = (float) bounds.right() / texture.width(); |
| + float bottom = (float) bounds.bottom() / texture.height(); |
| + if (texture.origin() == kBottomLeft_GrSurfaceOrigin) { |
| + uman.set4f(fBoundsUni, left, 1.0f - bottom, right, 1.0f - top); |
| + } else { |
| + uman.set4f(fBoundsUni, left, top, right, bottom); |
| + } |
| } |
| } |
| @@ -194,15 +213,16 @@ GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(GrTexture* texture, |
| SkScalar bias, |
| const SkIPoint& kernelOffset, |
| TileMode tileMode, |
| - bool convolveAlpha) |
| + bool convolveAlpha, |
| + bool useBounds) |
| : INHERITED(texture, MakeDivByTextureWHMatrix(texture)), |
| fBounds(bounds), |
| fKernelSize(kernelSize), |
| fGain(SkScalarToFloat(gain)), |
| fBias(SkScalarToFloat(bias) / 255.0f), |
| fTileMode(tileMode), |
| - fConvolveAlpha(convolveAlpha) { |
| - fKernel = new float[kernelSize.width() * kernelSize.height()]; |
| + fConvolveAlpha(convolveAlpha), |
| + fUseBounds(useBounds) { |
| for (int i = 0; i < kernelSize.width() * kernelSize.height(); i++) { |
| fKernel[i] = SkScalarToFloat(kernel[i]); |
| } |
| @@ -212,7 +232,6 @@ GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(GrTexture* texture, |
| } |
| GrMatrixConvolutionEffect::~GrMatrixConvolutionEffect() { |
| - delete[] fKernel; |
| } |
| const GrBackendEffectFactory& GrMatrixConvolutionEffect::getFactory() const { |
| @@ -232,6 +251,57 @@ bool GrMatrixConvolutionEffect::onIsEqual(const GrEffect& sBase) const { |
| fConvolveAlpha == s.convolveAlpha(); |
| } |
| +// Static function to create a 2D convolution |
| +GrEffect* GrMatrixConvolutionEffect::CreateGaussian(GrTexture* texture, |
| + const SkIRect& bounds, |
| + const SkISize& kernelSize, |
| + SkScalar gain, |
| + SkScalar bias, |
| + const SkIPoint& kernelOffset, |
| + TileMode tileMode, |
| + bool convolveAlpha, |
| + bool useBounds, |
| + SkScalar sigmaX, |
| + SkScalar sigmaY) { |
| + float kernel[MAX_KERNEL_SIZE]; |
| + int width = kernelSize.width(); |
| + int height = kernelSize.height(); |
| + SkASSERT(width * height <= MAX_KERNEL_SIZE); |
| + float sum = 0.0f; |
| + float sigmaXDenom = 1.0 / (2.0 * sigmaX * sigmaX); |
| + float sigmaYDenom = 1.0 / (2.0 * sigmaY * sigmaY); |
| + int xRadius = width / 2; |
| + int yRadius = height / 2; |
| + for (int x = 0; x < width; x++) { |
| + float xTerm = static_cast<float>(x - xRadius); |
| + xTerm = SkScalarSquare(xTerm) * sigmaXDenom; |
| + for (int y = 0; y < height; y++) { |
| + float yTerm = static_cast<float>(y - yRadius); |
| + |
| + float xyTerm = sk_float_exp(-(xTerm + SkScalarSquare(yTerm) * sigmaYDenom)); |
| + // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian |
| + // is dropped here, since we renormalize the kernel below. |
| + kernel[y * width + x] = xyTerm; |
| + sum += xyTerm; |
| + } |
| + } |
| + // Normalize the kernel |
| + float scale = 1.0f / sum; |
| + for (int i = 0; i < width * height; ++i) { |
| + kernel[i] *= scale; |
| + } |
| + return SkNEW_ARGS(GrMatrixConvolutionEffect, (texture, |
| + bounds, |
| + kernelSize, |
| + kernel, |
| + gain, |
| + bias, |
| + kernelOffset, |
| + tileMode, |
| + convolveAlpha, |
| + useBounds)); |
| +} |
| + |
| GR_DEFINE_EFFECT_TEST(GrMatrixConvolutionEffect); |
| GrEffect* GrMatrixConvolutionEffect::TestCreate(SkRandom* random, |
| @@ -257,6 +327,7 @@ GrEffect* GrMatrixConvolutionEffect::TestCreate(SkRandom* random, |
| random->nextRangeU(0, textures[texIdx]->height())); |
| TileMode tileMode = static_cast<TileMode>(random->nextRangeU(0, 2)); |
| bool convolveAlpha = random->nextBool(); |
| + bool useBounds = random->nextBool(); |
| return GrMatrixConvolutionEffect::Create(textures[texIdx], |
| bounds, |
| kernelSize, |
| @@ -265,5 +336,6 @@ GrEffect* GrMatrixConvolutionEffect::TestCreate(SkRandom* random, |
| bias, |
| kernelOffset, |
| tileMode, |
| - convolveAlpha); |
| + convolveAlpha, |
| + useBounds); |
| } |