Implement offset for GPU filter path. Although we can't yet use this in Blink for...
authorcommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 10 Jul 2013 21:22:18 +0000 (21:22 +0000)
committercommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 10 Jul 2013 21:22:18 +0000 (21:22 +0000)
This patch adds the parameter to the filterImageGPU() signature, plumbs through the code on the GPU side, and implements support for it in SkXfermodeImageFilter for both raster and GPU.

Of the remaining filters with GPU implementations, Blur, Morphology, Bicubic and Displacement work fine; they're commutative wrt offset and can simply pass it up the chain. Blend is not, but will be removed shortly anyway (has been replaced with SkXfermodeImageFilter in Blink).

R=reed@google.com, bsalomon@google.com

Author: senorblanco@chromium.org

Review URL: https://chromiumcodereview.appspot.com/15995026

git-svn-id: http://skia.googlecode.com/svn/trunk@9977 2bbb7eff-a529-9590-31e7-b0007b416f81

19 files changed:
gm/xfermodeimagefilter.cpp
include/core/SkImageFilter.h
include/core/SkImageFilterUtils.h
include/effects/SkBicubicImageFilter.h
include/effects/SkBlendImageFilter.h
include/effects/SkBlurImageFilter.h
include/effects/SkDisplacementMapEffect.h
include/effects/SkImageFilterUtils.h
include/effects/SkMorphologyImageFilter.h
include/effects/SkXfermodeImageFilter.h
src/core/SkImageFilter.cpp
src/core/SkImageFilterUtils.cpp
src/effects/SkBicubicImageFilter.cpp
src/effects/SkBlendImageFilter.cpp
src/effects/SkBlurImageFilter.cpp
src/effects/SkDisplacementMapEffect.cpp
src/effects/SkMorphologyImageFilter.cpp
src/effects/SkXfermodeImageFilter.cpp
src/gpu/SkGpuDevice.cpp

index a6d395e658a3044c8d8cf3e2ed5037a165705892..e602c7079d66453600dfbe362734bc83630e7762 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "gm.h"
 #include "SkArithmeticMode.h"
+#include "SkOffsetImageFilter.h"
 #include "SkXfermodeImageFilter.h"
 #include "SkBitmapSource.h"
 
@@ -68,7 +69,8 @@ protected:
         return make_isize(WIDTH, HEIGHT);
     }
 
-    void drawClippedBitmap(SkCanvas* canvas, const SkBitmap& bitmap, const SkPaint& paint, SkScalar x, SkScalar y) {
+    void drawClippedBitmap(SkCanvas* canvas, const SkBitmap& bitmap, const SkPaint& paint,
+                           SkScalar x, SkScalar y) {
         canvas->save();
         canvas->clipRect(SkRect::MakeXYWH(x, y,
             SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())));
@@ -125,7 +127,8 @@ protected:
         SkAutoTUnref<SkImageFilter> background(SkNEW_ARGS(SkBitmapSource, (fCheckerboard)));
         for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
             SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(gModes[i].fMode));
-            SkAutoTUnref<SkImageFilter> filter(SkNEW_ARGS(SkXfermodeImageFilter, (mode, background)));
+            SkAutoTUnref<SkImageFilter> filter(SkNEW_ARGS(
+                SkXfermodeImageFilter, (mode, background)));
             paint.setImageFilter(filter);
             drawClippedBitmap(canvas, fBitmap, paint, SkIntToScalar(x), SkIntToScalar(y));
             x += fBitmap.width() + MARGIN;
@@ -148,6 +151,40 @@ protected:
         filter.reset(SkNEW_ARGS(SkXfermodeImageFilter, (NULL, background)));
         paint.setImageFilter(filter);
         drawClippedBitmap(canvas, fBitmap, paint, SkIntToScalar(x), SkIntToScalar(y));
