Allow single-pass filters (which use asNewEffect()) to participate in the image filter DAG. This was done by introducing the SkSinglePassImageFilter abstract base class, which implements canFilterImageGPU() and filterImageGPU() on behalf of the derived class. The derived class still only needs to asNewEffect(). This allows us to recurse on the filter input in SkSinglePassImageFilter::onFilterImageGPU(). It also allows us to remove any knowledge of single-pass image filters from SkGpuDevice and from the SkImageFilter base class as well.
BUG=
Review URL: https://codereview.chromium.org/13602013
git-svn-id: http://skia.googlecode.com/svn/trunk@8563 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp
index 56fb1ae..2d81026 100644
--- a/src/core/SkImageFilter.cpp
+++ b/src/core/SkImageFilter.cpp
@@ -10,6 +10,11 @@
#include "SkBitmap.h"
#include "SkFlattenableBuffers.h"
#include "SkRect.h"
+#if SK_SUPPORT_GPU
+#include "GrContext.h"
+#include "GrTexture.h"
+#include "SkImageFilterUtils.h"
+#endif
SK_DEFINE_INST_COUNT(SkImageFilter)
@@ -104,12 +109,45 @@
}
bool SkImageFilter::canFilterImageGPU() const {
- return false;
+ return this->asNewEffect(NULL, NULL);
}
bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
- SkASSERT(false); // Should never be called, since canFilterImageGPU() returned false.
+#if SK_SUPPORT_GPU
+ SkBitmap input;
+ SkASSERT(fInputCount == 1);
+ if (!SkImageFilterUtils::GetInputResultGPU(this->getInput(0), proxy, src, &input)) {
+ return false;
+ }
+ GrTexture* srcTexture = (GrTexture*) input.getTexture();
+ SkRect rect;
+ src.getBounds(&rect);
+ GrContext* context = srcTexture->getContext();
+
+ GrTextureDesc desc;
+ desc.fFlags = kRenderTarget_GrTextureFlagBit,
+ desc.fWidth = input.width();
+ desc.fHeight = input.height();
+ desc.fConfig = kRGBA_8888_GrPixelConfig;
+
+ GrAutoScratchTexture dst(context, desc);
+ GrContext::AutoMatrix am;
+ am.setIdentity(context);
+ GrContext::AutoRenderTarget art(context, dst.texture()->asRenderTarget());
+ GrContext::AutoClip acs(context, rect);
+ GrEffectRef* effect;
+ this->asNewEffect(&effect, srcTexture);
+ SkASSERT(effect);
+ SkAutoUnref effectRef(effect);
+ GrPaint paint;
+ paint.colorStage(0)->setEffect(effect);
+ context->drawRect(paint, rect);
+ SkAutoTUnref<GrTexture> resultTex(dst.detach());
+ SkImageFilterUtils::WrapTexture(resultTex, input.width(), input.height(), result);
+ return true;
+#else
return false;
+#endif
}
bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
diff --git a/src/effects/SkImageFilterUtils.cpp b/src/core/SkImageFilterUtils.cpp
similarity index 95%
rename from src/effects/SkImageFilterUtils.cpp
rename to src/core/SkImageFilterUtils.cpp
index 2dfb33d..d6e109c 100644
--- a/src/effects/SkImageFilterUtils.cpp
+++ b/src/core/SkImageFilterUtils.cpp
@@ -15,7 +15,6 @@
#include "SkGr.h"
bool SkImageFilterUtils::WrapTexture(GrTexture* texture, int width, int height, SkBitmap* result) {
- SkASSERT(texture->config() == kSkia8888_GrPixelConfig);
result->setConfig(SkBitmap::kARGB_8888_Config, width, height);
result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (texture)))->unref();
return true;
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index a22bc6f..bb2927b 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -264,7 +264,9 @@
SkScalar kd, SkImageFilter* input);
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
+#if SK_SUPPORT_GPU
virtual bool asNewEffect(GrEffectRef** effect, GrTexture*) const SK_OVERRIDE;
+#endif
SkScalar kd() const { return fKD; }
protected:
@@ -284,7 +286,10 @@
SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input);
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
+#if SK_SUPPORT_GPU
virtual bool asNewEffect(GrEffectRef** effect, GrTexture*) const SK_OVERRIDE;
+#endif
+
SkScalar ks() const { return fKS; }
SkScalar shininess() const { return fShininess; }
@@ -859,19 +864,15 @@
return true;
}
-bool SkDiffuseLightingImageFilter::asNewEffect(GrEffectRef** effect,
- GrTexture* texture) const {
#if SK_SUPPORT_GPU
+bool SkDiffuseLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture) const {
if (effect) {
SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
*effect = GrDiffuseLightingEffect::Create(texture, light(), scale, kd());
}
return true;
-#else
- SkDEBUGFAIL("Should not call in GPU-less build");
- return false;
-#endif
}
+#endif
///////////////////////////////////////////////////////////////////////////////
@@ -928,19 +929,15 @@
return true;
}
-bool SkSpecularLightingImageFilter::asNewEffect(GrEffectRef** effect,
- GrTexture* texture) const {
#if SK_SUPPORT_GPU
+bool SkSpecularLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture) const {
if (effect) {
SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
*effect = GrSpecularLightingEffect::Create(texture, light(), scale, ks(), shininess());
}
return true;
-#else
- SkDEBUGFAIL("Should not call in GPU-less build");
- return false;
-#endif
}
+#endif
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/effects/SkMagnifierImageFilter.cpp b/src/effects/SkMagnifierImageFilter.cpp
index f6675c4..a68ab7c 100644
--- a/src/effects/SkMagnifierImageFilter.cpp
+++ b/src/effects/SkMagnifierImageFilter.cpp
@@ -212,7 +212,7 @@
uint32_t y = random->nextULessThan(kMaxHeight - height);
SkScalar inset = SkIntToScalar(random->nextULessThan(kMaxInset));
- SkAutoTUnref<SkImageFilter> filter(
+ SkAutoTUnref<SkMagnifierImageFilter> filter(
new SkMagnifierImageFilter(
SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y),
SkIntToScalar(width), SkIntToScalar(height)),
@@ -263,22 +263,20 @@
SkASSERT(srcRect.x() >= 0 && srcRect.y() >= 0 && inset >= 0);
}
-bool SkMagnifierImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture) const {
#if SK_SUPPORT_GPU
+bool SkMagnifierImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture) const {
if (effect) {
- *effect = GrMagnifierEffect::Create(texture,
- fSrcRect.x() / texture->width(),
- fSrcRect.y() / texture->height(),
- texture->width() / fSrcRect.width(),
- texture->height() / fSrcRect.height(),
- fInset / texture->width(),
- fInset / texture->height());
+ *effect = GrMagnifierEffect::Create(texture,
+ fSrcRect.x() / texture->width(),
+ fSrcRect.y() / texture->height(),
+ texture->width() / fSrcRect.width(),
+ texture->height() / fSrcRect.height(),
+ fInset / texture->width(),
+ fInset / texture->height());
}
return true;
-#else
- return false;
-#endif
}
+#endif
void SkMagnifierImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
this->INHERITED::flatten(buffer);
diff --git a/src/effects/SkMatrixConvolutionImageFilter.cpp b/src/effects/SkMatrixConvolutionImageFilter.cpp
index e3711d2..6368096 100644
--- a/src/effects/SkMatrixConvolutionImageFilter.cpp
+++ b/src/effects/SkMatrixConvolutionImageFilter.cpp
@@ -562,18 +562,19 @@
bool SkMatrixConvolutionImageFilter::asNewEffect(GrEffectRef** effect,
GrTexture* texture) const {
- bool ok = fKernelSize.width() * fKernelSize.height() <= MAX_KERNEL_SIZE;
- if (ok && effect) {
- *effect = GrMatrixConvolutionEffect::Create(texture,
- fKernelSize,
- fKernel,
- fGain,
- fBias,
- fTarget,
- fTileMode,
- fConvolveAlpha);
+ if (!effect) {
+ return fKernelSize.width() * fKernelSize.height() <= MAX_KERNEL_SIZE;
}
- return ok;
+ SkASSERT(fKernelSize.width() * fKernelSize.height() <= MAX_KERNEL_SIZE);
+ *effect = GrMatrixConvolutionEffect::Create(texture,
+ fKernelSize,
+ fKernel,
+ fGain,
+ fBias,
+ fTarget,
+ fTileMode,
+ fConvolveAlpha);
+ return true;
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 45176cf..c1364af 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1404,26 +1404,6 @@
fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
}
-namespace {
-
-void apply_effect(GrContext* context,
- GrTexture* srcTexture,
- GrTexture* dstTexture,
- const GrRect& rect,
- GrEffectRef* effect) {
- SkASSERT(srcTexture && srcTexture->getContext() == context);
- GrContext::AutoMatrix am;
- am.setIdentity(context);
- GrContext::AutoRenderTarget art(context, dstTexture->asRenderTarget());
- GrContext::AutoClip acs(context, rect);
-
- GrPaint paint;
- paint.colorStage(0)->setEffect(effect);
- context->drawRect(paint, rect);
-}
-
-};
-
static SkBitmap wrap_texture(GrTexture* texture) {
SkBitmap result;
bool dummy;
@@ -1439,26 +1419,11 @@
GrAssert(filter);
SkDeviceImageFilterProxy proxy(device);
- GrTextureDesc desc;
- desc.fFlags = kRenderTarget_GrTextureFlagBit,
- desc.fWidth = w;
- desc.fHeight = h;
- desc.fConfig = kRGBA_8888_GrPixelConfig;
- GrEffectRef* effect;
-
if (filter->canFilterImageGPU()) {
// 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);
- } else if (filter->asNewEffect(&effect, texture)) {
- GrAutoScratchTexture dst(context, desc);
- SkRect r = SkRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h));
- apply_effect(context, texture, dst.texture(), r, effect);
- SkAutoTUnref<GrTexture> resultTex(dst.detach());
- effect->unref();
- *result = wrap_texture(resultTex.get());
- return true;
} else {
return false;
}
@@ -1594,11 +1559,7 @@
}
bool SkGpuDevice::canHandleImageFilter(SkImageFilter* filter) {
- if (!filter->asNewEffect(NULL, NULL) &&
- !filter->canFilterImageGPU()) {
- return false;
- }
- return true;
+ return filter->canFilterImageGPU();
}
bool SkGpuDevice::filterImage(SkImageFilter* filter, const SkBitmap& src,