aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-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(),