+        x += fBitmap.width() + MARGIN;
+        if (x + fBitmap.width() > WIDTH) {
+            x = 0;
+            y += fBitmap.height() + MARGIN;
+        }
+        // Test offsets on SrcMode (uses fixed-function blend)
+        SkAutoTUnref<SkImageFilter> foreground(SkNEW_ARGS(SkBitmapSource, (fBitmap)));
+        SkAutoTUnref<SkImageFilter> offsetForeground(SkNEW_ARGS(SkOffsetImageFilter,
+            (SkIntToScalar(4), SkIntToScalar(-4), foreground)));
+        SkAutoTUnref<SkImageFilter> offsetBackground(SkNEW_ARGS(SkOffsetImageFilter,
+            (SkIntToScalar(4), SkIntToScalar(4), background)));
+        mode.reset(SkXfermode::Create(SkXfermode::kSrcOver_Mode));
+        filter.reset(SkNEW_ARGS(SkXfermodeImageFilter,
+            (mode, offsetBackground, offsetForeground)));
+        paint.setImageFilter(filter);
+        canvas->save();
+        canvas->clipRect(SkRect::MakeXYWH(x, y,
+            SkIntToScalar(fBitmap.width() + 4), SkIntToScalar(fBitmap.height() + 4)));
+        canvas->drawPaint(paint);
+        canvas->restore();
+        x += fBitmap.width() + MARGIN;
+        if (x + fBitmap.width() > WIDTH) {
+            x = 0;
+            y += fBitmap.height() + MARGIN;
+        }
+        // Test offsets on Darken (uses shader blend)
+        mode.reset(SkXfermode::Create(SkXfermode::kDarken_Mode));
+        filter.reset(SkNEW_ARGS(SkXfermodeImageFilter, (mode, offsetBackground, offsetForeground)));
+        paint.setImageFilter(filter);
+        canvas->save();
+        canvas->clipRect(SkRect::MakeXYWH(x, y,
+            SkIntToScalar(fBitmap.width() + 4), SkIntToScalar(fBitmap.height() + 4)));
+        canvas->drawPaint(paint);
+        canvas->restore();
     }
 private:
     typedef GM INHERITED;
index 78e321a7b5693307224cfee271470098ba5efbb2..f29b4606b5331b433cafd9fbaa14902f4917273d 100644 (file)
@@ -109,10 +109,11 @@ public:
      *  textures.  For single-pass effects, use asNewEffect().  src is the
      *  source image for processing, as a texture-backed bitmap.  result is
      *  the destination bitmap, which should contain a texture-backed pixelref
-     *  on success.  The default implementation does single-pass processing
-     *  using asNewEffect().
+     *  on success.  offset is the amount to translate the resulting image 
+     *  relative to the src when it is drawn. The default implementation does
+     *  single-pass processing using asNewEffect().
      */
-    virtual bool filterImageGPU(Proxy*, const SkBitmap& src, SkBitmap* result);
+    virtual bool filterImageGPU(Proxy*, const SkBitmap& src, SkBitmap* result, SkIPoint* offset);
 
     /**
      *  Returns whether this image filter is a color filter and puts the color filter into the
index 72a25fef7777c8644c7c5e709a17980891e710ea..5b9f192a0ff9f863e1ec9d1dcfeecc6351bace7c 100644 (file)
@@ -28,7 +28,8 @@ public:
      * this function returns src.  If the filter has no GPU implementation, it
      * will be processed in software and uploaded to the GPU.
      */
-    static bool GetInputResultGPU(SkImageFilter* filter, SkImageFilter::Proxy* proxy, const SkBitmap& src, SkBitmap* result);
+    static bool GetInputResultGPU(SkImageFilter* filter, SkImageFilter::Proxy* proxy,
+                                  const SkBitmap& src, SkBitmap* result, SkIPoint* offset);
 };
 
 #endif
index 119c07958eca676e0f995c4ecd003e72fdaba437..75cd27df7464715136d8ad133ac5e54b83b40b7a 100644 (file)
@@ -27,7 +27,8 @@ public:
                             passed to filterImage() is used instead.
     */
 
-    SkBicubicImageFilter(const SkSize& scale, const SkScalar coefficients[16], SkImageFilter* input = NULL);
+    SkBicubicImageFilter(const SkSize& scale, const SkScalar coefficients[16],
+                         SkImageFilter* input = NULL);
     static SkBicubicImageFilter* CreateMitchell(const SkSize& scale, SkImageFilter* input = NULL);
     virtual ~SkBicubicImageFilter();
 
@@ -42,7 +43,8 @@ protected:
 
 #if SK_SUPPORT_GPU
     virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; }
-    virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) SK_OVERRIDE;
+    virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result,
+                                SkIPoint* offset) SK_OVERRIDE;
 #endif
 
 private:
index a2dc847494276eceeed20626eba8cfda440e0609..7286cc11143a3a99d5735454515a6f0d800b616d 100644 (file)
@@ -33,7 +33,8 @@ public:
                                SkIPoint* offset) SK_OVERRIDE;
 #if SK_SUPPORT_GPU
     virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; }
