Fix for crash on large image blur sigma values.
This was crashing on the GPU path, due to a failed texture allocation. The belt-and-suspenders fix is to: 1) Limit the GPU path to only allocate up to maxTextureSize. 2) Limit both the raster and GPU paths to reasonable blur sizes (box blur kernel size of 1000, resulting in a sigma limit of 532). R=bsalomon@google.com BUG=skia: Review URL: https://codereview.chromium.org/209353014 git-svn-id: http://skia.googlecode.com/svn/trunk@13923 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
7b78981b4c
commit
09843fd5c1
@ -16,6 +16,13 @@
|
||||
#include "GrContext.h"
|
||||
#endif
|
||||
|
||||
// This rather arbitrary-looking value results in a maximum box blur kernel size
|
||||
// of 1000 pixels on the raster path, which matches the WebKit and Firefox
|
||||
// implementations. Since the GPU path does not compute a box blur, putting
|
||||
// the limit on sigma ensures consistent behaviour between the GPU and
|
||||
// raster paths.
|
||||
#define MAX_SIGMA SkIntToScalar(532)
|
||||
|
||||
SkBlurImageFilter::SkBlurImageFilter(SkReadBuffer& buffer)
|
||||
: INHERITED(1, buffer) {
|
||||
fSigma.fWidth = buffer.readScalar();
|
||||
@ -164,6 +171,8 @@ bool SkBlurImageFilter::onFilterImage(Proxy* proxy,
|
||||
|
||||
SkVector sigma, localSigma = SkVector::Make(fSigma.width(), fSigma.height());
|
||||
ctx.ctm().mapVectors(&sigma, &localSigma, 1);
|
||||
sigma.fX = SkMinScalar(sigma.fX, MAX_SIGMA);
|
||||
sigma.fY = SkMinScalar(sigma.fY, MAX_SIGMA);
|
||||
|
||||
int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX;
|
||||
int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY;
|
||||
@ -263,6 +272,8 @@ bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const
|
||||
GrTexture* source = input.getTexture();
|
||||
SkVector sigma, localSigma = SkVector::Make(fSigma.width(), fSigma.height());
|
||||
ctx.ctm().mapVectors(&sigma, &localSigma, 1);
|
||||
sigma.fX = SkMinScalar(sigma.fX, MAX_SIGMA);
|
||||
sigma.fY = SkMinScalar(sigma.fY, MAX_SIGMA);
|
||||
offset->fX = rect.fLeft;
|
||||
offset->fY = rect.fTop;
|
||||
rect.offset(-srcOffset);
|
||||
|
@ -28,11 +28,15 @@ static void scale_rect(SkRect* rect, float xScale, float yScale) {
|
||||
rect->fBottom = SkScalarMul(rect->fBottom, yScale);
|
||||
}
|
||||
|
||||
static float adjust_sigma(float sigma, int *scaleFactor, int *radius) {
|
||||
static float adjust_sigma(float sigma, int maxTextureSize, int *scaleFactor, int *radius) {
|
||||
*scaleFactor = 1;
|
||||
while (sigma > MAX_BLUR_SIGMA) {
|
||||
*scaleFactor *= 2;
|
||||
sigma *= 0.5f;
|
||||
if (*scaleFactor > maxTextureSize) {
|
||||
*scaleFactor = maxTextureSize;
|
||||
sigma = MAX_BLUR_SIGMA;
|
||||
}
|
||||
}
|
||||
*radius = static_cast<int>(ceilf(sigma * 3.0f));
|
||||
SkASSERT(*radius <= GrConvolutionEffect::kMaxKernelRadius);
|
||||
@ -129,8 +133,9 @@ GrTexture* GaussianBlur(GrContext* context,
|
||||
SkIRect clearRect;
|
||||
int scaleFactorX, radiusX;
|
||||
int scaleFactorY, radiusY;
|
||||
sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &radiusX);
|
||||
sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &radiusY);
|
||||
int maxTextureSize = context->getMaxTextureSize();
|
||||
sigmaX = adjust_sigma(sigmaX, maxTextureSize, &scaleFactorX, &radiusX);
|
||||
sigmaY = adjust_sigma(sigmaY, maxTextureSize, &scaleFactorY, &radiusY);
|
||||
|
||||
SkRect srcRect(rect);
|
||||
scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
|
||||
|
@ -295,6 +295,29 @@ DEF_TEST(ImageFilterMatrixTest, reporter) {
|
||||
canvas.drawPicture(picture);
|
||||
}
|
||||
|
||||
void test_huge_blur(SkBaseDevice* device, skiatest::Reporter* reporter) {
|
||||
SkCanvas canvas(device);
|
||||
|
||||
SkBitmap bitmap;
|
||||
bitmap.allocN32Pixels(100, 100);
|
||||
bitmap.eraseARGB(0, 0, 0, 0);
|
||||
|
||||
// Check that a blur with an insane radius does not crash or assert.
|
||||
SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(SkIntToScalar(1<<30), SkIntToScalar(1<<30)));
|
||||
|
||||
SkPaint paint;
|
||||
paint.setImageFilter(blur);
|
||||
canvas.drawSprite(bitmap, 0, 0, &paint);
|
||||
}
|
||||
|
||||
DEF_TEST(HugeBlurImageFilter, reporter) {
|
||||
SkBitmap temp;
|
||||
temp.allocN32Pixels(100, 100);
|
||||
SkBitmapDevice device(temp);
|
||||
test_huge_blur(&device, reporter);
|
||||
}
|
||||
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
DEF_GPUTEST(ImageFilterCropRectGPU, reporter, factory) {
|
||||
GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
|
||||
@ -303,4 +326,12 @@ DEF_GPUTEST(ImageFilterCropRectGPU, reporter, factory) {
|
||||
0));
|
||||
test_crop_rects(device, reporter);
|
||||
}
|
||||
|
||||
DEF_GPUTEST(HugeBlurImageFilterGPU, reporter, factory) {
|
||||
GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
|
||||
SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
|
||||
SkImageInfo::MakeN32Premul(100, 100),
|
||||
0));
|
||||
test_huge_blur(device, reporter);
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user