aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar joshualitt <joshualitt@chromium.org>2014-08-11 13:55:34 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-08-11 13:55:34 -0700
commit5acfea789d39106dbc706c6ee85cd8f027fce3ed (patch)
treeceec0b44a8cace23a13cdce08e1ffd27437a73ea
parenta10555a354cf294bde217044472d33c3161df249 (diff)
2D kernel initial wiring for Guassian
BUG=skia: R=senorblanco@chromium.org, bsalomon@chromium.org, bsalomon@google.com Author: joshualitt@chromium.org Review URL: https://codereview.chromium.org/418223009
-rw-r--r--bench/BlurBench.cpp8
-rw-r--r--bench/BlurImageFilterBench.cpp3
-rw-r--r--expectations/gm/ignored-tests.txt2
-rw-r--r--gm/imageblur2.cpp96
-rw-r--r--gyp/gmslides.gypi1
-rw-r--r--src/effects/SkGpuBlurUtils.cpp129
-rw-r--r--src/gpu/effects/GrMatrixConvolutionEffect.cpp77
-rw-r--r--src/gpu/effects/GrMatrixConvolutionEffect.h14
8 files changed, 270 insertions, 60 deletions
diff --git a/bench/BlurBench.cpp b/bench/BlurBench.cpp
index cafc6f3a2a..4133adc691 100644
--- a/bench/BlurBench.cpp
+++ b/bench/BlurBench.cpp
@@ -14,6 +14,7 @@
#include "SkShader.h"
#include "SkString.h"
+#define MINI 0.01f
#define SMALL SkIntToScalar(2)
#define REAL 1.5f
#define BIG SkIntToScalar(10)
@@ -78,6 +79,11 @@ private:
typedef Benchmark INHERITED;
};
+DEF_BENCH(return new BlurBench(MINI, kNormal_SkBlurStyle);)
+DEF_BENCH(return new BlurBench(MINI, kSolid_SkBlurStyle);)
+DEF_BENCH(return new BlurBench(MINI, kOuter_SkBlurStyle);)
+DEF_BENCH(return new BlurBench(MINI, kInner_SkBlurStyle);)
+
DEF_BENCH(return new BlurBench(SMALL, kNormal_SkBlurStyle);)
DEF_BENCH(return new BlurBench(SMALL, kSolid_SkBlurStyle);)
DEF_BENCH(return new BlurBench(SMALL, kOuter_SkBlurStyle);)
@@ -98,6 +104,8 @@ DEF_BENCH(return new BlurBench(REAL, kSolid_SkBlurStyle);)
DEF_BENCH(return new BlurBench(REAL, kOuter_SkBlurStyle);)
DEF_BENCH(return new BlurBench(REAL, kInner_SkBlurStyle);)
+DEF_BENCH(return new BlurBench(MINI, kNormal_SkBlurStyle, SkBlurMaskFilter::kHighQuality_BlurFlag);)
+
DEF_BENCH(return new BlurBench(SMALL, kNormal_SkBlurStyle, SkBlurMaskFilter::kHighQuality_BlurFlag);)
DEF_BENCH(return new BlurBench(BIG, kNormal_SkBlurStyle, SkBlurMaskFilter::kHighQuality_BlurFlag);)
diff --git a/bench/BlurImageFilterBench.cpp b/bench/BlurImageFilterBench.cpp
index 4e8688d9e3..9021d1b1d2 100644
--- a/bench/BlurImageFilterBench.cpp
+++ b/bench/BlurImageFilterBench.cpp
@@ -17,6 +17,7 @@
#define FILTER_HEIGHT_SMALL 32
#define FILTER_WIDTH_LARGE 256
#define FILTER_HEIGHT_LARGE 256
+#define BLUR_SIGMA_MINI 0.5f
#define BLUR_SIGMA_SMALL 1.0f
#define BLUR_SIGMA_LARGE 10.0f
#define BLUR_SIGMA_HUGE 80.0f
@@ -86,6 +87,8 @@ DEF_BENCH(return new BlurImageFilterBench(BLUR_SIGMA_LARGE, 0, false);)
DEF_BENCH(return new BlurImageFilterBench(BLUR_SIGMA_SMALL, 0, false);)
DEF_BENCH(return new BlurImageFilterBench(0, BLUR_SIGMA_LARGE, false);)
DEF_BENCH(return new BlurImageFilterBench(0, BLUR_SIGMA_SMALL, false);)
+DEF_BENCH(return new BlurImageFilterBench(BLUR_SIGMA_MINI, BLUR_SIGMA_MINI, true);)
+DEF_BENCH(return new BlurImageFilterBench(BLUR_SIGMA_MINI, BLUR_SIGMA_MINI, false);)
DEF_BENCH(return new BlurImageFilterBench(BLUR_SIGMA_SMALL, BLUR_SIGMA_SMALL, true);)
DEF_BENCH(return new BlurImageFilterBench(BLUR_SIGMA_SMALL, BLUR_SIGMA_SMALL, false);)
DEF_BENCH(return new BlurImageFilterBench(BLUR_SIGMA_LARGE, BLUR_SIGMA_LARGE, true);)
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt
index 226482c40d..241ce18649 100644
--- a/expectations/gm/ignored-tests.txt
+++ b/expectations/gm/ignored-tests.txt
@@ -59,3 +59,5 @@ circles
simpleaaclip_rect
complexclip2_rect_aa
+#joshualitt
+matrixconvolution \ No newline at end of file
diff --git a/gm/imageblur2.cpp b/gm/imageblur2.cpp
new file mode 100644
index 0000000000..b7c9f9d9c8
--- /dev/null
+++ b/gm/imageblur2.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkBlurImageFilter.h"
+#include "SkRandom.h"
+
+// TODO deprecate imageblur
+
+#define WIDTH 500
+#define HEIGHT 500
+
+static const float kBlurSigmas[] = {
+ 0.0, 0.3f, 0.5f, 2.0f, 32.0f, 80.0f };
+
+const char* kTestStrings[] = {
+ "The quick`~",
+ "brown fox[]",
+ "jumped over",
+ "the lazy@#$",
+ "dog.{}!%^&",
+ "*()+=-\\'\"/",
+};
+
+namespace skiagm {
+
+class BlurImageFilter : public GM {
+public:
+ BlurImageFilter() {
+ this->setBGColor(0xFFFFFFFF);
+ fName.printf("imageblur2");
+ }
+
+protected:
+ virtual uint32_t onGetFlags() const SK_OVERRIDE {
+ return kSkipTiled_Flag;
+ }
+
+ virtual SkString onShortName() {
+ return fName;
+ }
+
+ virtual SkISize onISize() {
+ return SkISize::Make(WIDTH, HEIGHT);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ const int sigmaCount = SK_ARRAY_COUNT(kBlurSigmas);
+ const int testStringCount = SK_ARRAY_COUNT(kTestStrings);
+ SkScalar dx = WIDTH / sigmaCount;
+ SkScalar dy = HEIGHT / sigmaCount;
+ const SkScalar textSize = 12;
+
+ for (int x = 0; x < sigmaCount; x++) {
+ SkScalar sigmaX = kBlurSigmas[x];
+ for (int y = 0; y < sigmaCount; y++) {
+ SkScalar sigmaY = kBlurSigmas[y];
+
+ SkPaint paint;
+ paint.setImageFilter(SkBlurImageFilter::Create(sigmaX, sigmaY))->unref();
+ canvas->saveLayer(NULL, &paint);
+
+ SkRandom rand;
+ SkPaint textPaint;
+ textPaint.setAntiAlias(false);
+ textPaint.setColor(rand.nextBits(24) | 0xFF000000);
+ textPaint.setTextSize(textSize);
+
+ for (int i = 0; i < testStringCount; i++) {
+ canvas->drawText(kTestStrings[i],
+ strlen(kTestStrings[i]),
+ SkIntToScalar(x * dx),
+ SkIntToScalar(y * dy + textSize * i + textSize),
+ textPaint);
+ }
+ canvas->restore();
+ }
+ }
+ }
+
+private:
+ SkString fName;
+
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new BlurImageFilter; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi
index fbd2462531..e1cb1a6fd8 100644
--- a/gyp/gmslides.gypi
+++ b/gyp/gmslides.gypi
@@ -96,6 +96,7 @@
'../gm/hittestpath.cpp',
'../gm/imagealphathreshold.cpp',
'../gm/imageblur.cpp',
+ '../gm/imageblur2.cpp',
'../gm/imageblurtiled.cpp',
'../gm/imagemagnifier.cpp',
'../gm/imageresizetiled.cpp',
diff --git a/src/effects/SkGpuBlurUtils.cpp b/src/effects/SkGpuBlurUtils.cpp
index 5888108755..aa7f9952f9 100644
--- a/src/effects/SkGpuBlurUtils.cpp
+++ b/src/effects/SkGpuBlurUtils.cpp
@@ -11,7 +11,7 @@
#if SK_SUPPORT_GPU
#include "effects/GrConvolutionEffect.h"
-#include "effects/GrTextureDomain.h"
+#include "effects/GrMatrixConvolutionEffect.h"
#include "GrContext.h"
#endif
@@ -43,15 +43,15 @@ static float adjust_sigma(float sigma, int maxTextureSize, int *scaleFactor, int
return sigma;
}
-static void convolve_gaussian_pass(GrContext* context,
- const SkRect& srcRect,
- const SkRect& dstRect,
- GrTexture* texture,
- Gr1DKernelEffect::Direction direction,
- int radius,
- float sigma,
- bool useBounds,
- float bounds[2]) {
+static void convolve_gaussian_1d(GrContext* context,
+ const SkRect& srcRect,
+ const SkRect& dstRect,
+ GrTexture* texture,
+ Gr1DKernelEffect::Direction direction,
+ int radius,
+ float sigma,
+ bool useBounds,
+ float bounds[2]) {
GrPaint paint;
paint.reset();
SkAutoTUnref<GrEffect> conv(GrConvolutionEffect::CreateGaussian(
@@ -61,6 +61,29 @@ static void convolve_gaussian_pass(GrContext* context,
context->drawRectToRect(paint, dstRect, srcRect);
}
+static void convolve_gaussian_2d(GrContext* context,
+ const SkRect& srcRect,
+ const SkRect& dstRect,
+ GrTexture* texture,
+ int radiusX,
+ int radiusY,
+ SkScalar sigmaX,
+ SkScalar sigmaY,
+ bool useBounds,
+ SkIRect bounds) {
+ SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1);
+ SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY);
+ GrPaint paint;
+ paint.reset();
+ SkAutoTUnref<GrEffect> conv(GrMatrixConvolutionEffect::CreateGaussian(
+ texture, bounds, size, 1.0, 0.0, kernelOffset,
+ useBounds ? GrTextureDomain::kClamp_Mode : GrTextureDomain::kIgnore_Mode,
+ true, sigmaX, sigmaY));
+ paint.reset();
+ paint.addColorEffect(conv);
+ context->drawRectToRect(paint, dstRect, srcRect);
+}
+
static void convolve_gaussian(GrContext* context,
const SkRect& srcRect,
const SkRect& dstRect,
@@ -71,8 +94,8 @@ static void convolve_gaussian(GrContext* context,
bool cropToSrcRect) {
float bounds[2] = { 0.0f, 1.0f };
if (!cropToSrcRect) {
- convolve_gaussian_pass(context, srcRect, dstRect, texture,
- direction, radius, sigma, false, bounds);
+ convolve_gaussian_1d(context, srcRect, dstRect, texture,
+ direction, radius, sigma, false, bounds);
return;
}
SkRect lowerSrcRect = srcRect, lowerDstRect = dstRect;
@@ -103,16 +126,16 @@ static void convolve_gaussian(GrContext* context,
}
if (radius >= size * SK_ScalarHalf) {
// Blur radius covers srcRect; use bounds over entire draw
- convolve_gaussian_pass(context, srcRect, dstRect, texture,
- direction, radius, sigma, true, bounds);
+ convolve_gaussian_1d(context, srcRect, dstRect, texture,
+ direction, radius, sigma, true, bounds);
} else {
// Draw upper and lower margins with bounds; middle without.
- convolve_gaussian_pass(context, lowerSrcRect, lowerDstRect, texture,
- direction, radius, sigma, true, bounds);
- convolve_gaussian_pass(context, upperSrcRect, upperDstRect, texture,
- direction, radius, sigma, true, bounds);
- convolve_gaussian_pass(context, middleSrcRect, middleDstRect, texture,
- direction, radius, sigma, false, bounds);
+ convolve_gaussian_1d(context, lowerSrcRect, lowerDstRect, texture,
+ direction, radius, sigma, true, bounds);
+ convolve_gaussian_1d(context, upperSrcRect, upperDstRect, texture,
+ direction, radius, sigma, true, bounds);
+ convolve_gaussian_1d(context, middleSrcRect, middleDstRect, texture,
+ direction, radius, sigma, false, bounds);
}
}
@@ -196,39 +219,55 @@ GrTexture* GaussianBlur(GrContext* context,
SkIRect srcIRect;
srcRect.roundOut(&srcIRect);
- if (sigmaX > 0.0f) {
- if (scaleFactorX > 1) {
- // Clear out a radius to the right of the srcRect to prevent the
- // X convolution from reading garbage.
- clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
- radiusX, srcIRect.height());
- context->clear(&clearRect, 0x0, false);
- }
+ // For really small blurs(Certainly no wider than 5x5 on desktop gpus) it is faster to just
+ // launch a single non separable kernel vs two launches
+ if (sigmaX > 0.0f && sigmaY > 0 &&
+ (2 * radiusX + 1) * (2 * radiusY + 1) <= MAX_KERNEL_SIZE) {
+ // We shouldn't be scaling because this is a small size blur
+ SkASSERT((scaleFactorX == scaleFactorY) == 1);
context->setRenderTarget(dstTexture->asRenderTarget());
SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
- convolve_gaussian(context, srcRect, dstRect, srcTexture,
- Gr1DKernelEffect::kX_Direction, radiusX, sigmaX, cropToRect);
+ convolve_gaussian_2d(context, srcRect, dstRect, srcTexture,
+ radiusX, radiusY, sigmaX, sigmaY, cropToRect, srcIRect);
srcTexture = dstTexture;
srcRect = dstRect;
SkTSwap(dstTexture, tempTexture);
- }
- if (sigmaY > 0.0f) {
- if (scaleFactorY > 1 || sigmaX > 0.0f) {
- // Clear out a radius below the srcRect to prevent the Y
- // convolution from reading garbage.
- clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
- srcIRect.width(), radiusY);
- context->clear(&clearRect, 0x0, false);
+ } else {
+ if (sigmaX > 0.0f) {
+ if (scaleFactorX > 1) {
+ // Clear out a radius to the right of the srcRect to prevent the
+ // X convolution from reading garbage.
+ clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
+ radiusX, srcIRect.height());
+ context->clear(&clearRect, 0x0, false);
+ }
+ context->setRenderTarget(dstTexture->asRenderTarget());
+ SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
+ convolve_gaussian(context, srcRect, dstRect, srcTexture,
+ Gr1DKernelEffect::kX_Direction, radiusX, sigmaX, cropToRect);
+ srcTexture = dstTexture;
+ srcRect = dstRect;
+ SkTSwap(dstTexture, tempTexture);
}
- context->setRenderTarget(dstTexture->asRenderTarget());
- SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
- convolve_gaussian(context, srcRect, dstRect, srcTexture,
- Gr1DKernelEffect::kY_Direction, radiusY, sigmaY, cropToRect);
- srcTexture = dstTexture;
- srcRect = dstRect;
- SkTSwap(dstTexture, tempTexture);
+ if (sigmaY > 0.0f) {
+ if (scaleFactorY > 1 || sigmaX > 0.0f) {
+ // Clear out a radius below the srcRect to prevent the Y
+ // convolution from reading garbage.
+ clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
+ srcIRect.width(), radiusY);
+ context->clear(&clearRect, 0x0, false);
+ }
+
+ context->setRenderTarget(dstTexture->asRenderTarget());
+ SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
+ convolve_gaussian(context, srcRect, dstRect, srcTexture,
+ Gr1DKernelEffect::kY_Direction, radiusY, sigmaY, cropToRect);
+ srcTexture = dstTexture;
+ srcRect = dstRect;
+ SkTSwap(dstTexture, tempTexture);
+ }
}
if (scaleFactorX > 1 || scaleFactorY > 1) {
diff --git a/src/gpu/effects/GrMatrixConvolutionEffect.cpp b/src/gpu/effects/GrMatrixConvolutionEffect.cpp
index 242aba8f86..01cf944592 100644
--- a/src/gpu/effects/GrMatrixConvolutionEffect.cpp
+++ b/src/gpu/effects/GrMatrixConvolutionEffect.cpp
@@ -84,34 +84,38 @@ void GrGLMatrixConvolutionEffect::emitCode(GrGLShaderBuilder* builder,
int kWidth = fKernelSize.width();
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,
+ builder->fsCodeAppend("vec4 sum = vec4(0, 0, 0, 0);");
+ builder->fsCodeAppendf("vec2 coord = %s - %s * %s;", coords2D.c_str(), kernelOffset,
imgInc);
- builder->fsCodeAppend("\t\tvec4 c;\n");
+ builder->fsCodeAppend("vec4 c;");
for (int y = 0; y < kHeight; y++) {
for (int x = 0; x < kWidth; x++) {
GrGLShaderBuilder::FSBlock block(builder);
- builder->fsCodeAppendf("\t\tfloat k = %s[%d * %d + %d];\n", kernel, y, kWidth, x);
+ builder->fsCodeAppendf("float k = %s[%d * %d + %d];", kernel, y, kWidth, x);
SkString coord;
coord.printf("coord + vec2(%d, %d) * %s", x, y, imgInc);
fDomain.sampleTexture(builder, domain, "c", coord, samplers[0]);
if (!fConvolveAlpha) {
- builder->fsCodeAppend("\t\tc.rgb /= c.a;\n");
+ builder->fsCodeAppend("c.rgb /= c.a;");
}
- builder->fsCodeAppend("\t\tsum += c * k;\n");
+ builder->fsCodeAppend("sum += c * k;");
}
}
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",
+ builder->fsCodeAppendf("%s = sum * %s + %s;", outputColor, gain, bias);
+ builder->fsCodeAppendf("%s.rgb = clamp(%s.rgb, 0.0, %s.a);",
outputColor, outputColor, outputColor);
} else {
fDomain.sampleTexture(builder, domain, "c", coords2D, samplers[0]);
- builder->fsCodeAppendf("\t\t%s.a = c.a;\n", outputColor);
- builder->fsCodeAppendf("\t\t%s.rgb = sum.rgb * %s + %s;\n", outputColor, gain, bias);
- builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
+ builder->fsCodeAppendf("%s.a = c.a;", outputColor);
+ builder->fsCodeAppendf("%s.rgb = sum.rgb * %s + %s;", outputColor, gain, bias);
+ builder->fsCodeAppendf("%s.rgb *= %s.a;", outputColor, outputColor);
}
+
+ SkString modulate;
+ GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
+ builder->fsCodeAppend(modulate.c_str());
}
void GrGLMatrixConvolutionEffect::GenKey(const GrDrawEffect& drawEffect,
@@ -157,17 +161,14 @@ GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(GrTexture* texture,
fBias(SkScalarToFloat(bias) / 255.0f),
fConvolveAlpha(convolveAlpha),
fDomain(GrTextureDomain::MakeTexelDomain(texture, bounds), tileMode) {
- fKernel = new float[kernelSize.width() * kernelSize.height()];
for (int i = 0; i < kernelSize.width() * kernelSize.height(); i++) {
fKernel[i] = SkScalarToFloat(kernel[i]);
}
fKernelOffset[0] = static_cast<float>(kernelOffset.x());
fKernelOffset[1] = static_cast<float>(kernelOffset.y());
- this->setWillNotUseInputColor();
}
GrMatrixConvolutionEffect::~GrMatrixConvolutionEffect() {
- delete[] fKernel;
}
const GrBackendEffectFactory& GrMatrixConvolutionEffect::getFactory() const {
@@ -187,6 +188,54 @@ bool GrMatrixConvolutionEffect::onIsEqual(const GrEffect& sBase) const {
fDomain == s.domain();
}
+// 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,
+ GrTextureDomain::Mode tileMode,
+ bool convolveAlpha,
+ 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.0f / (2.0f * SkScalarToFloat(SkScalarSquare(sigmaX)));
+ float sigmaYDenom = 1.0f / (2.0f * SkScalarToFloat(SkScalarSquare(sigmaY)));
+ int xRadius = width / 2;
+ int yRadius = height / 2;
+ for (int x = 0; x < width; x++) {
+ float xTerm = static_cast<float>(x - xRadius);
+ xTerm = xTerm * xTerm * sigmaXDenom;
+ for (int y = 0; y < height; y++) {
+ float yTerm = static_cast<float>(y - yRadius);
+ float xyTerm = sk_float_exp(-(xTerm + yTerm * 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));
+}
+
GR_DEFINE_EFFECT_TEST(GrMatrixConvolutionEffect);
GrEffect* GrMatrixConvolutionEffect::TestCreate(SkRandom* random,
diff --git a/src/gpu/effects/GrMatrixConvolutionEffect.h b/src/gpu/effects/GrMatrixConvolutionEffect.h
index 24c3bdb285..814299f2d1 100644
--- a/src/gpu/effects/GrMatrixConvolutionEffect.h
+++ b/src/gpu/effects/GrMatrixConvolutionEffect.h
@@ -38,6 +38,18 @@ public:
tileMode,
convolveAlpha));
}
+
+ static GrEffect* CreateGaussian(GrTexture* texture,
+ const SkIRect& bounds,
+ const SkISize& kernelSize,
+ SkScalar gain,
+ SkScalar bias,
+ const SkIPoint& kernelOffset,
+ GrTextureDomain::Mode tileMode,
+ bool convolveAlpha,
+ SkScalar sigmaX,
+ SkScalar sigmaY);
+
virtual ~GrMatrixConvolutionEffect();
virtual void getConstantColorComponents(GrColor* color,
@@ -75,7 +87,7 @@ private:
SkIRect fBounds;
SkISize fKernelSize;
- float* fKernel;
+ float fKernel[MAX_KERNEL_SIZE];
float fGain;
float fBias;
float fKernelOffset[2];