-    virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) SK_OVERRIDE;
+    virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result,
+                                SkIPoint* offset) SK_OVERRIDE;
 #endif
 
 protected:
index 80ea9e5c92cf8acdca9f03704bcab4e8e39368fe..56b1f3543e2c137ee743840afe91cebeb749a4ef 100644 (file)
@@ -25,7 +25,8 @@ protected:
                                SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
 
     bool canFilterImageGPU() const SK_OVERRIDE { return true; }
-    virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) SK_OVERRIDE;
+    virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result,
+                                SkIPoint* offset) SK_OVERRIDE;
 
 private:
     SkSize   fSigma;
index 18f9df866e4355439c3c394bcfe00012ce47d1e2..5efbf50e444768833e4c3adbfab6e7bf431e939b 100644 (file)
@@ -22,7 +22,10 @@ public:
         kKeyBits = 3 // Max value is 4, so 3 bits are required at most
     };
 
-    SkDisplacementMapEffect(ChannelSelectorType xChannelSelector, ChannelSelectorType yChannelSelector, SkScalar scale, SkImageFilter* displacement, SkImageFilter* color = NULL);
+    SkDisplacementMapEffect(ChannelSelectorType xChannelSelector,
+                            ChannelSelectorType yChannelSelector,
+                            SkScalar scale, SkImageFilter* displacement,
+                            SkImageFilter* color = NULL);
 
     ~SkDisplacementMapEffect();
 
@@ -35,7 +38,8 @@ public:
                                SkIPoint* offset) SK_OVERRIDE;
 #if SK_SUPPORT_GPU
     virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; }
-    virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) SK_OVERRIDE;
+    virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result,
+                                SkIPoint* offset) SK_OVERRIDE;
 #endif
 
 protected:
index 72a25fef7777c8644c7c5e709a17980891e710ea..5b9f192a0ff9f863e1ec9d1dcfeecc6351bace7c 100644 (file)
@@ -28,7 +28,8 @@ public:
      * this function returns src.  If the filter has no GPU implementation, it
      * will be processed in software and uploaded to the GPU.
      */
-    static bool GetInputResultGPU(SkImageFilter* filter, SkImageFilter::Proxy* proxy, const SkBitmap& src, SkBitmap* result);
+    static bool GetInputResultGPU(SkImageFilter* filter, SkImageFilter::Proxy* proxy,
+                                  const SkBitmap& src, SkBitmap* result, SkIPoint* offset);
 };
 
 #endif
index a189c757de1e13775d0da05ccb73b2b9422dc315..635fe42428eb1c12f05a07698443c6a558829354 100644 (file)
@@ -38,7 +38,8 @@ public:
     virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
                                SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
 #if SK_SUPPORT_GPU
-    virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) SK_OVERRIDE;
+    virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result,
+                                SkIPoint* offset) SK_OVERRIDE;
 #endif
 
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDilateImageFilter)
@@ -58,7 +59,8 @@ public:
     virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
                                SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
 #if SK_SUPPORT_GPU
-    virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) SK_OVERRIDE;
+    virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result,
+                                SkIPoint* offset) SK_OVERRIDE;
 #endif
 
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkErodeImageFilter)
index ec7ce87046a9e2edc7dea4c57327ff220c28c202..d13c4b2d2479396f2270f7d8604ba4f46f944107 100644 (file)
@@ -21,7 +21,8 @@ class SK_API SkXfermodeImageFilter : public SkImageFilter {
       */
 
 public:
-    SkXfermodeImageFilter(SkXfermode* mode, SkImageFilter* background, SkImageFilter* foreground = NULL);
+    SkXfermodeImageFilter(SkXfermode* mode, SkImageFilter* background,
+                          SkImageFilter* foreground = NULL);
 
     virtual ~SkXfermodeImageFilter();
 
@@ -34,7 +35,8 @@ public:
                                SkIPoint* offset) SK_OVERRIDE;
 #if SK_SUPPORT_GPU
     virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; }
-    virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) SK_OVERRIDE;
+    virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result,
+                                SkIPoint* offset) SK_OVERRIDE;
 #endif
 
 protected:
index 9f16b4a0c85e02d751cdf756eb1bf00dc3baad2c..33caf75a9d1e0a539e52cb0108c36344bc9386de 100644 (file)
@@ -98,11 +98,12 @@ bool SkImageFilter::canFilterImageGPU() const {
     return this->asNewEffect(NULL, NULL);
 }
 
-bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
+bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result,
+                                   SkIPoint* offset) {
 #if SK_SUPPORT_GPU
     SkBitmap input;
     SkASSERT(fInputCount == 1);
-    if (!SkImageFilterUtils::GetInputResultGPU(this->getInput(0), proxy, src, &input)) {
+    if (!SkImageFilterUtils::GetInputResultGPU(this->getInput(0), proxy, src, &input, offset)) {
         return false;
     }
     GrTexture* srcTexture = input.getTexture();
index d6e109c1ad32ce83c903a36033337081724a6909..c88d5fed413a4b20a68de470473518fd6dfc47b9 100644 (file)
@@ -20,15 +20,16 @@ bool SkImageFilterUtils::WrapTexture(GrTexture* texture, int width, int height,
     return true;
 }
 
-bool SkImageFilterUtils::GetInputResultGPU(SkImageFilter* filter, SkImageFilter::Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
+bool SkImageFilterUtils::GetInputResultGPU(SkImageFilter* filter, SkImageFilter::Proxy* proxy,
+                                           const SkBitmap& src, SkBitmap* result,
+                                           SkIPoint* offset) {
     if (!filter) {
         *result = src;
         return true;
     } else if (filter->canFilterImageGPU()) {
-        return filter->filterImageGPU(proxy, src, result);
+        return filter->filterImageGPU(proxy, src, result, offset);
     } else {
-        SkIPoint offset;
-        if (filter->filterImage(proxy, src, SkMatrix(), result, &offset)) {
+        if (filter->filterImage(proxy, src, SkMatrix(), result, offset)) {
             if (!result->getTexture()) {
                 GrContext* context = ((GrTexture *) src.getTexture())->getContext();
                 GrTexture* resultTex = GrLockAndRefCachedBitmapTexture(context,
index 2d0a17a116d5f15d09e576faf8cb0046c306fcc6..a97a768de94de03cd600c81d97145e3ae5b9bfe9 100644 (file)
@@ -341,9 +341,9 @@ GrEffectRef* GrBicubicEffect::TestCreate(SkMWCRandom* random,
     return GrBicubicEffect::Create(textures[texIdx], coefficients);
 }
 
-bool SkBicubicImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
+bool SkBicubicImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result, SkIPoint* offset) {
     SkBitmap srcBM;
-    if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &srcBM)) {
+    if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &srcBM, offset)) {
         return false;
     }
     GrTexture* srcTexture = srcBM.getTexture();
index 4f61ed80002acdb0d2ff82b65bec0c25ccc120ae..7b98644ec79b3292197eee3b214d8bc3ca3024f8 100644 (file)
@@ -68,10 +68,13 @@ bool SkBlendImageFilter::onFilterImage(Proxy* proxy,
     SkImageFilter* backgroundInput = getBackgroundInput();
     SkImageFilter* foregroundInput = getForegroundInput();
     SkASSERT(NULL != backgroundInput);
-    if (!backgroundInput->filterImage(proxy, src, ctm, &background, offset)) {
+    SkIPoint backgroundOffset = SkIPoint::Make(0, 0);
+    if (!backgroundInput->filterImage(proxy, src, ctm, &background, &backgroundOffset)) {
         return false;
     }
-    if (foregroundInput && !foregroundInput->filterImage(proxy, src, ctm, &foreground, offset)) {
+    SkIPoint foregroundOffset = SkIPoint::Make(0, 0);
+    if (foregroundInput &&
+        !foregroundInput->filterImage(proxy, src, ctm, &foreground, &foregroundOffset)) {
         return false;
     }
     SkAutoLockPixels alp_foreground(foreground), alp_background(background);
@@ -83,9 +86,9 @@ bool SkBlendImageFilter::onFilterImage(Proxy* proxy,
     SkCanvas canvas(*dst);
     SkPaint paint;
     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
-    canvas.drawBitmap(background, 0, 0, &paint);
+    canvas.drawBitmap(background, backgroundOffset.fX, backgroundOffset.fY, &paint);
     paint.setXfermodeMode(modeToXfermode(fMode));
-    canvas.drawBitmap(foreground, 0, 0, &paint);
+    canvas.drawBitmap(foreground, foregroundOffset.fX, foregroundOffset.fY, &paint);
     return true;
 }
 
@@ -124,8 +127,11 @@ class GrBlendEffect : public GrEffect {
 public:
     static GrEffectRef* Create(SkBlendImageFilter::Mode mode,
                                GrTexture* foreground,
-                               GrTexture* background) {
-        AutoEffectUnref effect(SkNEW_ARGS(GrBlendEffect, (mode, foreground, background)));
+                               const SkIPoint& foregroundOffset,
+                               GrTexture* background,
+                               const SkIPoint& backgroundOffset) {
+        AutoEffectUnref effect(SkNEW_ARGS(GrBlendEffect, (mode, foreground, foregroundOffset,
+                                                          background, backgroundOffset)));
         return CreateEffectRef(effect);
     }
 
@@ -133,6 +139,8 @@ public:
 
     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
     SkBlendImageFilter::Mode mode() const { return fMode; }
+    const SkMatrix& foregroundMatrix() const { return fForegroundMatrix; }
+    const SkMatrix& backgroundMatrix() const { return fBackgroundMatrix; }
 
     typedef GrGLBlendEffect GLEffect;
     static const char* Name() { return "Blend"; }
@@ -142,22 +150,31 @@ public:
 private:
     virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
 
-    GrBlendEffect(SkBlendImageFilter::Mode mode, GrTexture* foreground, GrTexture* background);
+    GrBlendEffect(SkBlendImageFilter::Mode mode,
+                  GrTexture* foreground, const SkIPoint& foregroundOffset,
+                  GrTexture* background, const SkIPoint& backgroundOffset);
     GrTextureAccess             fForegroundAccess;
+    SkMatrix                    fForegroundMatrix;
     GrTextureAccess             fBackgroundAccess;
+    SkMatrix                    fBackgroundMatrix;
     SkBlendImageFilter::Mode    fMode;
 
     typedef GrEffect INHERITED;
 };
 
-bool SkBlendImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
+bool SkBlendImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result,
+                                        SkIPoint* offset) {
     SkBitmap backgroundBM;
-    if (!SkImageFilterUtils::GetInputResultGPU(getBackgroundInput(), proxy, src, &backgroundBM)) {
+    SkIPoint backgroundOffset = SkIPoint::Make(0, 0);
+    if (!SkImageFilterUtils::GetInputResultGPU(getBackgroundInput(), proxy, src, &backgroundBM,
+                                               &backgroundOffset)) {
         return false;
     }
     GrTexture* background = backgroundBM.getTexture();
     SkBitmap foregroundBM;
-    if (!SkImageFilterUtils::GetInputResultGPU(getForegroundInput(), proxy, src, &foregroundBM)) {
+    SkIPoint foregroundOffset = SkIPoint::Make(0, 0);
+    if (!SkImageFilterUtils::GetInputResultGPU(getForegroundInput(), proxy, src, &foregroundBM,
+                                               &foregroundOffset)) {
         return false;
     }
     GrTexture* foreground = foregroundBM.getTexture();
@@ -176,7 +193,7 @@ bool SkBlendImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBit
 
     GrPaint paint;
     paint.colorStage(0)->setEffect(
-        GrBlendEffect::Create(fMode, foreground, background))->unref();
+        GrBlendEffect::Create(fMode, foreground, foregroundOffset, background, backgroundOffset))->unref();
     SkRect srcRect;
     src.getBounds(&srcRect);
     context->drawRect(paint, srcRect);
@@ -187,12 +204,20 @@ bool SkBlendImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBit
 
 GrBlendEffect::GrBlendEffect(SkBlendImageFilter::Mode mode,
                              GrTexture* foreground,
-                             GrTexture* background)
+                             const SkIPoint& foregroundOffset,
+                             GrTexture* background,
+                             const SkIPoint& backgroundOffset)
     : fForegroundAccess(foreground)
     , fBackgroundAccess(background)
     , fMode(mode) {
     this->addTextureAccess(&fForegroundAccess);
     this->addTextureAccess(&fBackgroundAccess);
+    fForegroundMatrix = GrEffect::MakeDivByTextureWHMatrix(foreground);
+    fForegroundMatrix.preTranslate(SkIntToScalar(-foregroundOffset.fX),
+                                   SkIntToScalar(-foregroundOffset.fY));
+    fBackgroundMatrix = GrEffect::MakeDivByTextureWHMatrix(background);
+    fBackgroundMatrix.preTranslate(SkIntToScalar(-backgroundOffset.fX),
+                                   SkIntToScalar(-backgroundOffset.fY));
 }
 
 GrBlendEffect::~GrBlendEffect() {
@@ -288,11 +313,11 @@ void GrGLBlendEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect
     GrTexture* fgTex = blend.texture(0);
     GrTexture* bgTex = blend.texture(1);
     fForegroundEffectMatrix.setData(uman,
-                                    GrEffect::MakeDivByTextureWHMatrix(fgTex),
+                                    blend.foregroundMatrix(),
                                     drawEffect,
                                     fgTex);
     fBackgroundEffectMatrix.setData(uman,
-                                    GrEffect::MakeDivByTextureWHMatrix(bgTex),
+                                    blend.backgroundMatrix(),
                                     drawEffect,
                                     bgTex);
 
index 36d0afd35e558f069774c0bbb614d0d2584726d0..e6032446bd5eb8988c3f2e82fa6a7958ca692a52 100644 (file)
@@ -119,7 +119,8 @@ static void boxBlurY(const SkBitmap& src, SkBitmap* dst, int kernelSize,
     }
 }
 
-static void getBox3Params(SkScalar s, int *kernelSize, int* kernelSize3, int *lowOffset, int *highOffset)
+static void getBox3Params(SkScalar s, int *kernelSize, int* kernelSize3, int *lowOffset,
+                          int *highOffset)
 {
     float pi = SkScalarToFloat(SK_ScalarPI);
     int d = static_cast<int>(floorf(SkScalarToFloat(s) * 3.0f * sqrtf(2.0f * pi) / 4.0f + 0.5f));
@@ -192,10 +193,11 @@ bool SkBlurImageFilter::onFilterImage(Proxy* proxy,
     return true;
 }
 
-bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
+bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result,
+                                       SkIPoint* offset) {
 #if SK_SUPPORT_GPU
     SkBitmap input;
-    if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &input)) {
+    if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &input, offset)) {
         return false;
     }
     GrTexture* source = input.getTexture();
index 7c99c023f8adb4cd58ed5e9869c0a2691d5b8dad..8d287b270462bee06ae14546cb8869c1e6db205b 100644 (file)
@@ -275,14 +275,19 @@ private:
     typedef GrEffect INHERITED;
 };
 
-bool SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
+bool SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result,
+                                             SkIPoint* offset) {
     SkBitmap colorBM;
-    if (!SkImageFilterUtils::GetInputResultGPU(getColorInput(), proxy, src, &colorBM)) {
+    SkIPoint colorOffset = SkIPoint::Make(0, 0);
+    if (!SkImageFilterUtils::GetInputResultGPU(getColorInput(), proxy, src, &colorBM,
+                                               &colorOffset)) {
         return false;
     }
     GrTexture* color = colorBM.getTexture();
     SkBitmap displacementBM;
-    if (!SkImageFilterUtils::GetInputResultGPU(getDisplacementInput(), proxy, src, &displacementBM)) {
+    SkIPoint displacementOffset = SkIPoint::Make(0, 0);
+    if (!SkImageFilterUtils::GetInputResultGPU(getDisplacementInput(), proxy, src, &displacementBM,
+                                               &displacementOffset)) {
         return false;
     }
     GrTexture* displacement = displacementBM.getTexture();
@@ -308,7 +313,9 @@ bool SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, const SkBitmap& src,
                                         color))->unref();
     SkRect srcRect;
     src.getBounds(&srcRect);
-    context->drawRect(paint, srcRect);
+    SkRect dstRect = srcRect;
+    dstRect.offset(SkIntToScalar(colorOffset.fX), SkIntToScalar(colorOffset.fY));
+    context->drawRectToRect(paint, srcRect, dstRect);
     return SkImageFilterUtils::WrapTexture(dst, src.width(), src.height(), result);
 }
 
index cbee8500ac85588eab5f55c835a1f5a84eeb2ba2..cb17c9011b6e9b98b8e7a807580983812e22e9ff 100644 (file)
@@ -502,9 +502,10 @@ GrTexture* apply_morphology(GrTexture* srcTexture,
 
 };
 
-bool SkDilateImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
+bool SkDilateImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result,
+                                         SkIPoint* offset) {
     SkBitmap inputBM;
-    if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &inputBM)) {
+    if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &inputBM, offset)) {
         return false;
     }
     GrTexture* input = inputBM.getTexture();
@@ -515,9 +516,10 @@ bool SkDilateImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBi
     return SkImageFilterUtils::WrapTexture(resultTex, src.width(), src.height(), result);
 }
 
-bool SkErodeImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
+bool SkErodeImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result,
+                                        SkIPoint* offset) {
     SkBitmap inputBM;
-    if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &inputBM)) {
+    if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &inputBM, offset)) {
         return false;
     }
     GrTexture* input = inputBM.getTexture();
