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
This commit is contained in:
parent
2e87ba0c7c
commit
d043ccee37
@ -96,6 +96,7 @@
|
||||
'<(skia_src_path)/core/SkGraphics.cpp',
|
||||
'<(skia_src_path)/core/SkInstCnt.cpp',
|
||||
'<(skia_src_path)/core/SkImageFilter.cpp',
|
||||
'<(skia_src_path)/core/SkImageFilterUtils.cpp',
|
||||
'<(skia_src_path)/core/SkLineClipper.cpp',
|
||||
'<(skia_src_path)/core/SkMallocPixelRef.cpp',
|
||||
'<(skia_src_path)/core/SkMask.cpp',
|
||||
@ -230,6 +231,7 @@
|
||||
'<(skia_include_path)/core/SkGeometry.h',
|
||||
'<(skia_include_path)/core/SkGraphics.h',
|
||||
'<(skia_include_path)/core/SkImageFilter.h',
|
||||
'<(skia_include_path)/core/SkImageFilterUtils.h',
|
||||
'<(skia_include_path)/core/SkInstCnt.h',
|
||||
'<(skia_include_path)/core/SkMallocPixelRef.h',
|
||||
'<(skia_include_path)/core/SkMask.h',
|
||||
|
@ -31,7 +31,6 @@
|
||||
'<(skia_src_path)/effects/SkEmbossMask.h',
|
||||
'<(skia_src_path)/effects/SkEmbossMask_Table.h',
|
||||
'<(skia_src_path)/effects/SkEmbossMaskFilter.cpp',
|
||||
'<(skia_src_path)/effects/SkImageFilterUtils.cpp',
|
||||
'<(skia_src_path)/effects/SkKernel33MaskFilter.cpp',
|
||||
'<(skia_src_path)/effects/SkLayerDrawLooper.cpp',
|
||||
'<(skia_src_path)/effects/SkLayerRasterizer.cpp',
|
||||
@ -89,7 +88,6 @@
|
||||
'<(skia_include_path)/effects/SkDrawExtraPathEffect.h',
|
||||
'<(skia_include_path)/effects/SkEmbossMaskFilter.h',
|
||||
'<(skia_include_path)/effects/SkGradientShader.h',
|
||||
'<(skia_include_path)/effects/SkImageFilterUtils.h',
|
||||
'<(skia_include_path)/effects/SkKernel33MaskFilter.h',
|
||||
'<(skia_include_path)/effects/SkLayerDrawLooper.h',
|
||||
'<(skia_include_path)/effects/SkLayerRasterizer.h',
|
||||
|
@ -99,16 +99,18 @@ public:
|
||||
* Returns true if the filter can be processed on the GPU. This is most
|
||||
* often used for multi-pass effects, where intermediate results must be
|
||||
* rendered to textures. For single-pass effects, use asNewEffect().
|
||||
* The default implementation returns false.
|
||||
* The default implementation returns asNewEffect(NULL, NULL).
|
||||
*/
|
||||
virtual bool canFilterImageGPU() const;
|
||||
|
||||
/**
|
||||
* Process this image filter on the GPU. 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 returns returns false and ignores the
|
||||
* result parameter.
|
||||
* Process this image filter on the GPU. This is most often used for
|
||||
* multi-pass effects, where intermediate results must be rendered to
|
||||
* 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().
|
||||
*/
|
||||
virtual bool filterImageGPU(Proxy*, const SkBitmap& src, SkBitmap* result);
|
||||
|
||||
|
36
include/core/SkImageFilterUtils.h
Normal file
36
include/core/SkImageFilterUtils.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2013 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 SkImageFilterUtils_DEFINED
|
||||
#define SkImageFilterUtils_DEFINED
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
#include "SkImageFilter.h"
|
||||
|
||||
class SkBitmap;
|
||||
class GrTexture;
|
||||
class SkImageFilter;
|
||||
|
||||
class SK_API SkImageFilterUtils {
|
||||
public:
|
||||
/**
|
||||
* Wrap the given texture in a texture-backed SkBitmap.
|
||||
*/
|
||||
static bool WrapTexture(GrTexture* texture, int width, int height, SkBitmap* result);
|
||||
|
||||
/**
|
||||
* Recursively evaluate the given filter on the GPU. If filter is NULL,
|
||||
* 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);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -16,7 +16,9 @@ class SK_API SkMagnifierImageFilter : public SkImageFilter {
|
||||
public:
|
||||
SkMagnifierImageFilter(SkRect srcRect, SkScalar inset);
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
virtual bool asNewEffect(GrEffectRef** effect, GrTexture* texture) const SK_OVERRIDE;
|
||||
#endif
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMagnifierImageFilter)
|
||||
|
||||
|
@ -62,7 +62,7 @@ protected:
|
||||
SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
virtual bool asNewEffect(GrEffectRef**, GrTexture*) const SK_OVERRIDE;
|
||||
virtual bool asNewEffect(GrEffectRef** effect, GrTexture*) const SK_OVERRIDE;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
@ -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::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&,
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -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;
|
@ -264,7 +264,9 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
|
||||
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 @@ bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
|
||||
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
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -212,7 +212,7 @@ GrEffectRef* GrMagnifierEffect::TestCreate(SkMWCRandom* random,
|
||||
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 @@ SkMagnifierImageFilter::SkMagnifierImageFilter(SkRect srcRect, SkScalar inset)
|
||||
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);
|
||||
|
@ -562,18 +562,19 @@ GrEffectRef* GrMatrixConvolutionEffect::TestCreate(SkMWCRandom* random,
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1404,26 +1404,6 @@ void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap,
|
||||
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 @@ static bool filter_texture(SkDevice* device, GrContext* context,
|
||||
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 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* device,
|
||||
}
|
||||
|
||||
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,
|
||||
|
Loading…
Reference in New Issue
Block a user