diff options
author | Robert Phillips <robertphillips@google.com> | 2018-06-20 07:46:19 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-06-20 12:09:00 +0000 |
commit | 4e962c6c248d60fa0b382050a566eed46f0fa10a (patch) | |
tree | f8d365c5bc94d2d22cc41e161fa31b324579abb6 /src/gpu/effects | |
parent | e42cef510026c8e4d1eca49ee709610633d69ff9 (diff) |
Fix degenerate case handling in fill_in_2D_gaussian_kernel
Bug: 849016
Change-Id: Icc46451acd83140cb86593195947efea7f83828d
Reviewed-on: https://skia-review.googlesource.com/135142
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Herb Derby <herb@google.com>
Diffstat (limited to 'src/gpu/effects')
-rw-r--r-- | src/gpu/effects/GrMatrixConvolutionEffect.cpp | 47 |
1 files changed, 43 insertions, 4 deletions
diff --git a/src/gpu/effects/GrMatrixConvolutionEffect.cpp b/src/gpu/effects/GrMatrixConvolutionEffect.cpp index ec2126d520..c2c1f7c8ba 100644 --- a/src/gpu/effects/GrMatrixConvolutionEffect.cpp +++ b/src/gpu/effects/GrMatrixConvolutionEffect.cpp @@ -213,19 +213,58 @@ bool GrMatrixConvolutionEffect::onIsEqual(const GrFragmentProcessor& sBase) cons fDomain == s.domain(); } +static void fill_in_1D_gaussian_kernel_with_stride(float* kernel, int size, int stride, + float twoSigmaSqrd) { + SkASSERT(!SkScalarNearlyZero(twoSigmaSqrd, SK_ScalarNearlyZero)); + + const float sigmaDenom = 1.0f / twoSigmaSqrd; + const int radius = size / 2; + + float sum = 0.0f; + for (int i = 0; i < size; ++i) { + float term = static_cast<float>(i - radius); + // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian + // is dropped here, since we renormalize the kernel below. + kernel[i * stride] = sk_float_exp(-term * term * sigmaDenom); + sum += kernel[i * stride]; + } + // Normalize the kernel + float scale = 1.0f / sum; + for (int i = 0; i < size; ++i) { + kernel[i * stride] *= scale; + } +} + static void fill_in_2D_gaussian_kernel(float* kernel, int width, int height, SkScalar sigmaX, SkScalar sigmaY) { SkASSERT(width * height <= MAX_KERNEL_SIZE); const float twoSigmaSqrdX = 2.0f * SkScalarToFloat(SkScalarSquare(sigmaX)); const float twoSigmaSqrdY = 2.0f * SkScalarToFloat(SkScalarSquare(sigmaY)); + // TODO: in all of these degenerate cases we're uploading (and using) a whole lot of zeros. if (SkScalarNearlyZero(twoSigmaSqrdX, SK_ScalarNearlyZero) || SkScalarNearlyZero(twoSigmaSqrdY, SK_ScalarNearlyZero)) { - SkASSERT(3 == width && 3 == height); - for (int i = 0; i < width * height; ++i) { - kernel[i] = 0.0f; + // In this case the 2D Gaussian degenerates to a 1D Gaussian (in X or Y) or a point + SkASSERT(3 == width || 3 == height); + memset(kernel, 0, width*height*sizeof(float)); + + if (SkScalarNearlyZero(twoSigmaSqrdX, SK_ScalarNearlyZero) && + SkScalarNearlyZero(twoSigmaSqrdY, SK_ScalarNearlyZero)) { + // A point + SkASSERT(3 == width && 3 == height); + kernel[4] = 1.0f; + } else if (SkScalarNearlyZero(twoSigmaSqrdX, SK_ScalarNearlyZero)) { + // A 1D Gaussian in Y + SkASSERT(3 == width); + // Down the middle column of the kernel with a stride of width + fill_in_1D_gaussian_kernel_with_stride(&kernel[1], height, width, twoSigmaSqrdY); + } else { + // A 1D Gaussian in X + SkASSERT(SkScalarNearlyZero(twoSigmaSqrdY, SK_ScalarNearlyZero)); + SkASSERT(3 == height); + // Down the middle row of the kernel with a stride of 1 + fill_in_1D_gaussian_kernel_with_stride(&kernel[width], width, 1, twoSigmaSqrdX); } - kernel[4] = 1.0f; return; } |