index c26ca18041ffb9315e955a96a089ee996d34f2fd..a318ceb9088b0a2c6359043f1a062d448d8558f7 100644 (file)
@@ -19,7 +19,9 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SkXfermodeImageFilter::SkXfermodeImageFilter(SkXfermode* mode, SkImageFilter* background, SkImageFilter* foreground)
+SkXfermodeImageFilter::SkXfermodeImageFilter(SkXfermode* mode,
+                                             SkImageFilter* background,
+                                             SkImageFilter* foreground)
   : INHERITED(background, foreground), fMode(mode) {
     SkSafeRef(fMode);
 }
@@ -46,10 +48,14 @@ bool SkXfermodeImageFilter::onFilterImage(Proxy* proxy,
     SkBitmap background = src, foreground = src;
     SkImageFilter* backgroundInput = getInput(0);
     SkImageFilter* foregroundInput = getInput(1);
-    if (backgroundInput && !backgroundInput->filterImage(proxy, src, ctm, &background, offset)) {
+    SkIPoint backgroundOffset = SkIPoint::Make(0, 0);
+    if (backgroundInput &&
+        !backgroundInput->filterImage(proxy, src, ctm, &background, &backgroundOffset)) {
         return false;
     }
-    if (foregroundInput && !foregroundInput->filterImage(proxy, src, ctm, &foreground, offset)) {
+    SkIPoint foregroundOffset = SkIPoint::Make(0, 0);
+    if (foregroundInput &&
+        !foregroundInput->filterImage(proxy, src, ctm, &foreground, &foregroundOffset)) {
         return false;
     }
     dst->setConfig(background.config(), background.width(), background.height());
@@ -59,20 +65,32 @@ bool SkXfermodeImageFilter::onFilterImage(Proxy* proxy,
     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
     canvas.drawBitmap(background, 0, 0, &paint);
     paint.setXfermode(fMode);
-    canvas.drawBitmap(foreground, 0, 0, &paint);
+    canvas.drawBitmap(foreground,
+                      SkIntToScalar(foregroundOffset.fX - backgroundOffset.fX),
+                      SkIntToScalar(foregroundOffset.fY - backgroundOffset.fY),
+                      &paint);
+    offset->fX += backgroundOffset.fX;
+    offset->fY += backgroundOffset.fY;
     return true;
 }
 
 #if SK_SUPPORT_GPU
 
-bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
+bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy,
+                                           const SkBitmap& src,
+                                           SkBitmap* result,
+                                           SkIPoint* offset) {
     SkBitmap background;
-    if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &background)) {
+    SkIPoint backgroundOffset = SkIPoint::Make(0, 0);
+    if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &background,
+                                               &backgroundOffset)) {
         return false;
     }
     GrTexture* backgroundTex = background.getTexture();
     SkBitmap foreground;
