Implements a new class, SkSingleInputImageFilter, to handle DAG connectivity
for filters with a single image input. This provides functionality to store,
flatten and unflatten a single SkImageFilter input, as well as to recursively
evaluate it on the CPU or GPU. The following classes were re-parented to
implement DAG connectivity: SkBlurImageFilter, SkDilateImageFilter,
SkErodeImageFilter, SkColorFilterImageFilter. The constructors for each
have been appended with a new parameter, representing the input filter
(default NULL).
This change also implements an arbitrary SkBitmap input source for filtering,
SkBitmapSource.
NOTE: This CL will require gyp file changes when rolling past this revision.
Review URL: https://codereview.appspot.com/6462071/
git-svn-id: http://skia.googlecode.com/svn/trunk@5170 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 2cfb67b..0f1aecf 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -2309,14 +2309,13 @@
bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
const SkMatrix& ctm,
SkBitmap* result, SkIPoint* loc) {
- SkASSERT(proxy);
SkASSERT(result);
SkASSERT(loc);
/*
* Give the proxy first shot at the filter. If it returns false, ask
* the filter to do it.
*/
- return proxy->filterImage(this, src, ctm, result, loc) ||
+ return (proxy && proxy->filterImage(this, src, ctm, result, loc)) ||
this->onFilterImage(proxy, src, ctm, result, loc);
}
diff --git a/src/effects/SkBitmapSource.cpp b/src/effects/SkBitmapSource.cpp
new file mode 100644
index 0000000..3092b93
--- /dev/null
+++ b/src/effects/SkBitmapSource.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2012 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 "SkBitmapSource.h"
+
+SkBitmapSource::SkBitmapSource(const SkBitmap& bitmap) : fBitmap(bitmap) {
+}
+
+SkBitmapSource::SkBitmapSource(SkFlattenableReadBuffer& buffer)
+ : INHERITED(buffer) {
+ fBitmap.unflatten(buffer);
+}
+
+void SkBitmapSource::flatten(SkFlattenableWriteBuffer& buffer) const {
+ this->INHERITED::flatten(buffer);
+ fBitmap.flatten(buffer);
+}
+
+bool SkBitmapSource::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&,
+ SkBitmap* result, SkIPoint* offset) {
+ *result = fBitmap;
+ return true;
+}
+
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkBitmapSource)
diff --git a/src/effects/SkBlurImageFilter.cpp b/src/effects/SkBlurImageFilter.cpp
index b01795b..c822626 100644
--- a/src/effects/SkBlurImageFilter.cpp
+++ b/src/effects/SkBlurImageFilter.cpp
@@ -19,8 +19,8 @@
fSigma.fHeight = buffer.readScalar();
}
-SkBlurImageFilter::SkBlurImageFilter(SkScalar sigmaX, SkScalar sigmaY)
- : fSigma(SkSize::Make(sigmaX, sigmaY)) {
+SkBlurImageFilter::SkBlurImageFilter(SkScalar sigmaX, SkScalar sigmaY, SkImageFilter* input)
+ : INHERITED(input), fSigma(SkSize::Make(sigmaX, sigmaY)) {
SkASSERT(sigmaX >= 0 && sigmaY >= 0);
}
@@ -133,9 +133,10 @@
}
}
-bool SkBlurImageFilter::onFilterImage(Proxy*,
- const SkBitmap& src, const SkMatrix&,
- SkBitmap* dst, SkIPoint*) {
+bool SkBlurImageFilter::onFilterImage(Proxy* proxy,
+ const SkBitmap& source, const SkMatrix& ctm,
+ SkBitmap* dst, SkIPoint* offset) {
+ SkBitmap src = this->getInputResult(proxy, source, ctm, offset);
if (src.config() != SkBitmap::kARGB_8888_Config) {
return false;
}
@@ -188,7 +189,8 @@
GrTexture* SkBlurImageFilter::onFilterImageGPU(GrTexture* src, const SkRect& rect) {
#if SK_SUPPORT_GPU
- return src->getContext()->gaussianBlur(src, false, rect,
+ SkAutoTUnref<GrTexture> input(this->getInputResultAsTexture(src, rect));
+ return src->getContext()->gaussianBlur(input.get(), false, rect,
fSigma.width(), fSigma.height());
#else
SkDEBUGFAIL("Should not call in GPU-less build");
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
index c1e2d26..34b3c09 100644
--- a/src/effects/SkMorphologyImageFilter.cpp
+++ b/src/effects/SkMorphologyImageFilter.cpp
@@ -21,8 +21,8 @@
fRadius.fHeight = buffer.readInt();
}
-SkMorphologyImageFilter::SkMorphologyImageFilter(int radiusX, int radiusY)
- : fRadius(SkISize::Make(radiusX, radiusY)) {
+SkMorphologyImageFilter::SkMorphologyImageFilter(int radiusX, int radiusY, SkImageFilter* input)
+ : INHERITED(input), fRadius(SkISize::Make(radiusX, radiusY)) {
}
@@ -128,9 +128,10 @@
src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels(), 1);
}
-bool SkErodeImageFilter::onFilterImage(Proxy*,
- const SkBitmap& src, const SkMatrix&,
- SkBitmap* dst, SkIPoint*) {
+bool SkErodeImageFilter::onFilterImage(Proxy* proxy,
+ const SkBitmap& source, const SkMatrix& ctm,
+ SkBitmap* dst, SkIPoint* offset) {
+ SkBitmap src = this->getInputResult(proxy, source, ctm, offset);
if (src.config() != SkBitmap::kARGB_8888_Config) {
return false;
}
@@ -172,9 +173,10 @@
return true;
}
-bool SkDilateImageFilter::onFilterImage(Proxy*,
- const SkBitmap& src, const SkMatrix&,
- SkBitmap* dst, SkIPoint*) {
+bool SkDilateImageFilter::onFilterImage(Proxy* proxy,
+ const SkBitmap& source, const SkMatrix& ctm,
+ SkBitmap* dst, SkIPoint* offset) {
+ SkBitmap src = this->getInputResult(proxy, source, ctm, offset);
if (src.config() != SkBitmap::kARGB_8888_Config) {
return false;
}
@@ -218,7 +220,8 @@
GrTexture* SkDilateImageFilter::onFilterImageGPU(GrTexture* src, const SkRect& rect) {
#if SK_SUPPORT_GPU
- return src->getContext()->applyMorphology(src, rect,
+ SkAutoTUnref<GrTexture> input(this->getInputResultAsTexture(src, rect));
+ return src->getContext()->applyMorphology(input.get(), rect,
GrContext::kDilate_MorphologyType,
radius());
#else
@@ -229,7 +232,8 @@
GrTexture* SkErodeImageFilter::onFilterImageGPU(GrTexture* src, const SkRect& rect) {
#if SK_SUPPORT_GPU
- return src->getContext()->applyMorphology(src, rect,
+ SkAutoTUnref<GrTexture> input(this->getInputResultAsTexture(src, rect));
+ return src->getContext()->applyMorphology(input.get(), rect,
GrContext::kErode_MorphologyType,
radius());
#else
diff --git a/src/effects/SkSingleInputImageFilter.cpp b/src/effects/SkSingleInputImageFilter.cpp
new file mode 100644
index 0000000..291d81c
--- /dev/null
+++ b/src/effects/SkSingleInputImageFilter.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSingleInputImageFilter.h"
+#include "SkBitmap.h"
+#include "SkFlattenableBuffers.h"
+#include "SkMatrix.h"
+#if SK_SUPPORT_GPU
+#include "GrTexture.h"
+#include "SkGr.h"
+#include "SkGrPixelRef.h"
+#endif
+
+SkSingleInputImageFilter::SkSingleInputImageFilter(SkImageFilter* input) : fInput(input) {
+ SkSafeRef(fInput);
+}
+
+SkSingleInputImageFilter::~SkSingleInputImageFilter() {
+ SkSafeUnref(fInput);
+}
+
+SkSingleInputImageFilter::SkSingleInputImageFilter(SkFlattenableReadBuffer& rb) {
+ if (rb.readBool()) {
+ fInput = rb.readFlattenableT<SkImageFilter>();
+ } else {
+ fInput = NULL;
+ }
+}
+
+void SkSingleInputImageFilter::flatten(SkFlattenableWriteBuffer& wb) const {
+ wb.writeBool(NULL != fInput);
+ if (NULL != fInput) {
+ wb.writeFlattenable(fInput);
+ }
+}
+
+SkBitmap SkSingleInputImageFilter::getInputResult(Proxy* proxy,
+ const SkBitmap& src,
+ const SkMatrix& ctm,
+ SkIPoint* offset) {
+ SkBitmap result;
+ if (fInput && fInput->filterImage(proxy, src, ctm, &result, offset)) {
+ return result;
+ } else {
+ return src;
+ }
+}
+
+#if SK_SUPPORT_GPU
+GrTexture* SkSingleInputImageFilter::getInputResultAsTexture(GrTexture* src,
+ const SkRect& rect) {
+ GrTexture* resultTex;
+ if (!fInput) {
+ resultTex = src;
+ } else if (fInput->canFilterImageGPU()) {
+ // onFilterImageGPU() already refs the result, so just return it here.
+ return fInput->onFilterImageGPU(src, rect);
+ } else {
+ SkBitmap srcBitmap, result;
+ srcBitmap.setConfig(SkBitmap::kARGB_8888_Config, src->width(), src->height());
+ srcBitmap.setPixelRef(new SkGrPixelRef(src))->unref();
+ SkIPoint offset;
+ if (fInput->filterImage(NULL, srcBitmap, SkMatrix(), &result, &offset)) {
+ if (result.getTexture()) {
+ resultTex = (GrTexture*) result.getTexture();
+ } else {
+ resultTex = GrLockCachedBitmapTexture(src->getContext(), result, NULL);
+ SkSafeRef(resultTex);
+ GrUnlockCachedBitmapTexture(resultTex);
+ return resultTex;
+ }
+ } else {
+ resultTex = src;
+ }
+ }
+ SkSafeRef(resultTex);
+ return resultTex;
+}
+#endif
+
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkSingleInputImageFilter)
diff --git a/src/effects/SkTestImageFilters.cpp b/src/effects/SkTestImageFilters.cpp
index 70e39ef..0fbc293 100755
--- a/src/effects/SkTestImageFilters.cpp
+++ b/src/effects/SkTestImageFilters.cpp
@@ -290,10 +290,11 @@
SkSafeUnref(fColorFilter);
}
-bool SkColorFilterImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
+bool SkColorFilterImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source,
const SkMatrix& matrix,
SkBitmap* result,
SkIPoint* loc) {
+ SkBitmap src = this->getInputResult(proxy, source, matrix, loc);
SkColorFilter* cf = fColorFilter;
if (NULL == cf) {
*result = src;