Move gaussianBlur functionality to src\effects

https://codereview.chromium.org/18771004/



git-svn-id: http://skia.googlecode.com/svn/trunk@10080 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
robertphillips@google.com 2013-07-15 15:06:54 +00:00
parent 3dd2784cb7
commit 736dd031f1
7 changed files with 239 additions and 198 deletions

View File

@ -31,6 +31,8 @@
'<(skia_src_path)/effects/SkEmbossMask.h',
'<(skia_src_path)/effects/SkEmbossMask_Table.h',
'<(skia_src_path)/effects/SkEmbossMaskFilter.cpp',
'<(skia_src_path)/effects/SkGpuBlurUtils.h',
'<(skia_src_path)/effects/SkGpuBlurUtils.cpp',
'<(skia_src_path)/effects/SkKernel33MaskFilter.cpp',
'<(skia_src_path)/effects/SkLayerDrawLooper.cpp',
'<(skia_src_path)/effects/SkLayerRasterizer.cpp',

View File

@ -619,22 +619,6 @@ public:
*/
void resolveRenderTarget(GrRenderTarget* target);
/**
* Applies a 2D Gaussian blur to a given texture.
* @param srcTexture The source texture to be blurred.
* @param canClobberSrc If true, srcTexture may be overwritten, and
* may be returned as the result.
* @param rect The destination rectangle.
* @param sigmaX The blur's standard deviation in X.
* @param sigmaY The blur's standard deviation in Y.
* @return the blurred texture, which may be srcTexture reffed, or a
* new texture. It is the caller's responsibility to unref this texture.
*/
GrTexture* gaussianBlur(GrTexture* srcTexture,
bool canClobberSrc,
const SkRect& rect,
float sigmaX, float sigmaY);
///////////////////////////////////////////////////////////////////////////
// Helpers

View File

