aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/imagefiltersbase.cpp215
-rw-r--r--gyp/gmslides.gypi1
-rw-r--r--include/core/SkCanvas.h6
-rw-r--r--include/core/SkDevice.h21
-rw-r--r--include/core/SkImageFilter.h6
-rw-r--r--include/gpu/SkGpuDevice.h6
-rw-r--r--src/core/SkCanvas.cpp146
-rw-r--r--src/core/SkDevice.cpp10
-rw-r--r--src/gpu/SkGpuDevice.cpp152
9 files changed, 441 insertions, 122 deletions
diff --git a/gm/imagefiltersbase.cpp b/gm/imagefiltersbase.cpp
new file mode 100644
index 0000000000..bde2612166
--- /dev/null
+++ b/gm/imagefiltersbase.cpp
@@ -0,0 +1,215 @@
+/*
+ * 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 "SkCanvas.h"
+#include "SkColorFilter.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+
+#include "SkBlurImageFilter.h"
+#include "SkTestImageFilters.h"
+
+class FailImageFilter : public SkImageFilter {
+public:
+ FailImageFilter() {}
+ virtual Factory getFactory() SK_OVERRIDE { return CreateProc; };
+
+protected:
+ virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
+ SkBitmap* result, SkIPoint* offset) {
+ return false;
+ }
+
+ FailImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
+
+private:
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return new FailImageFilter(buffer);
+ }
+
+ typedef SkImageFilter INHERITED;
+};
+
+class IdentityImageFilter : public SkImageFilter {
+public:
+ IdentityImageFilter() {}
+ virtual Factory getFactory() SK_OVERRIDE { return CreateProc; };
+
+protected:
+ virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
+ SkBitmap* result, SkIPoint* offset) {
+ *result = src;
+ return true;
+ }
+
+ IdentityImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
+
+private:
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return new IdentityImageFilter(buffer);
+ }
+
+ typedef SkImageFilter INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void draw_paint(SkCanvas* canvas, const SkRect& r, SkImageFilter* imf) {
+ SkPaint paint;
+ paint.setImageFilter(imf);
+ paint.setColor(SK_ColorGREEN);
+ canvas->save();
+ canvas->clipRect(r);
+ canvas->drawPaint(paint);
+ canvas->restore();
+}
+
+static void draw_line(SkCanvas* canvas, const SkRect& r, SkImageFilter* imf) {
+ SkPaint paint;
+ paint.setColor(SK_ColorBLUE);
+ paint.setImageFilter(imf);
+ paint.setStrokeWidth(r.width()/10);
+ canvas->drawLine(r.fLeft, r.fTop, r.fRight, r.fBottom, paint);
+}
+
+static void draw_rect(SkCanvas* canvas, const SkRect& r, SkImageFilter* imf) {
+ SkPaint paint;
+ paint.setColor(SK_ColorYELLOW);
+ paint.setImageFilter(imf);
+ SkRect rr(r);
+ rr.inset(r.width()/10, r.height()/10);
+ canvas->drawRect(rr, paint);
+}
+
+static void draw_path(SkCanvas* canvas, const SkRect& r, SkImageFilter* imf) {
+ SkPaint paint;
+ paint.setColor(SK_ColorMAGENTA);
+ paint.setImageFilter(imf);
+ paint.setAntiAlias(true);
+ canvas->drawCircle(r.centerX(), r.centerY(), r.width()*2/5, paint);
+}
+
+static void draw_text(SkCanvas* canvas, const SkRect& r, SkImageFilter* imf) {
+ SkPaint paint;
+ paint.setImageFilter(imf);
+ paint.setColor(SK_ColorCYAN);
+ paint.setAntiAlias(true);
+ paint.setTextSize(r.height()/2);
+ paint.setTextAlign(SkPaint::kCenter_Align);
+ canvas->drawText("Text", 4, r.centerX(), r.centerY(), paint);
+}
+
+static void draw_bitmap(SkCanvas* canvas, const SkRect& r, SkImageFilter* imf) {
+ SkPaint paint;
+ paint.setImageFilter(imf);
+
+ SkIRect bounds;
+ r.roundOut(&bounds);
+
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(), bounds.height());
+ bm.allocPixels();
+ bm.eraseColor(0);
+ SkCanvas c(bm);
+ draw_path(&c, r, NULL);
+
+ canvas->drawBitmap(bm, 0, 0, &paint);
+}
+
+static void draw_sprite(SkCanvas* canvas, const SkRect& r, SkImageFilter* imf) {
+ SkPaint paint;
+ paint.setImageFilter(imf);
+
+ SkIRect bounds;
+ r.roundOut(&bounds);
+
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(), bounds.height());
+ bm.allocPixels();
+ bm.eraseColor(0);
+ SkCanvas c(bm);
+ draw_path(&c, r, NULL);
+
+ SkPoint loc = { r.fLeft, r.fTop };
+ canvas->getTotalMatrix().mapPoints(&loc, 1);
+ canvas->drawSprite(bm,
+ SkScalarRoundToInt(loc.fX), SkScalarRoundToInt(loc.fY),
+ &paint);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class ImageFiltersBaseGM : public skiagm::GM {
+public:
+ ImageFiltersBaseGM () {}
+
+protected:
+
+ virtual SkString onShortName() {
+ return SkString("imagefiltersbase");
+ }
+
+ virtual SkISize onISize() { return SkISize::Make(700, 460); }
+
+ void draw_frame(SkCanvas* canvas, const SkRect& r) {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(SK_ColorRED);
+ canvas->drawRect(r, paint);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ void (*drawProc[])(SkCanvas*, const SkRect&, SkImageFilter*) = {
+ draw_paint,
+ draw_line, draw_rect, draw_path, draw_text,
+ draw_bitmap,
+ draw_sprite
+ };
+
+ SkColorFilter* cf = SkColorFilter::CreateModeFilter(SK_ColorRED,
+ SkXfermode::kSrcIn_Mode);
+ SkImageFilter* filters[] = {
+#if 1
+ NULL,
+ new IdentityImageFilter,
+ new FailImageFilter,
+ new SkColorFilterImageFilter(cf),
+#endif
+ new SkBlurImageFilter(12.0f, 0.0f),
+ };
+ cf->unref();
+
+ SkRect r = SkRect::MakeWH(SkIntToScalar(64), SkIntToScalar(64));
+ SkScalar MARGIN = SkIntToScalar(16);
+ SkScalar DX = r.width() + MARGIN;
+ SkScalar DY = r.height() + MARGIN;
+
+ canvas->translate(MARGIN, MARGIN);
+ for (size_t i = 0; i < SK_ARRAY_COUNT(drawProc); ++i) {
+ canvas->save();
+ for (size_t j = 0; j < SK_ARRAY_COUNT(filters); ++j) {
+ drawProc[i](canvas, r, filters[j]);
+
+ draw_frame(canvas, r);
+ canvas->translate(0, DY);
+ }
+ canvas->restore();
+ canvas->translate(DX, 0);
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static skiagm::GM* MyFactory(void*) { return new ImageFiltersBaseGM; }
+static skiagm::GMRegistry reg(MyFactory);
+
+
diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi
index 5beac2b787..491af68e64 100644
--- a/gyp/gmslides.gypi
+++ b/gyp/gmslides.gypi
@@ -26,6 +26,7 @@
'../gm/gradtext.cpp',
'../gm/hairmodes.cpp',
'../gm/imageblur.cpp',
+ '../gm/imagefiltersbase.cpp',
'../gm/lcdtext.cpp',
'../gm/linepaths.cpp',
'../gm/morphology.cpp',
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 7ad88f64cc..5224217fdc 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -977,6 +977,7 @@ private:
void updateDeviceCMCache();
friend class SkDrawIter; // needs setupDrawForLayerDevice()
+ friend class AutoDrawLooper;
SkDevice* createLayerDevice(SkBitmap::Config, int width, int height,
bool isOpaque);
@@ -992,9 +993,10 @@ private:
void internalDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
const SkRect& dst, const SkPaint* paint);
void internalDrawPaint(const SkPaint& paint);
+ int internalSaveLayer(const SkRect* bounds, const SkPaint* paint,
+ SaveFlags, bool justForImageFilter);
+ void internalDrawDevice(SkDevice*, int x, int y, const SkPaint*);
-
- void drawDevice(SkDevice*, int x, int y, const SkPaint*);
// shared by save() and saveLayer()
int internalSave(SaveFlags flags);
void internalRestore();
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index 3303981c74..db9c542ada 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -321,13 +321,22 @@ protected:
virtual bool allowImageFilter(SkImageFilter*);
/**
- * Override and return true for filters that the device handles
- * intrinsically. Returning false means call the filter.
- * Default impl returns false. This will only be called if allowImageFilter()
- * returned true.
+ * Override and return true for filters that the device can handle
+ * intrinsically. Doing so means that SkCanvas will pass-through this
+ * filter to drawSprite and drawDevice (and potentially filterImage).
+ * Returning false means the SkCanvas will have apply the filter itself,
+ * and just pass the resulting image to the device.
*/
- virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
- const SkMatrix& ctm,
+ virtual bool canHandleImageFilter(SkImageFilter*);
+
+ /**
+ * Related (but not required) to canHandleImageFilter, this method returns
+ * true if the device could apply the filter to the src bitmap and return
+ * the result (and updates offset as needed).
+ * If the device does not recognize or support this filter,
+ * it just returns false and leaves result and offset unchanged.
+ */
+ virtual bool filterImage(SkImageFilter*, const SkBitmap&, const SkMatrix&,
SkBitmap* result, SkIPoint* offset);
// This is equal kBGRA_Premul_Config8888 or kRGBA_Premul_Config8888 if
diff --git a/include/core/SkImageFilter.h b/include/core/SkImageFilter.h
index 7d7c1404f1..1b282d2e32 100644
--- a/include/core/SkImageFilter.h
+++ b/include/core/SkImageFilter.h
@@ -40,14 +40,16 @@ class SK_API SkImageFilter : public SkFlattenable {
public:
class Proxy {
public:
+ virtual ~Proxy() {};
+
virtual SkDevice* createDevice(int width, int height) = 0;
-
+ // returns true if the proxy can handle this filter natively
+ virtual bool canHandleImageFilter(SkImageFilter*) = 0;
// returns true if the proxy handled the filter itself. if this returns
// false then the filter's code will be called.
virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
const SkMatrix& ctm,
SkBitmap* result, SkIPoint* offset) = 0;
- virtual ~Proxy() {};
};
/**
diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h
index 24e6e5adb1..409e3b30a5 100644
--- a/include/gpu/SkGpuDevice.h
+++ b/include/gpu/SkGpuDevice.h
@@ -110,9 +110,9 @@ public:
*/
virtual void makeRenderTargetCurrent();
- virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
- const SkMatrix& ctm,
- SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
+ virtual bool canHandleImageFilter(SkImageFilter*) SK_OVERRIDE;
+ virtual bool filterImage(SkImageFilter*, const SkBitmap&, const SkMatrix&,
+ SkBitmap*, SkIPoint*) SK_OVERRIDE;
class SkAutoCachedTexture; // used internally
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 1cd9d719c0..dde357049c 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -277,20 +277,36 @@ private:
class AutoDrawLooper {
public:
- AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint) : fOrigPaint(paint) {
+ AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint,
+ bool skipLayerForImageFilter = false) : fOrigPaint(paint) {
fCanvas = canvas;
fLooper = paint.getLooper();
fFilter = canvas->getDrawFilter();
fPaint = NULL;
fSaveCount = canvas->getSaveCount();
+ fDoClearImageFilter = false;
fDone = false;
+ if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
+ SkPaint tmp;
+ tmp.setImageFilter(fOrigPaint.getImageFilter());
+ // it would be nice if we had a guess at the bounds, instead of null
+ (void)canvas->internalSaveLayer(NULL, &tmp,
+ SkCanvas::kARGB_ClipLayer_SaveFlag, true);
+ // we'll clear the imageFilter for the actual draws in next(), so
+ // it will only be applied during the restore().
+ fDoClearImageFilter = true;
+ }
+
if (fLooper) {
fLooper->init(canvas);
}
}
~AutoDrawLooper() {
+ if (fDoClearImageFilter) {
+ fCanvas->internalRestore();
+ }
SkASSERT(fCanvas->getSaveCount() == fSaveCount);
}
@@ -309,6 +325,7 @@ private:
SkDrawFilter* fFilter;
const SkPaint* fPaint;
int fSaveCount;
+ bool fDoClearImageFilter;
bool fDone;
};
@@ -318,8 +335,13 @@ bool AutoDrawLooper::next(SkDrawFilter::Type drawType) {
return false;
}
- if (fLooper || fFilter) {
+ if (fLooper || fFilter || fDoClearImageFilter) {
SkPaint* paint = fLazyPaint.set(fOrigPaint);
+
+ if (fDoClearImageFilter) {
+ paint->setImageFilter(NULL);
+ }
+
if (fLooper && !fLooper->next(fCanvas, paint)) {
fDone = true;
return false;
@@ -332,6 +354,11 @@ bool AutoDrawLooper::next(SkDrawFilter::Type drawType) {
}
}
fPaint = paint;
+
+ // if we only came in here for the imagefilter, mark us as done
+ if (!fLooper && !fFilter) {
+ fDone = true;
+ }
} else {
fDone = true;
fPaint = &fOrigPaint;
@@ -386,6 +413,13 @@ private:
////////// macros to place around the internal draw calls //////////////////
+#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
+/* AutoValidator validator(fMCRec->fTopLayer->fDevice); */ \
+ AutoDrawLooper looper(this, paint, true); \
+ while (looper.next(type)) { \
+ SkAutoBounderCommit ac(fBounder); \
+ SkDrawIter iter(this);
+
#define LOOPER_BEGIN(paint, type) \
/* AutoValidator validator(fMCRec->fTopLayer->fDevice); */ \
AutoDrawLooper looper(this, paint); \
@@ -749,6 +783,11 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
SaveFlags flags) {
+ return this->internalSaveLayer(bounds, paint, flags, false);
+}
+
+int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint,
+ SaveFlags flags, bool justForImageFilter) {
// do this before we create the layer. We don't call the public save() since
// that would invoke a possibly overridden virtual
int count = this->internalSave(flags);
@@ -764,6 +803,10 @@ int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
SkLazyPaint lazyP;
if (paint && paint->getImageFilter()) {
if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) {
+ if (justForImageFilter) {
+ // early exit if the layer was just for the imageFilter
+ return count;
+ }
SkPaint* p = lazyP.set(*paint);
p->setImageFilter(NULL);
paint = p;
@@ -841,9 +884,9 @@ void SkCanvas::internalRestore() {
if (NULL != layer) {
if (layer->fNext) {
const SkIPoint& origin = layer->fDevice->getOrigin();
- this->drawDevice(layer->fDevice, origin.x(), origin.y(),
- layer->fPaint);
- // reset this, since drawDevice will have set it to true
+ this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
+ layer->fPaint);
+ // reset this, since internalDrawDevice will have set it to true
fDeviceCMDirty = true;
SkASSERT(fLayerCount > 0);
@@ -905,43 +948,38 @@ class DeviceImageFilterProxy : public SkImageFilter::Proxy {
public:
DeviceImageFilterProxy(SkDevice* device) : fDevice(device) {}
- virtual SkDevice* createDevice(int w, int h) SK_OVERRIDE;
- virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
+ virtual SkDevice* createDevice(int w, int h) SK_OVERRIDE {
+ return fDevice->createCompatibleDevice(SkBitmap::kARGB_8888_Config,
+ w, h, false);
+ }
+ virtual bool canHandleImageFilter(SkImageFilter* filter) SK_OVERRIDE {
+ return fDevice->canHandleImageFilter(filter);
+ }
+ virtual bool filterImage(SkImageFilter* filter, const SkBitmap& src,
const SkMatrix& ctm,
- SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
-
+ SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
+ return fDevice->filterImage(filter, src, ctm, result, offset);
+ }
+
private:
SkDevice* fDevice;
};
-SkDevice* DeviceImageFilterProxy::createDevice(int w, int h) {
- return fDevice->createCompatibleDevice(SkBitmap::kARGB_8888_Config,
- w, h, false);
-}
-
-bool DeviceImageFilterProxy::filterImage(SkImageFilter* filter,
- const SkBitmap& src,
- const SkMatrix& ctm,
- SkBitmap* result,
- SkIPoint* offset) {
- return fDevice->filterImage(filter, src, ctm, result, offset);
-}
-
-void SkCanvas::drawDevice(SkDevice* srcDev, int x, int y,
- const SkPaint* paint) {
+void SkCanvas::internalDrawDevice(SkDevice* srcDev, int x, int y,
+ const SkPaint* paint) {
SkPaint tmp;
if (NULL == paint) {
tmp.setDither(true);
paint = &tmp;
}
- LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
+ LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
while (iter.next()) {
SkDevice* dstDev = iter.fDevice;
paint = &looper.paint();
SkImageFilter* filter = paint->getImageFilter();
SkIPoint pos = { x - iter.getX(), y - iter.getY() };
- if (filter) {
+ if (filter && !dstDev->canHandleImageFilter(filter)) {
DeviceImageFilterProxy proxy(dstDev);
SkBitmap dst;
const SkBitmap& src = srcDev->accessBitmap(false);
@@ -957,6 +995,40 @@ void SkCanvas::drawDevice(SkDevice* srcDev, int x, int y,
LOOPER_END
}
+void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
+ const SkPaint* paint) {
+ SkDEBUGCODE(bitmap.validate();)
+
+ if (reject_bitmap(bitmap)) {
+ return;
+ }
+
+ SkPaint tmp;
+ if (NULL == paint) {
+ paint = &tmp;
+ }
+
+ LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
+
+ while (iter.next()) {
+ paint = &looper.paint();
+ SkImageFilter* filter = paint->getImageFilter();
+ SkIPoint pos = { x - iter.getX(), y - iter.getY() };
+ if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
+ DeviceImageFilterProxy proxy(iter.fDevice);
+ SkBitmap dst;
+ if (filter->filterImage(&proxy, bitmap, *iter.fMatrix, &dst, &pos)) {
+ SkPaint tmp(*paint);
+ tmp.setImageFilter(NULL);
+ iter.fDevice->drawSprite(iter, dst, pos.x(), pos.y(), tmp);
+ }
+ } else {
+ iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
+ }
+ }
+ LOOPER_END
+}
+
/////////////////////////////////////////////////////////////////////////////
bool SkCanvas::translate(SkScalar dx, SkScalar dy) {
@@ -1575,28 +1647,6 @@ void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
this->internalDrawBitmapNine(bitmap, center, dst, paint);
}
-void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
- const SkPaint* paint) {
- SkDEBUGCODE(bitmap.validate();)
-
- if (reject_bitmap(bitmap)) {
- return;
- }
-
- SkPaint tmp;
- if (NULL == paint) {
- paint = &tmp;
- }
-
- LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
-
- while (iter.next()) {
- iter.fDevice->drawSprite(iter, bitmap, x - iter.getX(), y - iter.getY(),
- looper.paint());
- }
- LOOPER_END
-}
-
class SkDeviceFilteredPaint {
public:
SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) {
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index f1da2ef919..b92f4e1985 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -101,9 +101,13 @@ void SkDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& region,
const SkClipStack& clipStack) {
}
-bool SkDevice::filterImage(SkImageFilter*, const SkBitmap& src,
- const SkMatrix& ctm,
- SkBitmap* result, SkIPoint* offset) {
+bool SkDevice::canHandleImageFilter(SkImageFilter*) {
+ return false;
+}
+
+bool SkDevice::filterImage(SkImageFilter* filter, const SkBitmap& src,
+ const SkMatrix& ctm, SkBitmap* result,
+ SkIPoint* offset) {
return false;
}
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 4917dcb1a4..0ac4ed52d8 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1398,11 +1398,50 @@ void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
}
+static GrTexture* filter_texture(GrContext* context, GrTexture* texture,
+ SkImageFilter* filter, const GrRect& rect) {
+ GrAssert(filter);
+
+ SkSize blurSize;
+ SkISize radius;
+
+ const GrTextureDesc desc = {
+ kRenderTarget_GrTextureFlagBit,
+ rect.width(),
+ rect.height(),
+ kRGBA_8888_PM_GrPixelConfig,
+ {0} // samples
+ };
+
+ if (filter->asABlur(&blurSize)) {
+ GrAutoScratchTexture temp1, temp2;
+ texture = context->gaussianBlur(texture, &temp1, &temp2, rect,
+ blurSize.width(),
+ blurSize.height());
+ texture->ref();
+ } else if (filter->asADilate(&radius)) {
+ GrAutoScratchTexture temp1(context, desc), temp2(context, desc);
+ texture = context->applyMorphology(texture, rect,
+ temp1.texture(), temp2.texture(),
+ GrSamplerState::kDilate_Filter,
+ radius);
+ texture->ref();
+ } else if (filter->asAnErode(&radius)) {
+ GrAutoScratchTexture temp1(context, desc), temp2(context, desc);
+ texture = context->applyMorphology(texture, rect,
+ temp1.texture(), temp2.texture(),
+ GrSamplerState::kErode_Filter,
+ radius);
+ texture->ref();
+ }
+ return texture;
+}
+
void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
int left, int top, const SkPaint& paint) {
CHECK_SHOULD_DRAW(draw);
- SkAutoLockPixels alp(bitmap);
+ SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
return;
}
@@ -1422,50 +1461,19 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
GrTexture* texture;
sampler->reset();
SkAutoCachedTexture act(this, bitmap, sampler, &texture);
-
- SkImageFilter* imageFilter = paint.getImageFilter();
- SkSize blurSize;
- SkISize radius;
- if (NULL != imageFilter && imageFilter->asABlur(&blurSize)) {
- GrAutoScratchTexture temp1, temp2;
- GrTexture* blurTexture = fContext->gaussianBlur(texture, &temp1, &temp2,
- GrRect::MakeWH(w, h),
- blurSize.width(),
- blurSize.height());
- texture = blurTexture;
- grPaint.setTexture(kBitmapTextureIdx, texture);
- } else if (NULL != imageFilter && imageFilter->asADilate(&radius)) {
- const GrTextureDesc desc = {
- kRenderTarget_GrTextureFlagBit,
- w,
- h,
- kRGBA_8888_PM_GrPixelConfig,
- {0} // samples
- };
- GrAutoScratchTexture temp1(fContext, desc), temp2(fContext, desc);
- texture = fContext->applyMorphology(texture, GrRect::MakeWH(w, h),
- temp1.texture(), temp2.texture(),
- GrSamplerState::kDilate_Filter,
- radius);
- grPaint.setTexture(kBitmapTextureIdx, texture);
- } else if (NULL != imageFilter && imageFilter->asAnErode(&radius)) {
- const GrTextureDesc desc = {
- kRenderTarget_GrTextureFlagBit,
- w,
- h,
- kRGBA_8888_PM_GrPixelConfig,
- {0} // samples
- };
- GrAutoScratchTexture temp1(fContext, desc), temp2(fContext, desc);
- texture = fContext->applyMorphology(texture, GrRect::MakeWH(w, h),
- temp1.texture(), temp2.texture(),
- GrSamplerState::kErode_Filter,
- radius);
- grPaint.setTexture(kBitmapTextureIdx, texture);
- } else {
- grPaint.setTexture(kBitmapTextureIdx, texture);
+ grPaint.setTexture(kBitmapTextureIdx, texture);
+
+ SkImageFilter* filter = paint.getImageFilter();
+ if (NULL != filter) {
+ GrTexture* filteredTexture = filter_texture(fContext, texture, filter,
+ GrRect::MakeWH(w, h));
+ if (filteredTexture) {
+ grPaint.setTexture(kBitmapTextureIdx, filteredTexture);
+ texture = filteredTexture;
+ filteredTexture->unref();
+ }
}
-
+
fContext->drawRectToRect(grPaint,
GrRect::MakeXYWH(GrIntToScalar(left),
GrIntToScalar(top),
@@ -1488,6 +1496,18 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
GrTexture* devTex = grPaint.getTexture(0);
SkASSERT(NULL != devTex);
+ SkImageFilter* filter = paint.getImageFilter();
+ if (NULL != filter) {
+ GrRect rect = GrRect::MakeWH(devTex->width(), devTex->height());
+ GrTexture* filteredTexture = filter_texture(fContext, devTex, filter,
+ rect);
+ if (filteredTexture) {
+ grPaint.setTexture(kBitmapTextureIdx, filteredTexture);
+ devTex = filteredTexture;
+ filteredTexture->unref();
+ }
+ }
+
const SkBitmap& bm = dev->accessBitmap(false);
int w = bm.width();
int h = bm.height();
@@ -1509,27 +1529,43 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
fContext->drawRectToRect(grPaint, dstRect, srcRect);
}
-bool SkGpuDevice::filterImage(SkImageFilter* filter, const SkBitmap& src,
- const SkMatrix& ctm,
- SkBitmap* result, SkIPoint* offset) {
+bool SkGpuDevice::canHandleImageFilter(SkImageFilter* filter) {
SkSize size;
SkISize radius;
if (!filter->asABlur(&size) && !filter->asADilate(&radius) && !filter->asAnErode(&radius)) {
return false;
}
- SkDevice* dev = this->createCompatibleDevice(SkBitmap::kARGB_8888_Config,
- src.width(),
- src.height(),
- false);
- if (NULL == dev) {
+ return true;
+}
+
+bool SkGpuDevice::filterImage(SkImageFilter* filter, const SkBitmap& src,
+ const SkMatrix& ctm,
+ SkBitmap* result, SkIPoint* offset) {
+ // want explicitly our impl, so guard against a subclass of us overriding it
+ if (!this->SkGpuDevice::canHandleImageFilter(filter)) {
+ return false;
+ }
+
+ SkAutoLockPixels alp(src, !src.getTexture());
+ if (!src.getTexture() && !src.readyToDraw()) {
return false;
}
- SkAutoUnref aur(dev);
- SkCanvas canvas(dev);
- SkPaint paint;
- paint.setImageFilter(filter);
- canvas.drawSprite(src, 0, 0, &paint);
- *result = dev->accessBitmap(false);
+
+ GrPaint paint;
+ paint.reset();
+
+ GrSamplerState* sampler = paint.textureSampler(kBitmapTextureIdx);
+
+ GrTexture* texture;
+ SkAutoCachedTexture act(this, src, sampler, &texture);
+
+ result->setConfig(src.config(), src.width(), src.height());
+ GrRect rect = GrRect::MakeWH(src.width(), src.height());
+ GrTexture* resultTexture = filter_texture(fContext, texture, filter, rect);
+ if (resultTexture) {
+ result->setPixelRef(new SkGrTexturePixelRef(resultTexture))->unref();
+ resultTexture->unref();
+ }
return true;
}