This changes the signature of SkImageFilter::filterImageGPU() to use SkBitmaps for input and output, and removes the rect param. This allows us to return textures which are larger than the actual result, such as when GrAutoScratchTextures are used. The SkBitmap's size represents the active region, while the GrTexture's size is the full texture size.
This fixes the bicubic image filter GM on the GPU, which otherwise draws garbage outside the filtered region. It also moves us closer to unifying the signatures of SkImageFilter::onFilterImage() and SkImageFilter::filterImageGPU(). Review URL: https://codereview.appspot.com/7180048 git-svn-id: http://skia.googlecode.com/svn/trunk@7467 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
74749cd45c
commit
c2594f4106
@ -31,6 +31,7 @@
|
||||
'<(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',
|
||||
|
@ -16,7 +16,6 @@ class SkDevice;
|
||||
class SkMatrix;
|
||||
struct SkIPoint;
|
||||
struct SkIRect;
|
||||
struct SkRect;
|
||||
class GrEffectRef;
|
||||
class GrTexture;
|
||||
|
||||
@ -104,13 +103,13 @@ public:
|
||||
virtual bool canFilterImageGPU() const;
|
||||
|
||||
/**
|
||||
* Process this image filter on the GPU. texture is the source texture
|
||||
* for processing, and rect is the effect region to process. The
|
||||
* function must allocate a new texture of at least rect width/height
|
||||
* size, and return it to the caller. The default implementation returns
|
||||
* NULL.
|
||||
* 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.
|
||||
*/
|
||||
virtual GrTexture* filterImageGPU(Proxy*, GrTexture* texture, const SkRect& rect);
|
||||
virtual bool filterImageGPU(Proxy*, const SkBitmap& src, SkBitmap* result);
|
||||
|
||||
/**
|
||||
* Returns this image filter as a color filter if possible,
|
||||
|
@ -42,8 +42,7 @@ protected:
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; }
|
||||
virtual GrTexture* filterImageGPU(Proxy* proxy, GrTexture* src,
|
||||
const SkRect& rect) SK_OVERRIDE;
|
||||
virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) SK_OVERRIDE;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
@ -33,7 +33,7 @@ public:
|
||||
SkIPoint* offset) SK_OVERRIDE;
|
||||
#if SK_SUPPORT_GPU
|
||||
virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; }
|
||||
virtual GrTexture* filterImageGPU(Proxy* proxy, GrTexture* src, const SkRect& rect) SK_OVERRIDE;
|
||||
virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) SK_OVERRIDE;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
@ -25,7 +25,7 @@ protected:
|
||||
SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
|
||||
|
||||
bool canFilterImageGPU() const SK_OVERRIDE { return true; }
|
||||
virtual GrTexture* filterImageGPU(Proxy* proxy, GrTexture* src, const SkRect& rect) SK_OVERRIDE;
|
||||
virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkSize fSigma;
|
||||
|
@ -35,7 +35,7 @@ public:
|
||||
SkIPoint* offset) SK_OVERRIDE;
|
||||
#if SK_SUPPORT_GPU
|
||||
virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; }
|
||||
virtual GrTexture* filterImageGPU(Proxy* proxy, GrTexture* src, const SkRect& rect) SK_OVERRIDE;
|
||||
virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) SK_OVERRIDE;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
36
include/effects/SkImageFilterUtils.h
Normal file
36
include/effects/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
|
@ -38,8 +38,7 @@ public:
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
|
||||
#if SK_SUPPORT_GPU
|
||||
virtual GrTexture* filterImageGPU(Proxy* proxy, GrTexture* src,
|
||||
const SkRect& rect) SK_OVERRIDE;
|
||||
virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) SK_OVERRIDE;
|
||||
#endif
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDilateImageFilter)
|
||||
@ -59,8 +58,7 @@ public:
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
|
||||
#if SK_SUPPORT_GPU
|
||||
virtual GrTexture* filterImageGPU(Proxy* proxy, GrTexture* src,
|
||||
const SkRect& rect) SK_OVERRIDE;
|
||||
virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) SK_OVERRIDE;
|
||||
#endif
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkErodeImageFilter)
|
||||
|
@ -29,12 +29,6 @@ protected:
|
||||
SkBitmap getInputResult(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkIPoint* offset);
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
// Recurses on input (if non-NULL), and returns the processed result as
|
||||
// a texture, otherwise returns src.
|
||||
GrTexture* getInputResultAsTexture(Proxy* proxy, GrTexture* src, const SkRect& rect);
|
||||
#endif
|
||||
|
||||
SkImageFilter* input() const { return getInput(0); }
|
||||
private:
|
||||
typedef SkImageFilter INHERITED;
|
||||
|
@ -107,8 +107,9 @@ bool SkImageFilter::canFilterImageGPU() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
GrTexture* SkImageFilter::filterImageGPU(Proxy* proxy, GrTexture* texture, const SkRect& rect) {
|
||||
return NULL;
|
||||
bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
|
||||
SkASSERT(false); // Should never be called, since canFilterImageGPU() returned false.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "GrTBackendEffectFactory.h"
|
||||
#include "GrContext.h"
|
||||
#include "GrTexture.h"
|
||||
#include "SkImageFilterUtils.h"
|
||||
#endif
|
||||
|
||||
SkBicubicImageFilter::SkBicubicImageFilter(const SkSize& scale, const SkScalar coefficients[16], SkImageFilter* input)
|
||||
@ -331,28 +332,35 @@ GrEffectRef* GrBicubicEffect::TestCreate(SkRandom* random,
|
||||
return GrBicubicEffect::Create(textures[texIdx], coefficients);
|
||||
}
|
||||
|
||||
GrTexture* SkBicubicImageFilter::filterImageGPU(Proxy* proxy, GrTexture* src, const SkRect& rect) {
|
||||
SkAutoTUnref<GrTexture> srcTexture(this->getInputResultAsTexture(proxy, src, rect));
|
||||
bool SkBicubicImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
|
||||
SkBitmap srcBM;
|
||||
if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &srcBM)) {
|
||||
return false;
|
||||
}
|
||||
GrTexture* srcTexture = (GrTexture*) srcBM.getTexture();
|
||||
GrContext* context = srcTexture->getContext();
|
||||
|
||||
SkRect dstRect = SkRect::MakeWH(rect.width() * fScale.fWidth,
|
||||
rect.height() * fScale.fHeight);
|
||||
SkRect dstRect = SkRect::MakeWH(srcBM.width() * fScale.fWidth,
|
||||
srcBM.height() * fScale.fHeight);
|
||||
|
||||
GrTextureDesc desc;
|
||||
desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
|
||||
desc.fWidth = SkScalarCeilToInt(dstRect.width());
|
||||
desc.fHeight = SkScalarCeilToInt(dstRect.height());
|
||||
desc.fConfig = kRGBA_8888_GrPixelConfig;
|
||||
desc.fConfig = kSkia8888_GrPixelConfig;
|
||||
|
||||
GrAutoScratchTexture ast(context, desc);
|
||||
if (!ast.texture()) {
|
||||
return NULL;
|
||||
SkAutoTUnref<GrTexture> dst(ast.detach());
|
||||
if (!dst) {
|
||||
return false;
|
||||
}
|
||||
GrContext::AutoRenderTarget art(context, ast.texture()->asRenderTarget());
|
||||
GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
|
||||
GrPaint paint;
|
||||
paint.colorStage(0)->setEffect(GrBicubicEffect::Create(srcTexture, fCoefficients))->unref();
|
||||
context->drawRectToRect(paint, dstRect, rect);
|
||||
return ast.detach();
|
||||
SkRect srcRect;
|
||||
srcBM.getBounds(&srcRect);
|
||||
context->drawRectToRect(paint, dstRect, srcRect);
|
||||
return SkImageFilterUtils::WrapTexture(dst, desc.fWidth, desc.fHeight, result);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -10,12 +10,11 @@
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "SkGr.h"
|
||||
#include "SkGrPixelRef.h"
|
||||
#include "GrContext.h"
|
||||
#include "gl/GrGLEffect.h"
|
||||
#include "gl/GrGLEffectMatrix.h"
|
||||
#include "effects/GrSingleTextureEffect.h"
|
||||
#include "GrTBackendEffectFactory.h"
|
||||
#include "SkImageFilterUtils.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
@ -171,64 +170,37 @@ private:
|
||||
typedef GrEffect INHERITED;
|
||||
};
|
||||
|
||||
// FIXME: This should be refactored with SkSingleInputImageFilter's version.
|
||||
static GrTexture* getInputResultAsTexture(SkImageFilter::Proxy* proxy,
|
||||
SkImageFilter* input,
|
||||
GrTexture* src,
|
||||
const SkRect& rect) {
|
||||
GrTexture* resultTex;
|
||||
if (!input) {
|
||||
resultTex = src;
|
||||
} else if (input->canFilterImageGPU()) {
|
||||
// filterImageGPU() already refs the result, so just return it here.
|
||||
return input->filterImageGPU(proxy, 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 (input->filterImage(proxy, srcBitmap, SkMatrix(), &result, &offset)) {
|
||||
if (result.getTexture()) {
|
||||
resultTex = (GrTexture*) result.getTexture();
|
||||
} else {
|
||||
resultTex = GrLockAndRefCachedBitmapTexture(src->getContext(), result, NULL);
|
||||
SkSafeRef(resultTex); // for the caller
|
||||
GrUnlockAndUnrefCachedBitmapTexture(resultTex);
|
||||
return resultTex;
|
||||
}
|
||||
} else {
|
||||
resultTex = src;
|
||||
}
|
||||
bool SkBlendImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
|
||||
SkBitmap backgroundBM;
|
||||
if (!SkImageFilterUtils::GetInputResultGPU(getBackgroundInput(), proxy, src, &backgroundBM)) {
|
||||
return false;
|
||||
}
|
||||
SkSafeRef(resultTex);
|
||||
return resultTex;
|
||||
}
|
||||
|
||||
GrTexture* SkBlendImageFilter::filterImageGPU(Proxy* proxy, GrTexture* src, const SkRect& rect) {
|
||||
SkAutoTUnref<GrTexture> background(getInputResultAsTexture(proxy, getBackgroundInput(), src, rect));
|
||||
SkAutoTUnref<GrTexture> foreground(getInputResultAsTexture(proxy, getForegroundInput(), src, rect));
|
||||
GrContext* context = src->getContext();
|
||||
GrTexture* background = (GrTexture*) backgroundBM.getTexture();
|
||||
SkBitmap foregroundBM;
|
||||
if (!SkImageFilterUtils::GetInputResultGPU(getForegroundInput(), proxy, src, &foregroundBM)) {
|
||||
return false;
|
||||
}
|
||||
GrTexture* foreground = (GrTexture*) foregroundBM.getTexture();
|
||||
GrContext* context = foreground->getContext();
|
||||
|
||||
GrTextureDesc desc;
|
||||
desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
|
||||
desc.fWidth = SkScalarCeilToInt(rect.width());
|
||||
desc.fHeight = SkScalarCeilToInt(rect.height());
|
||||
desc.fConfig = kRGBA_8888_GrPixelConfig;
|
||||
desc.fWidth = src.width();
|
||||
desc.fHeight = src.height();
|
||||
desc.fConfig = kSkia8888_GrPixelConfig;
|
||||
|
||||
GrAutoScratchTexture ast(context, desc);
|
||||
GrTexture* dst = ast.detach();
|
||||
|
||||
GrContext::AutoMatrix am;
|
||||
am.setIdentity(context);
|
||||
SkAutoTUnref<GrTexture> dst(ast.detach());
|
||||
|
||||
GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
|
||||
GrContext::AutoClip ac(context, rect);
|
||||
|
||||
GrPaint paint;
|
||||
paint.colorStage(0)->setEffect(
|
||||
GrBlendEffect::Create(fMode, foreground.get(), background.get()))->unref();
|
||||
context->drawRect(paint, rect);
|
||||
return dst;
|
||||
GrBlendEffect::Create(fMode, foreground, background))->unref();
|
||||
SkRect srcRect;
|
||||
src.getBounds(&srcRect);
|
||||
context->drawRect(paint, srcRect);
|
||||
return SkImageFilterUtils::WrapTexture(dst, src.width(), src.height(), result);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "SkFlattenableBuffers.h"
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrContext.h"
|
||||
#include "SkImageFilterUtils.h"
|
||||
#endif
|
||||
|
||||
SkBlurImageFilter::SkBlurImageFilter(SkFlattenableReadBuffer& buffer)
|
||||
@ -187,13 +188,20 @@ bool SkBlurImageFilter::onFilterImage(Proxy* proxy,
|
||||
return true;
|
||||
}
|
||||
|
||||
GrTexture* SkBlurImageFilter::filterImageGPU(Proxy* proxy, GrTexture* src, const SkRect& rect) {
|
||||
bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
|
||||
#if SK_SUPPORT_GPU
|
||||
SkAutoTUnref<GrTexture> input(this->getInputResultAsTexture(proxy, src, rect));
|
||||
return src->getContext()->gaussianBlur(input.get(), false, rect,
|
||||
fSigma.width(), fSigma.height());
|
||||
SkBitmap input;
|
||||
if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &input)) {
|
||||
return false;
|
||||
}
|
||||
GrTexture* source = (GrTexture*) input.getTexture();
|
||||
SkRect rect;
|
||||
src.getBounds(&rect);
|
||||
SkAutoTUnref<GrTexture> tex(source->getContext()->gaussianBlur(source, false, rect,
|
||||
fSigma.width(), fSigma.height()));
|
||||
return SkImageFilterUtils::WrapTexture(tex, src.width(), src.height(), result);
|
||||
#else
|
||||
SkDEBUGFAIL("Should not call in GPU-less build");
|
||||
return NULL;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
@ -10,11 +10,11 @@
|
||||
#include "SkUnPreMultiply.h"
|
||||
#include "SkColorPriv.h"
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "SkGr.h"
|
||||
#include "SkGrPixelRef.h"
|
||||
#include "GrContext.h"
|
||||
#include "gl/GrGLEffect.h"
|
||||
#include "gl/GrGLEffectMatrix.h"
|
||||
#include "GrTBackendEffectFactory.h"
|
||||
#include "SkImageFilterUtils.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
@ -275,70 +275,41 @@ private:
|
||||
typedef GrEffect INHERITED;
|
||||
};
|
||||
|
||||
// FIXME: This should be refactored with SkSingleInputImageFilter's version.
|
||||
static GrTexture* getInputResultAsTexture(SkImageFilter::Proxy* proxy,
|
||||
SkImageFilter* input,
|
||||
GrTexture* src,
|
||||
const SkRect& rect) {
|
||||
GrTexture* resultTex = NULL;
|
||||
if (!input) {
|
||||
resultTex = src;
|
||||
} else if (input->canFilterImageGPU()) {
|
||||
// filterImageGPU() already refs the result, so just return it here.
|
||||
return input->filterImageGPU(proxy, 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 (input->filterImage(proxy, srcBitmap, SkMatrix(), &result, &offset)) {
|
||||
if (result.getTexture()) {
|
||||
resultTex = (GrTexture*) result.getTexture();
|
||||
} else {
|
||||
resultTex = GrLockAndRefCachedBitmapTexture(src->getContext(), result, NULL);
|
||||
SkSafeRef(resultTex); // for the caller
|
||||
GrUnlockAndUnrefCachedBitmapTexture(resultTex);
|
||||
return resultTex;
|
||||
}
|
||||
} else {
|
||||
resultTex = src;
|
||||
}
|
||||
bool SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
|
||||
SkBitmap colorBM;
|
||||
if (!SkImageFilterUtils::GetInputResultGPU(getColorInput(), proxy, src, &colorBM)) {
|
||||
return false;
|
||||
}
|
||||
SkSafeRef(resultTex);
|
||||
return resultTex;
|
||||
}
|
||||
|
||||
GrTexture* SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, GrTexture* src,
|
||||
const SkRect& rect) {
|
||||
SkAutoTUnref<GrTexture> color(getInputResultAsTexture(proxy, getColorInput(), src, rect));
|
||||
SkAutoTUnref<GrTexture> displacement(getInputResultAsTexture(proxy, getDisplacementInput(),
|
||||
src, rect));
|
||||
GrContext* context = src->getContext();
|
||||
GrTexture* color = (GrTexture*) colorBM.getTexture();
|
||||
SkBitmap displacementBM;
|
||||
if (!SkImageFilterUtils::GetInputResultGPU(getDisplacementInput(), proxy, src, &displacementBM)) {
|
||||
return false;
|
||||
}
|
||||
GrTexture* displacement = (GrTexture*) displacementBM.getTexture();
|
||||
GrContext* context = color->getContext();
|
||||
|
||||
GrTextureDesc desc;
|
||||
desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
|
||||
desc.fWidth = SkScalarCeilToInt(rect.width());
|
||||
desc.fHeight = SkScalarCeilToInt(rect.height());
|
||||
desc.fConfig = kRGBA_8888_GrPixelConfig;
|
||||
desc.fWidth = src.width();
|
||||
desc.fHeight = src.height();
|
||||
desc.fConfig = kSkia8888_GrPixelConfig;
|
||||
|
||||
GrAutoScratchTexture ast(context, desc);
|
||||
GrTexture* dst = ast.detach();
|
||||
|
||||
GrContext::AutoMatrix am;
|
||||
am.setIdentity(context);
|
||||
SkAutoTUnref<GrTexture> dst(ast.detach());
|
||||
|
||||
GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
|
||||
GrContext::AutoClip ac(context, rect);
|
||||
|
||||
GrPaint paint;
|
||||
paint.colorStage(0)->setEffect(
|
||||
GrDisplacementMapEffect::Create(fXChannelSelector,
|
||||
fYChannelSelector,
|
||||
fScale,
|
||||
displacement.get(),
|
||||
color.get()))->unref();
|
||||
context->drawRect(paint, rect);
|
||||
return dst;
|
||||
displacement,
|
||||
color))->unref();
|
||||
SkRect srcRect;
|
||||
src.getBounds(&srcRect);
|
||||
context->drawRect(paint, srcRect);
|
||||
return SkImageFilterUtils::WrapTexture(dst, src.width(), src.height(), result);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
45
src/effects/SkImageFilterUtils.cpp
Normal file
45
src/effects/SkImageFilterUtils.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrTexture.h"
|
||||
#include "SkImageFilterUtils.h"
|
||||
#include "SkBitmap.h"
|
||||
#include "SkMatrix.h"
|
||||
#include "SkGrPixelRef.h"
|
||||
#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;
|
||||
}
|
||||
|
||||
bool SkImageFilterUtils::GetInputResultGPU(SkImageFilter* filter, SkImageFilter::Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
|
||||
if (!filter) {
|
||||
*result = src;
|
||||
return true;
|
||||
} else if (filter->canFilterImageGPU()) {
|
||||
return filter->filterImageGPU(proxy, src, result);
|
||||
} else {
|
||||
SkIPoint offset;
|
||||
if (filter->filterImage(proxy, src, SkMatrix(), result, &offset)) {
|
||||
if (!result->getTexture()) {
|
||||
GrContext* context = ((GrTexture *) src.getTexture())->getContext();
|
||||
GrTexture* resultTex = GrLockAndRefCachedBitmapTexture(context,
|
||||
*result, NULL);
|
||||
result->setPixelRef(new SkGrPixelRef(resultTex))->unref();
|
||||
GrUnlockAndUnrefCachedBitmapTexture(resultTex);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -17,6 +17,7 @@
|
||||
#include "gl/GrGLEffect.h"
|
||||
#include "gl/GrGLEffectMatrix.h"
|
||||
#include "effects/Gr1DKernelEffect.h"
|
||||
#include "SkImageFilterUtils.h"
|
||||
#endif
|
||||
|
||||
SkMorphologyImageFilter::SkMorphologyImageFilter(SkFlattenableReadBuffer& buffer)
|
||||
@ -275,7 +276,7 @@ private:
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class GrGLMorphologyEffect : public GrGLEffect {
|
||||
class GrGLMorphologyEffect : public GrGLEffect {
|
||||
public:
|
||||
GrGLMorphologyEffect (const GrBackendEffectFactory&, const GrEffectRef&);
|
||||
|
||||
@ -436,7 +437,7 @@ namespace {
|
||||
|
||||
void apply_morphology_pass(GrContext* context,
|
||||
GrTexture* texture,
|
||||
const SkRect& rect,
|
||||
const SkIRect& rect,
|
||||
int radius,
|
||||
GrMorphologyEffect::MorphologyType morphType,
|
||||
Gr1DKernelEffect::Direction direction) {
|
||||
@ -445,11 +446,11 @@ void apply_morphology_pass(GrContext* context,
|
||||
direction,
|
||||
radius,
|
||||
morphType))->unref();
|
||||
context->drawRect(paint, rect);
|
||||
context->drawRect(paint, SkRect::MakeFromIRect(rect));
|
||||
}
|
||||
|
||||
GrTexture* apply_morphology(GrTexture* srcTexture,
|
||||
const GrRect& rect,
|
||||
const SkIRect& rect,
|
||||
GrMorphologyEffect::MorphologyType morphType,
|
||||
SkISize radius) {
|
||||
GrContext* context = srcTexture->getContext();
|
||||
@ -463,20 +464,17 @@ GrTexture* apply_morphology(GrTexture* srcTexture,
|
||||
|
||||
GrTextureDesc desc;
|
||||
desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
|
||||
desc.fWidth = SkScalarCeilToInt(rect.width());
|
||||
desc.fHeight = SkScalarCeilToInt(rect.height());
|
||||
desc.fConfig = kRGBA_8888_GrPixelConfig;
|
||||
desc.fWidth = rect.width();
|
||||
desc.fHeight = rect.height();
|
||||
desc.fConfig = kSkia8888_GrPixelConfig;
|
||||
|
||||
if (radius.fWidth > 0) {
|
||||
GrAutoScratchTexture ast(context, desc);
|
||||
GrContext::AutoRenderTarget art(context, ast.texture()->asRenderTarget());
|
||||
apply_morphology_pass(context, srcTexture, rect, radius.fWidth,
|
||||
morphType, Gr1DKernelEffect::kX_Direction);
|
||||
SkIRect clearRect = SkIRect::MakeXYWH(
|
||||
SkScalarFloorToInt(rect.fLeft),
|
||||
SkScalarFloorToInt(rect.fBottom),
|
||||
SkScalarFloorToInt(rect.width()),
|
||||
radius.fHeight);
|
||||
SkIRect clearRect = SkIRect::MakeXYWH(rect.fLeft, rect.fBottom,
|
||||
rect.width(), radius.fHeight);
|
||||
context->clear(&clearRect, 0x0);
|
||||
srcTexture->unref();
|
||||
srcTexture = ast.detach();
|
||||
@ -494,14 +492,30 @@ GrTexture* apply_morphology(GrTexture* srcTexture,
|
||||
|
||||
};
|
||||
|
||||
GrTexture* SkDilateImageFilter::filterImageGPU(Proxy* proxy, GrTexture* src, const SkRect& rect) {
|
||||
SkAutoTUnref<GrTexture> input(this->getInputResultAsTexture(proxy, src, rect));
|
||||
return apply_morphology(input, rect, GrMorphologyEffect::kDilate_MorphologyType, radius());
|
||||
bool SkDilateImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
|
||||
SkBitmap inputBM;
|
||||
if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &inputBM)) {
|
||||
return false;
|
||||
}
|
||||
GrTexture* input = (GrTexture*) inputBM.getTexture();
|
||||
SkIRect bounds;
|
||||
src.getBounds(&bounds);
|
||||
SkAutoTUnref<GrTexture> resultTex(apply_morphology(input, bounds,
|
||||
GrMorphologyEffect::kDilate_MorphologyType, radius()));
|
||||
return SkImageFilterUtils::WrapTexture(resultTex, src.width(), src.height(), result);
|
||||
}
|
||||
|
||||
GrTexture* SkErodeImageFilter::filterImageGPU(Proxy* proxy, GrTexture* src, const SkRect& rect) {
|
||||
SkAutoTUnref<GrTexture> input(this->getInputResultAsTexture(proxy, src, rect));
|
||||
return apply_morphology(input, rect, GrMorphologyEffect::kErode_MorphologyType, radius());
|
||||
bool SkErodeImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
|
||||
SkBitmap inputBM;
|
||||
if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &inputBM)) {
|
||||
return false;
|
||||
}
|
||||
GrTexture* input = (GrTexture*) inputBM.getTexture();
|
||||
SkIRect bounds;
|
||||
src.getBounds(&bounds);
|
||||
SkAutoTUnref<GrTexture> resultTex(apply_morphology(input, bounds,
|
||||
GrMorphologyEffect::kErode_MorphologyType, radius()));
|
||||
return SkImageFilterUtils::WrapTexture(resultTex, src.width(), src.height(), result);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -9,11 +9,6 @@
|
||||
#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) : INHERITED(input) {
|
||||
}
|
||||
@ -35,38 +30,3 @@ SkBitmap SkSingleInputImageFilter::getInputResult(Proxy* proxy,
|
||||
SkIPoint* offset) {
|
||||
return this->INHERITED::getInputResult(0, proxy, src, ctm, offset);
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
// FIXME: generalize and move to base class
|
||||
GrTexture* SkSingleInputImageFilter::getInputResultAsTexture(Proxy* proxy,
|
||||
GrTexture* src,
|
||||
const SkRect& rect) {
|
||||
GrTexture* resultTex = NULL;
|
||||
SkImageFilter* input = getInput(0);
|
||||
if (!input) {
|
||||
resultTex = src;
|
||||
} else if (input->canFilterImageGPU()) {
|
||||
// filterImageGPU() already refs the result, so just return it here.
|
||||
return input->filterImageGPU(proxy, 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 (input->filterImage(proxy, srcBitmap, SkMatrix(), &result, &offset)) {
|
||||
if (result.getTexture()) {
|
||||
resultTex = (GrTexture*) result.getTexture();
|
||||
} else {
|
||||
resultTex = GrLockAndRefCachedBitmapTexture(src->getContext(), result, NULL);
|
||||
SkSafeRef(resultTex); // for the caller
|
||||
GrUnlockAndUnrefCachedBitmapTexture(resultTex);
|
||||
return resultTex;
|
||||
}
|
||||
} else {
|
||||
resultTex = src;
|
||||
}
|
||||
}
|
||||
SkSafeRef(resultTex);
|
||||
return resultTex;
|
||||
}
|
||||
#endif
|
||||
|
@ -1399,16 +1399,25 @@ void apply_effect(GrContext* context,
|
||||
|
||||
};
|
||||
|
||||
static GrTexture* filter_texture(SkDevice* device, GrContext* context,
|
||||
GrTexture* texture, SkImageFilter* filter,
|
||||
const GrRect& rect) {
|
||||
static SkBitmap wrap_texture(GrTexture* texture) {
|
||||
SkBitmap result;
|
||||
bool dummy;
|
||||
SkBitmap::Config config = grConfig2skConfig(texture->config(), &dummy);
|
||||
result.setConfig(config, texture->width(), texture->height());
|
||||
result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (texture)))->unref();
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool filter_texture(SkDevice* device, GrContext* context,
|
||||
GrTexture* texture, SkImageFilter* filter,
|
||||
int w, int h, SkBitmap* result) {
|
||||
GrAssert(filter);
|
||||
SkDeviceImageFilterProxy proxy(device);
|
||||
|
||||
GrTextureDesc desc;
|
||||
desc.fFlags = kRenderTarget_GrTextureFlagBit,
|
||||
desc.fWidth = SkScalarCeilToInt(rect.width());
|
||||
desc.fHeight = SkScalarCeilToInt(rect.height());
|
||||
desc.fWidth = w;
|
||||
desc.fHeight = h;
|
||||
desc.fConfig = kRGBA_8888_GrPixelConfig;
|
||||
GrEffectRef* effect;
|
||||
|
||||
@ -1416,14 +1425,18 @@ static GrTexture* 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);
|
||||
texture = filter->filterImageGPU(&proxy, texture, rect);
|
||||
return filter->filterImageGPU(&proxy, wrap_texture(texture), result);
|
||||
} else if (filter->asNewEffect(&effect, texture)) {
|
||||
GrAutoScratchTexture dst(context, desc);
|
||||
apply_effect(context, texture, dst.texture(), rect, effect);
|
||||
texture = dst.detach();
|
||||
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;
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
|
||||
void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
|
||||
@ -1455,13 +1468,13 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
|
||||
|
||||
SkImageFilter* filter = paint.getImageFilter();
|
||||
if (NULL != filter) {
|
||||
GrTexture* filteredTexture = filter_texture(this, fContext, texture, filter,
|
||||
GrRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h)));
|
||||
if (filteredTexture) {
|
||||
SkBitmap filterBitmap;
|
||||
if (filter_texture(this, fContext, texture, filter, w, h, &filterBitmap)) {
|
||||
grPaint.colorStage(kBitmapTextureIdx)->setEffect(
|
||||
GrSimpleTextureEffect::Create(filteredTexture, SkMatrix::I()))->unref();
|
||||
texture = filteredTexture;
|
||||
filteredTexture->unref();
|
||||
GrSimpleTextureEffect::Create((GrTexture*) filterBitmap.getTexture(), SkMatrix::I()))->unref();
|
||||
texture = (GrTexture*) filterBitmap.getTexture();
|
||||
w = filterBitmap.width();
|
||||
h = filterBitmap.height();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1526,23 +1539,22 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* device,
|
||||
GrTexture* devTex = (*grPaint.getColorStage(kBitmapTextureIdx).getEffect())->texture(0);
|
||||
SkASSERT(NULL != devTex);
|
||||
|
||||
SkImageFilter* filter = paint.getImageFilter();
|
||||
if (NULL != filter) {
|
||||
GrRect rect = GrRect::MakeWH(SkIntToScalar(devTex->width()),
|
||||
SkIntToScalar(devTex->height()));
|
||||
GrTexture* filteredTexture = filter_texture(this, fContext, devTex, filter, rect);
|
||||
if (filteredTexture) {
|
||||
grPaint.colorStage(kBitmapTextureIdx)->setEffect(
|
||||
GrSimpleTextureEffect::Create(filteredTexture, SkMatrix::I()))->unref();
|
||||
devTex = filteredTexture;
|
||||
filteredTexture->unref();
|
||||
}
|
||||
}
|
||||
|
||||
const SkBitmap& bm = dev->accessBitmap(false);
|
||||
int w = bm.width();
|
||||
int h = bm.height();
|
||||
|
||||
SkImageFilter* filter = paint.getImageFilter();
|
||||
if (NULL != filter) {
|
||||
SkBitmap filterBitmap;
|
||||
if (filter_texture(this, fContext, devTex, filter, w, h, &filterBitmap)) {
|
||||
grPaint.colorStage(kBitmapTextureIdx)->setEffect(
|
||||
GrSimpleTextureEffect::Create((GrTexture*) filterBitmap.getTexture(), SkMatrix::I()))->unref();
|
||||
devTex = (GrTexture*) filterBitmap.getTexture();
|
||||
w = filterBitmap.width();
|
||||
h = filterBitmap.height();
|
||||
}
|
||||
}
|
||||
|
||||
GrRect dstRect = GrRect::MakeXYWH(SkIntToScalar(x),
|
||||
SkIntToScalar(y),
|
||||
SkIntToScalar(w),
|
||||
@ -1584,16 +1596,7 @@ bool SkGpuDevice::filterImage(SkImageFilter* filter, const SkBitmap& src,
|
||||
// must be pushed upstack.
|
||||
SkAutoCachedTexture act(this, src, NULL, &texture);
|
||||
|
||||
result->setConfig(src.config(), src.width(), src.height());
|
||||
GrRect rect = GrRect::MakeWH(SkIntToScalar(src.width()),
|
||||
SkIntToScalar(src.height()));
|
||||
GrTexture* resultTexture = filter_texture(this, fContext, texture, filter, rect);
|
||||
if (resultTexture) {
|
||||
result->setPixelRef(SkNEW_ARGS(SkGrTexturePixelRef,
|
||||
(resultTexture)))->unref();
|
||||
resultTexture->unref();
|
||||
}
|
||||
return true;
|
||||
return filter_texture(this, fContext, texture, filter, src.width(), src.height(), result);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
Loading…
Reference in New Issue
Block a user