-    if (!SkImageFilterUtils::GetInputResultGPU(getInput(1), proxy, src, &foreground)) {
+    SkIPoint foregroundOffset = SkIPoint::Make(0, 0);
+    if (!SkImageFilterUtils::GetInputResultGPU(getInput(1), proxy, src, &foreground,
+                                               &foregroundOffset)) {
         return false;
     }
     GrTexture* foregroundTex = foreground.getTexture();
@@ -96,23 +114,31 @@ bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, Sk
         return false;
     }
 
+    SkMatrix foregroundMatrix = GrEffect::MakeDivByTextureWHMatrix(foregroundTex);
+    foregroundMatrix.preTranslate(SkIntToScalar(backgroundOffset.fX-foregroundOffset.fX),
+                                  SkIntToScalar(backgroundOffset.fY-foregroundOffset.fY));
+
+
     GrPaint paint;
     SkRect srcRect;
     src.getBounds(&srcRect);
     if (NULL != xferEffect) {
         paint.colorStage(0)->setEffect(
-            GrSimpleTextureEffect::Create(foregroundTex, GrEffect::MakeDivByTextureWHMatrix(foregroundTex)))->unref();
+            GrSimpleTextureEffect::Create(foregroundTex, foregroundMatrix))->unref();
         paint.colorStage(1)->setEffect(xferEffect)->unref();
         context->drawRect(paint, srcRect);
     } else {
+        SkMatrix backgroundMatrix = GrEffect::MakeDivByTextureWHMatrix(backgroundTex);
         paint.colorStage(0)->setEffect(
-            GrSimpleTextureEffect::Create(backgroundTex, GrEffect::MakeDivByTextureWHMatrix(backgroundTex)))->unref();
+            GrSimpleTextureEffect::Create(backgroundTex, backgroundMatrix))->unref();
         context->drawRect(paint, srcRect);
         paint.setBlendFunc(sk_blend_to_grblend(sm), sk_blend_to_grblend(dm));
         paint.colorStage(0)->setEffect(
-            GrSimpleTextureEffect::Create(foregroundTex, GrEffect::MakeDivByTextureWHMatrix(foregroundTex)))->unref();
+            GrSimpleTextureEffect::Create(foregroundTex, foregroundMatrix))->unref();
         context->drawRect(paint, srcRect);
     }