@ -9,6 +9,7 @@
#include "SkBlurImageFilter.h"
#include "SkColorPriv.h"
#include "SkFlattenableBuffers.h"
#include "SkGpuBlurUtils.h"
#if SK_SUPPORT_GPU
#include "GrContext.h"
#include "SkImageFilterUtils.h"
@ -203,8 +204,9 @@ bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitm
GrTexture* source = input.getTexture();
SkRect rect;
src.getBounds(&rect);
SkAutoTUnref<GrTexture> tex(source->getContext()->gaussianBlur(source, false, rect,
fSigma.width(), fSigma.height()));
SkAutoTUnref<GrTexture> tex(SkGpuBlurUtils::GaussianBlur(source->getContext(),
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");

View File

@ -8,6 +8,7 @@
#include "SkBlurMaskFilter.h"
#include "SkBlurMask.h"
#include "SkGpuBlurUtils.h"
#include "SkFlattenableBuffers.h"
#include "SkMaskFilter.h"
#include "SkRTConf.h"
@ -410,8 +411,8 @@ bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src,
// If we're doing a normal blur, we can clobber the pathTexture in the
// gaussianBlur. Otherwise, we need to save it for later compositing.
bool isNormalBlur = (SkBlurMaskFilter::kNormal_BlurStyle == fBlurStyle);
*result = context->gaussianBlur(src, isNormalBlur && canOverwriteSrc,
clipRect, sigma, sigma);
*result = SkGpuBlurUtils::GaussianBlur(context, src, isNormalBlur && canOverwriteSrc,
clipRect, sigma, sigma);
if (NULL == *result) {
return false;
}

View File

@ -0,0 +1,187 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkGpuBlurUtils.h"
#include "SkRect.h"
#if SK_SUPPORT_GPU
#include "effects/GrConvolutionEffect.h"
#include "GrContext.h"
#endif
namespace SkGpuBlurUtils {
#if SK_SUPPORT_GPU
#define MAX_BLUR_SIGMA 4.0f
static void scale_rect(SkRect* rect, float xScale, float yScale) {
rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale));
rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale));
rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale));
rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale));
}
static float adjust_sigma(float sigma, int *scaleFactor, int *radius) {
*scaleFactor = 1;
while (sigma > MAX_BLUR_SIGMA) {
*scaleFactor *= 2;
sigma *= 0.5f;
}
*radius = static_cast<int>(ceilf(sigma * 3.0f));
GrAssert(*radius <= GrConvolutionEffect::kMaxKernelRadius);
return sigma;
}
static void convolve_gaussian(GrContext* context,
GrTexture* texture,
const SkRect& rect,
float sigma,
int radius,
Gr1DKernelEffect::Direction direction) {
GrPaint paint;
SkAutoTUnref<GrEffectRef> conv(GrConvolutionEffect::CreateGaussian(texture,
direction,
radius,
sigma));
paint.addColorEffect(conv);
context->drawRect(paint, rect);
}
GrTexture* GaussianBlur(GrContext* context,
GrTexture* srcTexture,
bool canClobberSrc,
const SkRect& rect,
float sigmaX,
float sigmaY) {
GrAssert(NULL != context);
GrContext::AutoRenderTarget art(context);
GrContext::AutoMatrix am;
am.setIdentity(context);
SkIRect clearRect;
int scaleFactorX, radiusX;
int scaleFactorY, radiusY;
sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &radiusX);
sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &radiusY);
SkRect srcRect(rect);
scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
srcRect.roundOut();
scale_rect(&srcRect, static_cast<float>(scaleFactorX),
static_cast<float>(scaleFactorY));
GrContext::AutoClip acs(context, srcRect);
GrAssert(kBGRA_8888_GrPixelConfig == srcTexture->config() ||
kRGBA_8888_GrPixelConfig == srcTexture->config() ||
kAlpha_8_GrPixelConfig == srcTexture->config());
GrTextureDesc desc;
desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
desc.fWidth = SkScalarFloorToInt(srcRect.width());
desc.fHeight = SkScalarFloorToInt(srcRect.height());
desc.fConfig = srcTexture->config();
GrAutoScratchTexture temp1, temp2;
GrTexture* dstTexture = temp1.set(context, desc);
GrTexture* tempTexture = canClobberSrc ? srcTexture : temp2.set(context, desc);
if (NULL == dstTexture || NULL == tempTexture) {
return NULL;
}
for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
GrPaint paint;
SkMatrix matrix;
matrix.setIDiv(srcTexture->width(), srcTexture->height());
context->setRenderTarget(dstTexture->asRenderTarget());
SkRect dstRect(srcRect);
scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
i < scaleFactorY ? 0.5f : 1.0f);
GrTextureParams params(SkShader::kClamp_TileMode, true);
paint.addColorTextureEffect(srcTexture, matrix, params);
context->drawRectToRect(paint, dstRect, srcRect);
srcRect = dstRect;
srcTexture = dstTexture;
SkTSwap(dstTexture, tempTexture);
}
SkIRect srcIRect;
srcRect.roundOut(&srcIRect);
if (sigmaX > 0.0f) {
if (scaleFactorX > 1) {
// Clear out a radius to the right of the srcRect to prevent the
// X convolution from reading garbage.
clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
radiusX, srcIRect.height());
context->clear(&clearRect, 0x0);
}
context->setRenderTarget(dstTexture->asRenderTarget());
convolve_gaussian(context, srcTexture, srcRect, sigmaX, radiusX,
Gr1DKernelEffect::kX_Direction);
srcTexture = dstTexture;
SkTSwap(dstTexture, tempTexture);
}
if (sigmaY > 0.0f) {
if (scaleFactorY > 1 || sigmaX > 0.0f) {
// Clear out a radius below the srcRect to prevent the Y
// convolution from reading garbage.
clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
srcIRect.width(), radiusY);
context->clear(&clearRect, 0x0);
}
context->setRenderTarget(dstTexture->asRenderTarget());
convolve_gaussian(context, srcTexture, srcRect, sigmaY, radiusY,
Gr1DKernelEffect::kY_Direction);
srcTexture = dstTexture;
SkTSwap(dstTexture, tempTexture);
}
if (scaleFactorX > 1 || scaleFactorY > 1) {
// Clear one pixel to the right and below, to accommodate bilinear
// upsampling.
clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
srcIRect.width() + 1, 1);
context->clear(&clearRect, 0x0);
clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
1, srcIRect.height());
context->clear(&clearRect, 0x0);
SkMatrix matrix;
matrix.setIDiv(srcTexture->width(), srcTexture->height());
context->setRenderTarget(dstTexture->asRenderTarget());
GrPaint paint;
// FIXME: this should be mitchell, not bilinear.
GrTextureParams params(SkShader::kClamp_TileMode, true);
paint.addColorTextureEffect(srcTexture, matrix, params);
SkRect dstRect(srcRect);
scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY);
context->drawRectToRect(paint, dstRect, srcRect);
srcRect = dstRect;
srcTexture = dstTexture;
SkTSwap(dstTexture, tempTexture);
}
if (srcTexture == temp1.texture()) {
return temp1.detach();
} else if (srcTexture == temp2.texture()) {
return temp2.detach();
} else {
srcTexture->ref();
return srcTexture;
}
}
#endif
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkGpuBlurUtils_DEFINED
#define SkGpuBlurUtils_DEFINED
#if SK_SUPPORT_GPU
class GrTexture;
class GrContext;
#endif
struct SkRect;
namespace SkGpuBlurUtils {
#if SK_SUPPORT_GPU
/**
* Applies a 2D Gaussian blur to a given texture.
* @param context The GPU context
* @param srcTexture The source texture to be blurred.
* @param canClobberSrc If true, srcTexture may be overwritten, and
* may be returned as the result.
* @param rect The destination rectangle.
* @param sigmaX The blur's standard deviation in X.
* @param sigmaY The blur's standard deviation in Y.
* @return the blurred texture, which may be srcTexture reffed, or a
* new texture. It is the caller's responsibility to unref this texture.
*/
GrTexture* GaussianBlur(GrContext* context,
GrTexture* srcTexture,
bool canClobberSrc,
const SkRect& rect,
float sigmaX,
float sigmaY);
#endif
};
#endif

