aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-11-09 16:05:58 +0000
committerGravatar senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-11-09 16:05:58 +0000
commit60014ca38710d3fc265f4376b05c0fefd0e044cf (patch)
treee8d3a0d9228caccd4e0f704175f4340dc4302293
parent82c7bd8f25682fcacfeea12ed899976504a767ff (diff)
Implement Gaussian blurs for images. The caller creates an an
SkBlurImageFilter, sets it on an SkPaint, passes that paint to saveLayer(), draws the primitives which are to be blurred, then calls restore(), which applies the blur. The blurs have separate sizes in the horizontal and vertical direction. This feature is GPU-only for now. NB: Due to the clipping change, there are slight pixel differences on the blurs_gpu and shadows_gpu tests, so those will require rebaselining on all platforms, as will some of the WebKit layout tests (TBD). Review URL: http://codereview.appspot.com/5322068/ git-svn-id: http://skia.googlecode.com/svn/trunk@2643 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--gm/imageblur.cpp57
-rw-r--r--gyp/effects.gyp2
-rw-r--r--gyp/gmslides.gypi1
-rw-r--r--include/effects/SkBlurImageFilter.h23
-rw-r--r--include/gpu/GrConfig.h2
-rw-r--r--src/effects/SkBlurImageFilter.cpp18
-rw-r--r--src/gpu/GrContext.cpp8
-rw-r--r--src/gpu/SkGpuDevice.cpp314
8 files changed, 294 insertions, 131 deletions
diff --git a/gm/imageblur.cpp b/gm/imageblur.cpp
new file mode 100644
index 0000000000..fe9d6c29ac
--- /dev/null
+++ b/gm/imageblur.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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"
+
+namespace skiagm {
+
+class ImageBlurGM : public GM {
+public:
+ ImageBlurGM() {
+ this->setBGColor(0xFF000000);
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("imageblur");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(500, 500);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setImageFilter(new SkBlurImageFilter(24.0f, 0.0f))->unref();
+ canvas->saveLayer(NULL, &paint);
+ paint.setColor(0xFFFFFFFF);
+ paint.setTextSize(100);
+ paint.setAntiAlias(true);
+ const char* str = "The quick brown fox jumped over the lazy dog.";
+ srand(1234);
+ SkISize size = canvas->getDeviceSize();
+ for (int i = 0; i < 25; ++i) {
+ int x = rand() % size.fWidth;
+ int y = rand() % size.fHeight;
+ paint.setColor(rand() % 0x1000000 | 0xFF000000);
+ paint.setTextSize(rand() % 300);
+ canvas->drawText(str, strlen(str), x, y, paint);
+ }
+ canvas->restore();
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new ImageBlurGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gyp/effects.gyp b/gyp/effects.gyp
index 3b6783833b..81e8fa86f5 100644
--- a/gyp/effects.gyp
+++ b/gyp/effects.gyp
@@ -16,6 +16,7 @@
'../include/effects/Sk2DPathEffect.h',
'../include/effects/SkAvoidXfermode.h',
'../include/effects/SkBlurDrawLooper.h',
+ '../include/effects/SkBlurImageFilter.h',
'../include/effects/SkBlurMaskFilter.h',
'../include/effects/SkColorMatrix.h',
'../include/effects/SkColorMatrixFilter.h',
@@ -43,6 +44,7 @@
'../src/effects/SkBlurDrawLooper.cpp',
'../src/effects/SkBlurMask.cpp',
'../src/effects/SkBlurMask.h',
+ '../src/effects/SkBlurImageFilter.cpp',
'../src/effects/SkBlurMaskFilter.cpp',
'../src/effects/SkColorFilters.cpp',
'../src/effects/SkColorMatrixFilter.cpp',
diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi
index 8a97b0c685..3eb66045f6 100644
--- a/gyp/gmslides.gypi
+++ b/gyp/gmslides.gypi
@@ -13,6 +13,7 @@
'../gm/fontscaler.cpp',
'../gm/gradients.cpp',
'../gm/hairmodes.cpp',
+ '../gm/imageblur.cpp',
'../gm/lcdtext.cpp',
'../gm/ninepatchstretch.cpp',
'../gm/nocolorbleed.cpp',
diff --git a/include/effects/SkBlurImageFilter.h b/include/effects/SkBlurImageFilter.h
new file mode 100644
index 0000000000..ceab31a861
--- /dev/null
+++ b/include/effects/SkBlurImageFilter.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkBlurImageFilter_DEFINED
+#define SkBlurImageFilter_DEFINED
+
+#include "SkImageFilter.h"
+
+class SK_API SkBlurImageFilter : public SkImageFilter {
+public:
+ SkBlurImageFilter(SkScalar sigmaX, SkScalar sigmaY);
+ virtual bool asABlur(SkSize* sigma) const;
+private:
+ SkSize fSigma;
+};
+
+#endif
+
diff --git a/include/gpu/GrConfig.h b/include/gpu/GrConfig.h
index bc71792305..d6037f4f97 100644
--- a/include/gpu/GrConfig.h
+++ b/include/gpu/GrConfig.h
@@ -351,7 +351,7 @@ inline void GrCrash(const char* msg) { GrPrintf(msg); GrAlwaysAssert(false); }
* program.
*/
#if !defined(GR_AGGRESSIVE_SHADER_OPTS)
- #define GR_AGGRESSIVE_SHADER_OPTS 0
+ #define GR_AGGRESSIVE_SHADER_OPTS 1
#endif
/**
diff --git a/src/effects/SkBlurImageFilter.cpp b/src/effects/SkBlurImageFilter.cpp
new file mode 100644
index 0000000000..7777f316a3
--- /dev/null
+++ b/src/effects/SkBlurImageFilter.cpp
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBlurImageFilter.h"
+
+SkBlurImageFilter::SkBlurImageFilter(SkScalar sigmaX, SkScalar sigmaY)
+ : fSigma(SkSize::Make(sigmaX, sigmaY)) {
+ SkASSERT(sigmaX >= 0 && sigmaY >= 0);
+}
+
+bool SkBlurImageFilter::asABlur(SkSize* sigma) const {
+ *sigma = fSigma;
+ return true;
+}
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 74ed582e2a..2ccd843839 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -2008,7 +2008,7 @@ void GrContext::convolveInX(GrTexture* texture,
const SkRect& rect,
const float* kernel,
int kernelWidth) {
- float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
+ float imageIncrement[2] = {1.0f / texture->allocatedWidth(), 0.0f};
convolve(texture, rect, imageIncrement, kernel, kernelWidth);
}
@@ -2016,7 +2016,7 @@ void GrContext::convolveInY(GrTexture* texture,
const SkRect& rect,
const float* kernel,
int kernelWidth) {
- float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
+ float imageIncrement[2] = {0.0f, 1.0f / texture->allocatedHeight()};
convolve(texture, rect, imageIncrement, kernel, kernelWidth);
}
@@ -2031,12 +2031,12 @@ void GrContext::convolve(GrTexture* texture,
GrSamplerState::kClamp_WrapMode,
GrSamplerState::kConvolution_Filter);
sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
- sampleM.setScale(GR_Scalar1 / texture->width(),
- GR_Scalar1 / texture->height());
+ sampleM.setIDiv(texture->width(), texture->height());
sampler.setMatrix(sampleM);
fGpu->setSamplerState(0, sampler);
fGpu->setViewMatrix(GrMatrix::I());
fGpu->setTexture(0, texture);
+ fGpu->setColor(0xFFFFFFFF);
fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
fGpu->drawSimpleRect(rect, NULL, 1 << 0);
}
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 031333bc28..8ad951dacd 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -17,6 +17,7 @@
#include "SkColorFilter.h"
#include "SkDrawProcs.h"
#include "SkGlyphCache.h"
+#include "SkImageFilter.h"
#include "SkTLazy.h"
#include "SkUtils.h"
@@ -689,11 +690,149 @@ static void buildKernel(float sigma, float* kernel, int kernelWidth) {
kernel[i] *= scale;
}
-static void scaleRect(SkRect* rect, float scale) {
- rect->fLeft *= scale;
- rect->fTop *= scale;
- rect->fRight *= scale;
- rect->fBottom *= scale;
+static void scaleRect(SkRect* rect, float xScale, float yScale) {
+ rect->fLeft *= xScale;
+ rect->fTop *= yScale;
+ rect->fRight *= xScale;
+ rect->fBottom *= yScale;
+}
+
+static float adjustSigma(float sigma, int *scaleFactor, int *halfWidth,
+ int *kernelWidth) {
+ *scaleFactor = 1;
+ while (sigma > MAX_BLUR_SIGMA) {
+ *scaleFactor *= 2;
+ sigma *= 0.5f;
+ }
+ *halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
+ *kernelWidth = *halfWidth * 2 + 1;
+ return sigma;
+}
+
+// Apply a Gaussian blur to srcTexture by sigmaX and sigmaY, within the given
+// rect.
+// temp1 and temp2 are used for allocation of intermediate textures.
+// If temp2 is non-NULL, srcTexture will be untouched, and the return
+// value will be either temp1 or temp2.
+// If temp2 is NULL, srcTexture will be overwritten with intermediate
+// results, and the return value will either be temp1 or srcTexture.
+static GrTexture* gaussianBlur(GrContext* context, GrTexture* srcTexture,
+ GrAutoScratchTexture* temp1,
+ GrAutoScratchTexture* temp2,
+ const SkRect& rect,
+ float sigmaX, float sigmaY) {
+
+ GrRenderTarget* oldRenderTarget = context->getRenderTarget();
+ GrClip oldClip = context->getClip();
+ GrTexture* origTexture = srcTexture;
+ GrAutoMatrix avm(context, GrMatrix::I());
+ SkIRect clearRect;
+ int scaleFactorX, halfWidthX, kernelWidthX;
+ int scaleFactorY, halfWidthY, kernelWidthY;
+ sigmaX = adjustSigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
+ sigmaY = adjustSigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
+
+ SkRect srcRect(rect);
+ scaleRect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
+ srcRect.roundOut();
+ scaleRect(&srcRect, scaleFactorX, scaleFactorY);
+ context->setClip(srcRect);
+
+ const GrTextureDesc desc = {
+ kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
+ kNone_GrAALevel,
+ srcRect.width(),
+ srcRect.height(),
+ kRGBA_8888_GrPixelConfig
+ };
+
+ temp1->set(context, desc);
+ if (temp2) temp2->set(context, desc);
+
+ GrTexture* dstTexture = temp1->texture();
+ GrPaint paint;
+ paint.reset();
+ paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
+
+ for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
+ GrMatrix sampleM;
+ sampleM.setIDiv(srcTexture->width(), srcTexture->height());
+ paint.getTextureSampler(0)->setMatrix(sampleM);
+ context->setRenderTarget(dstTexture->asRenderTarget());
+ SkRect dstRect(srcRect);
+ scaleRect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
+ i < scaleFactorY ? 0.5f : 1.0f);
+ paint.setTexture(0, srcTexture);
+ context->drawRectToRect(paint, dstRect, srcRect);
+ srcRect = dstRect;
+ SkTSwap(srcTexture, dstTexture);
+ // If temp2 is non-NULL, don't render back to origTexture
+ if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
+ }
+
+ if (sigmaX > 0.0f) {
+ SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
+ float* kernelX = kernelStorageX.get();
+ buildKernel(sigmaX, kernelX, kernelWidthX);
+
+ if (scaleFactorX > 1) {
+ // Clear out a halfWidth to the right of the srcRect to prevent the
+ // X convolution from reading garbage.
+ clearRect = SkIRect::MakeXYWH(
+ srcRect.fRight, srcRect.fTop, halfWidthX, srcRect.height());
+ context->clear(&clearRect, 0x0);
+ }
+
+ context->setRenderTarget(dstTexture->asRenderTarget());
+ context->convolveInX(srcTexture, srcRect, kernelX, kernelWidthX);
+ SkTSwap(srcTexture, dstTexture);
+ if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
+ }
+
+ if (sigmaY > 0.0f) {
+ SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
+ float* kernelY = kernelStorageY.get();
+ buildKernel(sigmaY, kernelY, kernelWidthY);
+
+ if (scaleFactorY > 1 || sigmaX > 0.0f) {
+ // Clear out a halfWidth below the srcRect to prevent the Y
+ // convolution from reading garbage.
+ clearRect = SkIRect::MakeXYWH(
+ srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidthY);
+ context->clear(&clearRect, 0x0);
+ }
+
+ context->setRenderTarget(dstTexture->asRenderTarget());
+ context->convolveInY(srcTexture, srcRect, kernelY, kernelWidthY);
+ SkTSwap(srcTexture, dstTexture);
+ if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
+ }
+
+ if (scaleFactorX > 1 || scaleFactorY > 1) {
+ // Clear one pixel to the right and below, to accommodate bilinear
+ // upsampling.
+ clearRect = SkIRect::MakeXYWH(
+ srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
+ context->clear(&clearRect, 0x0);
+ clearRect = SkIRect::MakeXYWH(
+ srcRect.fRight, srcRect.fTop, 1, srcRect.height());
+ context->clear(&clearRect, 0x0);
+ // FIXME: This should be mitchell, not bilinear.
+ paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
+ GrMatrix sampleM;
+ sampleM.setIDiv(srcTexture->width(), srcTexture->height());
+ paint.getTextureSampler(0)->setMatrix(sampleM);
+ context->setRenderTarget(dstTexture->asRenderTarget());
+ paint.setTexture(0, srcTexture);
+ SkRect dstRect(srcRect);
+ scaleRect(&dstRect, scaleFactorX, scaleFactorY);
+ context->drawRectToRect(paint, dstRect, srcRect);
+ srcRect = dstRect;
+ SkTSwap(srcTexture, dstTexture);
+ }
+ context->setRenderTarget(oldRenderTarget);
+ context->setClip(oldClip);
+ return srcTexture;
}
static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
@@ -716,33 +855,17 @@ static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
return false;
}
float sigma = SkScalarToFloat(radius) * BLUR_SIGMA_SCALE;
- SkRect srcRect = path.getBounds();
-
- int scaleFactor = 1;
-
- while (sigma > MAX_BLUR_SIGMA) {
- scaleFactor *= 2;
- sigma *= 0.5f;
- }
- int halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
- int kernelWidth = halfWidth * 2 + 1;
+ float sigma3 = sigma * 3.0f;
- float invScale = 1.0f / scaleFactor;
- scaleRect(&srcRect, invScale);
- srcRect.roundOut();
- srcRect.inset(-halfWidth, -halfWidth);
-
- SkRect clipBounds;
- clipBounds.set(clip.getBounds());
- scaleRect(&clipBounds, invScale);
- clipBounds.roundOut();
- clipBounds.inset(-halfWidth, -halfWidth);
-
- srcRect.intersect(clipBounds);
+ SkRect srcRect = path.getBounds();
+ SkRect clipRect;
+ clipRect.set(clip.getBounds());
- scaleRect(&srcRect, scaleFactor);
+ // Outset srcRect and clipRect by 3 * sigma, to compute affected blur area.
+ srcRect.inset(-sigma3, -sigma3);
+ clipRect.inset(-sigma3, -sigma3);
+ srcRect.intersect(clipRect);
SkRect finalRect = srcRect;
-
SkIRect finalIRect;
finalRect.roundOut(&finalIRect);
if (clip.quickReject(finalIRect)) {
@@ -752,7 +875,7 @@ static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
return true;
}
GrPoint offset = GrPoint::Make(-srcRect.fLeft, -srcRect.fTop);
- srcRect.offset(-srcRect.fLeft, -srcRect.fTop);
+ srcRect.offset(offset);
const GrTextureDesc desc = {
kRenderTarget_GrTextureFlagBit,
kNone_GrAALevel,
@@ -763,21 +886,16 @@ static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
kRGBA_8888_PM_GrPixelConfig
};
- GrAutoScratchTexture srcEntry(context, desc);
- GrAutoScratchTexture dstEntry(context, desc);
- if (NULL == srcEntry.texture() || NULL == dstEntry.texture()) {
- return false;
- }
- GrTexture* srcTexture = srcEntry.texture();
- GrTexture* dstTexture = dstEntry.texture();
- if (NULL == srcTexture || NULL == dstTexture) {
+ GrAutoScratchTexture pathEntry(context, desc);
+ GrTexture* pathTexture = pathEntry.texture();
+ if (NULL == pathTexture) {
return false;
}
GrRenderTarget* oldRenderTarget = context->getRenderTarget();
// Once this code moves into GrContext, this should be changed to use
// an AutoClipRestore.
GrClip oldClip = context->getClip();
- context->setRenderTarget(dstTexture->asRenderTarget());
+ context->setRenderTarget(pathTexture->asRenderTarget());
context->setClip(srcRect);
context->clear(NULL, 0);
GrPaint tempPaint;
@@ -795,95 +913,27 @@ static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
tempPaint.fSrcBlendCoeff = kOne_BlendCoeff;
tempPaint.fDstBlendCoeff = kISC_BlendCoeff;
}
- // Draw hard shadow to dstTexture with path topleft at origin 0,0.
+ // Draw hard shadow to pathTexture with path topleft at origin 0,0.
context->drawPath(tempPaint, path, skToGrFillType(path.getFillType()), &offset);
- SkTSwap(srcTexture, dstTexture);
-
- GrMatrix sampleM;
- sampleM.setIDiv(srcTexture->width(), srcTexture->height());
- GrPaint paint;
- paint.reset();
- paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
- paint.getTextureSampler(0)->setMatrix(sampleM);
- GrAutoScratchTexture origEntry;
-
- if (blurType != SkMaskFilter::kNormal_BlurType) {
- // Stash away a copy of the unblurred image.
- origEntry.set(context, desc);
- if (NULL == origEntry.texture()) {
- return false;
- }
- context->setRenderTarget(origEntry.texture()->asRenderTarget());
- paint.setTexture(0, srcTexture);
- context->drawRect(paint, srcRect);
- }
- for (int i = 1; i < scaleFactor; i *= 2) {
- sampleM.setIDiv(srcTexture->width(), srcTexture->height());
- paint.getTextureSampler(0)->setMatrix(sampleM);
- context->setRenderTarget(dstTexture->asRenderTarget());
- SkRect dstRect(srcRect);
- scaleRect(&dstRect, 0.5f);
- paint.setTexture(0, srcTexture);
- context->drawRectToRect(paint, dstRect, srcRect);
- srcRect = dstRect;
- SkTSwap(srcTexture, dstTexture);
- }
- SkAutoTMalloc<float> kernelStorage(kernelWidth);
- float* kernel = kernelStorage.get();
- buildKernel(sigma, kernel, kernelWidth);
-
- // Clear out a halfWidth to the right of the srcRect to prevent the
- // X convolution from reading garbage.
- SkIRect clearRect = SkIRect::MakeXYWH(
- srcRect.fRight, srcRect.fTop, halfWidth, srcRect.height());
- context->clear(&clearRect, 0x0);
-
- context->setRenderTarget(dstTexture->asRenderTarget());
- context->convolveInX(srcTexture, srcRect, kernel, kernelWidth);
- SkTSwap(srcTexture, dstTexture);
-
- // Clear out a halfWidth below the srcRect to prevent the Y
- // convolution from reading garbage.
- clearRect = SkIRect::MakeXYWH(
- srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidth);
- context->clear(&clearRect, 0x0);
-
- context->setRenderTarget(dstTexture->asRenderTarget());
- context->convolveInY(srcTexture, srcRect, kernel, kernelWidth);
- SkTSwap(srcTexture, dstTexture);
-
- // Clear one pixel to the right and below, to accommodate bilinear
- // upsampling.
- clearRect = SkIRect::MakeXYWH(
- srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
- context->clear(&clearRect, 0x0);
- clearRect = SkIRect::MakeXYWH(
- srcRect.fRight, srcRect.fTop, 1, srcRect.height());
- context->clear(&clearRect, 0x0);
-
- if (scaleFactor > 1) {
- // FIXME: This should be mitchell, not bilinear.
- paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
- sampleM.setIDiv(srcTexture->width(), srcTexture->height());
- paint.getTextureSampler(0)->setMatrix(sampleM);
- context->setRenderTarget(dstTexture->asRenderTarget());
- paint.setTexture(0, srcTexture);
- SkRect dstRect(srcRect);
- scaleRect(&dstRect, scaleFactor);
- context->drawRectToRect(paint, dstRect, srcRect);
- srcRect = dstRect;
- SkTSwap(srcTexture, dstTexture);
- }
-
- if (blurType != SkMaskFilter::kNormal_BlurType) {
- GrTexture* origTexture = origEntry.texture();
+ GrAutoScratchTexture temp1, temp2;
+ // If we're doing a normal blur, we can clobber the pathTexture in the
+ // gaussianBlur. Otherwise, we need to save it for later compositing.
+ bool isNormalBlur = blurType == SkMaskFilter::kNormal_BlurType;
+ GrTexture* blurTexture = gaussianBlur(context, pathTexture,
+ &temp1, isNormalBlur ? NULL : &temp2,
+ srcRect, sigma, sigma);
+
+ if (!isNormalBlur) {
+ GrPaint paint;
+ paint.reset();
paint.getTextureSampler(0)->setFilter(GrSamplerState::kNearest_Filter);
- sampleM.setIDiv(origTexture->width(), origTexture->height());
+ GrMatrix sampleM;
+ sampleM.setIDiv(pathTexture->width(), pathTexture->height());
paint.getTextureSampler(0)->setMatrix(sampleM);
- // Blend origTexture over srcTexture.
- context->setRenderTarget(srcTexture->asRenderTarget());
- paint.setTexture(0, origTexture);
+ // Blend pathTexture over blurTexture.
+ context->setRenderTarget(blurTexture->asRenderTarget());
+ paint.setTexture(0, pathTexture);
if (SkMaskFilter::kInner_BlurType == blurType) {
// inner: dst = dst * src
paint.fSrcBlendCoeff = kDC_BlendCoeff;
@@ -915,12 +965,12 @@ static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
static const int MASK_IDX = GrPaint::kMaxMasks - 1;
// we assume the last mask index is available for use
GrAssert(NULL == grp->getMask(MASK_IDX));
- grp->setMask(MASK_IDX, srcTexture);
+ grp->setMask(MASK_IDX, blurTexture);
grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
GrMatrix m;
m.setTranslate(-finalRect.fLeft, -finalRect.fTop);
- m.postIDiv(srcTexture->width(), srcTexture->height());
+ m.postIDiv(blurTexture->width(), blurTexture->height());
grp->getMaskSampler(MASK_IDX)->setMatrix(m);
context->drawRect(*grp, finalRect);
return true;
@@ -1352,6 +1402,18 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
GrIntToScalar(y),
GrIntToScalar(w),
GrIntToScalar(h));
+ SkImageFilter* imageFilter = paint.getImageFilter();
+ SkSize size;
+ if (NULL != imageFilter && imageFilter->asABlur(&size)) {
+ GrAutoScratchTexture temp1, temp2;
+ GrTexture* blurTexture = gaussianBlur(fContext,
+ devTex, &temp1, &temp2,
+ GrRect::MakeWH(w, h),
+ size.width(),
+ size.height());
+ grPaint.setTexture(kBitmapTextureIdx, blurTexture);
+ devTex = blurTexture;
+ }
// The device being drawn may not fill up its texture (saveLayer uses
// the approximate ).
GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),