+    offset->fX += backgroundOffset.fX;
+    offset->fY += backgroundOffset.fY;
     return SkImageFilterUtils::WrapTexture(dst, src.width(), src.height(), result);
 }
 
index 766158fb28e499793f1e10048d78d5ec370f8ecc..d9de0ca774cb27e46191d788ac81b6de76e85ca6 100644 (file)
@@ -1377,7 +1377,7 @@ void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap,
 
 static bool filter_texture(SkDevice* device, GrContext* context,
                            GrTexture* texture, SkImageFilter* filter,
-                           int w, int h, SkBitmap* result) {
+                           int w, int h, SkBitmap* result, SkIPoint* offset) {
     GrAssert(filter);
     SkDeviceImageFilterProxy proxy(device);
 
@@ -1385,7 +1385,7 @@ static bool filter_texture(SkDevice* device, GrContext* context,
         // Save the render target and set it to NULL, so we don't accidentally draw to it in the
         // filter.  Also set the clip wide open and the matrix to identity.
         GrContext::AutoWideOpenIdentityDraw awo(context, NULL);
-        return filter->filterImageGPU(&proxy, wrap_texture(texture), result);
+        return filter->filterImageGPU(&proxy, wrap_texture(texture), result, offset);
     } else {
         return false;
     }
@@ -1419,9 +1419,10 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
         GrSimpleTextureEffect::Create(texture, SkMatrix::I()))->unref();
 
     SkImageFilter* filter = paint.getImageFilter();