View File

@ -9,7 +9,6 @@
#include "GrContext.h"
#include "effects/GrConvolutionEffect.h"
#include "effects/GrSingleTextureEffect.h"
#include "effects/GrConfigConversionEffect.h"
@ -42,8 +41,6 @@ SK_CONF_DECLARE(bool, c_Defer, "gpu.deferContext", true,
#define BUFFERED_DRAW (c_Defer ? kYes_BufferedDraw : kNo_BufferedDraw)
#define MAX_BLUR_SIGMA 4.0f
// When we're using coverage AA but the blend is incompatible (given gpu
// limitations) should we disable AA or draw wrong?
#define DISABLE_COVERAGE_AA_FOR_BLEND 1
@ -230,48 +227,6 @@ size_t GrContext::getGpuTextureCacheBytes() const {
////////////////////////////////////////////////////////////////////////////////
namespace {
void scale_rect(SkRect* rect, float xScale, float yScale) {
rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale));
rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale));
rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale));
rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale));
}
float adjust_sigma(float sigma, int *scaleFactor, int *radius) {
*scaleFactor = 1;
while (sigma > MAX_BLUR_SIGMA) {
*scaleFactor *= 2;
sigma *= 0.5f;
}
*radius = static_cast<int>(ceilf(sigma * 3.0f));
GrAssert(*radius <= GrConvolutionEffect::kMaxKernelRadius);
return sigma;
}
void convolve_gaussian(GrDrawTarget* target,
GrTexture* texture,
const SkRect& rect,
float sigma,
int radius,
Gr1DKernelEffect::Direction direction) {
GrRenderTarget* rt = target->drawState()->getRenderTarget();
GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kReset_ASRInit);
GrDrawState* drawState = target->drawState();
drawState->setRenderTarget(rt);
SkAutoTUnref<GrEffectRef> conv(GrConvolutionEffect::CreateGaussian(texture,
direction,
radius,
sigma));
drawState->addColorEffect(conv);
target->drawSimpleRect(rect, NULL);
}
}
////////////////////////////////////////////////////////////////////////////////
GrTexture* GrContext::findAndRefTexture(const GrTextureDesc& desc,
const GrCacheID& cacheID,
const GrTextureParams* params) {
@ -1724,139 +1679,6 @@ const GrEffectRef* GrContext::createUPMToPMEffect(GrTexture* texture,
}
}
GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
bool canClobberSrc,
const SkRect& rect,
float sigmaX, float sigmaY) {
ASSERT_OWNED_RESOURCE(srcTexture);
AutoRenderTarget art(this);
AutoMatrix am;
am.setIdentity(this);
SkIRect clearRect;
int scaleFactorX, radiusX;
int scaleFactorY, radiusY;
sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &radiusX);
sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &radiusY);
SkRect srcRect(rect);
scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
srcRect.roundOut();
scale_rect(&srcRect, static_cast<float>(scaleFactorX),
static_cast<float>(scaleFactorY));
AutoClip acs(this, srcRect);
GrAssert(kBGRA_8888_GrPixelConfig == srcTexture->config() ||
kRGBA_8888_GrPixelConfig == srcTexture->config() ||
kAlpha_8_GrPixelConfig == srcTexture->config());
GrTextureDesc desc;
desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
desc.fWidth = SkScalarFloorToInt(srcRect.width());
desc.fHeight = SkScalarFloorToInt(srcRect.height());
desc.fConfig = srcTexture->config();
GrAutoScratchTexture temp1, temp2;
GrTexture* dstTexture = temp1.set(this, desc);
GrTexture* tempTexture = canClobberSrc ? srcTexture : temp2.set(this, desc);
if (NULL == dstTexture || NULL == tempTexture) {
return NULL;
}
for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
GrPaint paint;
SkMatrix matrix;
matrix.setIDiv(srcTexture->width(), srcTexture->height());
this->setRenderTarget(dstTexture->asRenderTarget());
SkRect dstRect(srcRect);
scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
i < scaleFactorY ? 0.5f : 1.0f);
GrTextureParams params(SkShader::kClamp_TileMode, true);
paint.addColorTextureEffect(srcTexture, matrix, params);
this->drawRectToRect(paint, dstRect, srcRect);
srcRect = dstRect;
srcTexture = dstTexture;
SkTSwap(dstTexture, tempTexture);
}
SkIRect srcIRect;
srcRect.roundOut(&srcIRect);
if (sigmaX > 0.0f) {
if (scaleFactorX > 1) {
// Clear out a radius to the right of the srcRect to prevent the
// X convolution from reading garbage.
clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
radiusX, srcIRect.height());
this->clear(&clearRect, 0x0);
}
GrPaint paint;
this->setRenderTarget(dstTexture->asRenderTarget());
AutoRestoreEffects are;
GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are);
convolve_gaussian(target, srcTexture, srcRect, sigmaX, radiusX,
Gr1DKernelEffect::kX_Direction);
srcTexture = dstTexture;
SkTSwap(dstTexture, tempTexture);
}
if (sigmaY > 0.0f) {
if (scaleFactorY > 1 || sigmaX > 0.0f) {
// Clear out a radius below the srcRect to prevent the Y
// convolution from reading garbage.
clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
srcIRect.width(), radiusY);
this->clear(&clearRect, 0x0);
}
this->setRenderTarget(dstTexture->asRenderTarget());
GrPaint paint;
AutoRestoreEffects are;
GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are);
convolve_gaussian(target, srcTexture, srcRect, sigmaY, radiusY,
Gr1DKernelEffect::kY_Direction);
srcTexture = dstTexture;
SkTSwap(dstTexture, tempTexture);
}
if (scaleFactorX > 1 || scaleFactorY > 1) {
// Clear one pixel to the right and below, to accommodate bilinear
// upsampling.
clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
srcIRect.width() + 1, 1);
this->clear(&clearRect, 0x0);
clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
1, srcIRect.height());
this->clear(&clearRect, 0x0);
SkMatrix matrix;
matrix.setIDiv(srcTexture->width(), srcTexture->height());
this->setRenderTarget(dstTexture->asRenderTarget());
GrPaint paint;
// FIXME: This should be mitchell, not bilinear.
GrTextureParams params(SkShader::kClamp_TileMode, true);
paint.addColorTextureEffect(srcTexture, matrix, params);
SkRect dstRect(srcRect);
scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY);
this->drawRectToRect(paint, dstRect, srcRect);
srcRect = dstRect;
srcTexture = dstTexture;
SkTSwap(dstTexture, tempTexture);
}
if (srcTexture == temp1.texture()) {
return temp1.detach();
} else if (srcTexture == temp2.texture()) {
return temp2.detach();
} else {
srcTexture->ref();
return srcTexture;
}
}
///////////////////////////////////////////////////////////////////////////////
#if GR_CACHE_STATS
void GrContext::printCacheStats() const {