+    SkIPoint offset = SkIPoint::Make(0, 0);
     if (NULL != filter) {
         SkBitmap filterBitmap;
-        if (filter_texture(this, fContext, texture, filter, w, h, &filterBitmap)) {
+        if (filter_texture(this, fContext, texture, filter, w, h, &filterBitmap, &offset)) {
             grPaint.colorStage(kBitmapEffectIdx)->setEffect(
                 GrSimpleTextureEffect::Create(filterBitmap.getTexture(), SkMatrix::I()))->unref();
             texture = filterBitmap.getTexture();
@@ -1435,8 +1436,10 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
                                             SkIntToScalar(top),
                                             SkIntToScalar(w),
                                             SkIntToScalar(h)),
-                            GrRect::MakeWH(SK_Scalar1 * w / texture->width(),
-                                        SK_Scalar1 * h / texture->height()));
+                            GrRect::MakeXYWH(offset.fX,
+                                             offset.fY,
+                                             SK_Scalar1 * w / texture->width(),
+                                             SK_Scalar1 * h / texture->height()));
 }
 
 void SkGpuDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
@@ -1498,12 +1501,15 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* device,
     SkImageFilter* filter = paint.getImageFilter();
     if (NULL != filter) {
         SkBitmap filterBitmap;
-        if (filter_texture(this, fContext, devTex, filter, w, h, &filterBitmap)) {
+        SkIPoint offset = SkIPoint::Make(0, 0);
+        if (filter_texture(this, fContext, devTex, filter, w, h, &filterBitmap, &offset)) {
             grPaint.colorStage(kBitmapEffectIdx)->setEffect(
                 GrSimpleTextureEffect::Create(filterBitmap.getTexture(), SkMatrix::I()))->unref();
             devTex = filterBitmap.getTexture();
             w = filterBitmap.width();
             h = filterBitmap.height();
+            x += offset.fX;
+            y += offset.fY;
         }
     }
 
@@ -1542,7 +1548,7 @@ bool SkGpuDevice::filterImage(SkImageFilter* filter, const SkBitmap& src,
     // must be pushed upstack.
     SkAutoCachedTexture act(this, src, NULL, &texture);
 
-    return filter_texture(this, fContext, texture, filter, src.width(), src.height(), result);
+    return filter_texture(this, fContext, texture, filter, src.width(), src.height(), result, offset);
 }
 
 ///////////////////////////////////////////////////////////////////////////////