aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkGpuBlurUtils.cpp
diff options
context:
space:
mode:
authorGravatar wutao <wutao@google.com>2017-06-30 10:44:45 -0700
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-06-30 18:11:16 +0000
commit039a7c70cea29aa40c4fb880b0d6bb523d449568 (patch)
treeb62a5274d4b1cbcaac89ad5fb8bf86118c7caa87 /src/core/SkGpuBlurUtils.cpp
parent981deec8b2928f07e3899849bed31bfbb8c19b9b (diff)
Added new edge handling mode (clamp and repeat) to Gaussian blur filter.
Gaussian blur filter will interpolate value by using out of bounds coords, which is 0. This makes it appears darker near the bounds in the blurred images. There are two issues: 1) when downsampling and upsampling, we should use GrTextureDomainEffect kClamp_Mode to clamp the texture coords to the bounds; 2) during Gaussian blur, we need to clamp to texture bounds. BUG=622128 TEST=cc_unittests, GM image test & manual. Some test results can be found at: https://bugs.chromium.org/p/chromium/issues/detail?id=622128#c49 Change-Id: I9283da1d91efb0da94a991f2d372e9f62c288bdc Reviewed-on: https://skia-review.googlesource.com/20465 Commit-Queue: Robert Phillips <robertphillips@google.com> Reviewed-by: Stephen White <senorblanco@chromium.org> Reviewed-by: Robert Phillips <robertphillips@google.com> Reviewed-by: Mike Reed <reed@google.com>
Diffstat (limited to 'src/core/SkGpuBlurUtils.cpp')
-rw-r--r--src/core/SkGpuBlurUtils.cpp99
1 files changed, 60 insertions, 39 deletions
diff --git a/src/core/SkGpuBlurUtils.cpp b/src/core/SkGpuBlurUtils.cpp
index 40a6c24706..129a8fbfb7 100644
--- a/src/core/SkGpuBlurUtils.cpp
+++ b/src/core/SkGpuBlurUtils.cpp
@@ -74,13 +74,13 @@ static void convolve_gaussian_1d(GrRenderTargetContext* renderTargetContext,
Gr1DKernelEffect::Direction direction,
int radius,
float sigma,
- bool useBounds,
+ GrTextureDomain::Mode mode,
int bounds[2]) {
GrPaint paint;
paint.setGammaCorrect(renderTargetContext->isGammaCorrect());
sk_sp<GrFragmentProcessor> conv(GrGaussianConvolutionFragmentProcessor::Make(
- std::move(proxy), direction, radius, sigma, useBounds, bounds));
+ std::move(proxy), direction, radius, sigma, mode, bounds));
paint.addColorFragmentProcessor(std::move(conv));
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
SkMatrix localMatrix = SkMatrix::MakeTrans(-SkIntToScalar(srcOffset.x()),
@@ -98,19 +98,18 @@ static void convolve_gaussian_2d(GrRenderTargetContext* renderTargetContext,
int radiusY,
SkScalar sigmaX,
SkScalar sigmaY,
- const SkIRect* srcBounds) {
+ const SkIRect& srcBounds,
+ GrTextureDomain::Mode mode) {
SkMatrix localMatrix = SkMatrix::MakeTrans(-SkIntToScalar(srcOffset.x()),
-SkIntToScalar(srcOffset.y()));
SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1);
SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY);
GrPaint paint;
paint.setGammaCorrect(renderTargetContext->isGammaCorrect());
- SkIRect bounds = srcBounds ? *srcBounds : SkIRect::EmptyIRect();
sk_sp<GrFragmentProcessor> conv(GrMatrixConvolutionEffect::MakeGaussian(
- std::move(proxy), bounds, size, 1.0, 0.0, kernelOffset,
- srcBounds ? GrTextureDomain::kDecal_Mode : GrTextureDomain::kIgnore_Mode,
- true, sigmaX, sigmaY));
+ std::move(proxy), srcBounds, size, 1.0, 0.0, kernelOffset,
+ mode, true, sigmaX, sigmaY));
paint.addColorFragmentProcessor(std::move(conv));
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
renderTargetContext->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(),
@@ -124,21 +123,23 @@ static void convolve_gaussian(GrRenderTargetContext* renderTargetContext,
Gr1DKernelEffect::Direction direction,
int radius,
float sigma,
- const SkIRect* srcBounds,
- const SkIPoint& srcOffset) {
+ const SkIRect& srcBounds,
+ const SkIPoint& srcOffset,
+ GrTextureDomain::Mode mode) {
int bounds[2] = { 0, 0 };
SkIRect dstRect = SkIRect::MakeWH(srcRect.width(), srcRect.height());
- if (!srcBounds) {
+ if (GrTextureDomain::kIgnore_Mode == mode) {
convolve_gaussian_1d(renderTargetContext, clip, dstRect, srcOffset,
- std::move(proxy), direction, radius, sigma, false, bounds);
+ std::move(proxy), direction, radius, sigma,
+ GrTextureDomain::kIgnore_Mode, bounds);
return;
}
- SkIRect midRect = *srcBounds, leftRect, rightRect;
+ SkIRect midRect = srcBounds, leftRect, rightRect;
midRect.offset(srcOffset);
SkIRect topRect, bottomRect;
if (direction == Gr1DKernelEffect::kX_Direction) {
- bounds[0] = srcBounds->left();
- bounds[1] = srcBounds->right();
+ bounds[0] = srcBounds.left();
+ bounds[1] = srcBounds.right();
topRect = SkIRect::MakeLTRB(0, 0, dstRect.right(), midRect.top());
bottomRect = SkIRect::MakeLTRB(0, midRect.bottom(), dstRect.right(), dstRect.bottom());
midRect.inset(radius, 0);
@@ -148,8 +149,8 @@ static void convolve_gaussian(GrRenderTargetContext* renderTargetContext,
dstRect.fTop = midRect.top();
dstRect.fBottom = midRect.bottom();
} else {
- bounds[0] = srcBounds->top();
- bounds[1] = srcBounds->bottom();
+ bounds[0] = srcBounds.top();
+ bounds[1] = srcBounds.bottom();
topRect = SkIRect::MakeLTRB(0, 0, midRect.left(), dstRect.bottom());
bottomRect = SkIRect::MakeLTRB(midRect.right(), 0, dstRect.right(), dstRect.bottom());
midRect.inset(0, radius);
@@ -166,18 +167,20 @@ static void convolve_gaussian(GrRenderTargetContext* renderTargetContext,
if (!bottomRect.isEmpty()) {
renderTargetContext->clear(&bottomRect, 0, false);
}
+
if (midRect.isEmpty()) {
// Blur radius covers srcBounds; use bounds over entire draw
convolve_gaussian_1d(renderTargetContext, clip, dstRect, srcOffset,
- std::move(proxy), direction, radius, sigma, true, bounds);
+ std::move(proxy), direction, radius, sigma, mode, bounds);
} else {
// Draw right and left margins with bounds; middle without.
convolve_gaussian_1d(renderTargetContext, clip, leftRect, srcOffset,
- proxy, direction, radius, sigma, true, bounds);
+ proxy, direction, radius, sigma, mode, bounds);
convolve_gaussian_1d(renderTargetContext, clip, rightRect, srcOffset,
- proxy, direction, radius, sigma, true, bounds);
+ proxy, direction, radius, sigma, mode, bounds);
convolve_gaussian_1d(renderTargetContext, clip, midRect, srcOffset,
- std::move(proxy), direction, radius, sigma, false, bounds);
+ std::move(proxy), direction, radius, sigma,
+ GrTextureDomain::kIgnore_Mode, bounds);
}
}
@@ -187,12 +190,12 @@ sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context,
sk_sp<GrTextureProxy> srcProxy,
sk_sp<SkColorSpace> colorSpace,
const SkIRect& dstBounds,
- const SkIRect* srcBounds,
+ const SkIRect& srcBounds,
float sigmaX,
float sigmaY,
+ GrTextureDomain::Mode mode,
SkBackingFit fit) {
SkASSERT(context);
-
SkIRect clearRect;
int scaleFactorX, radiusX;
int scaleFactorY, radiusY;
@@ -205,12 +208,11 @@ sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context,
SkIRect localDstBounds = SkIRect::MakeWH(dstBounds.width(), dstBounds.height());
SkIRect localSrcBounds;
SkIRect srcRect;
- if (srcBounds) {
- srcRect = localSrcBounds = *srcBounds;
- srcRect.offset(srcOffset);
- srcBounds = &localSrcBounds;
- } else {
+ if (GrTextureDomain::kIgnore_Mode == mode) {
srcRect = localDstBounds;
+ } else {
+ srcRect = localSrcBounds = srcBounds;
+ srcRect.offset(srcOffset);
}
scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
@@ -241,11 +243,12 @@ sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context,
// We shouldn't be scaling because this is a small size blur
SkASSERT((1 == scaleFactorX) && (1 == scaleFactorY));
- convolve_gaussian_2d(dstRenderTargetContext.get(), clip, localDstBounds, srcOffset,
- std::move(srcProxy), radiusX, radiusY, sigmaX, sigmaY, srcBounds);
+ convolve_gaussian_2d(dstRenderTargetContext.get(),
+ clip, localDstBounds, srcOffset, std::move(srcProxy),
+ radiusX, radiusY, sigmaX, sigmaY, srcBounds, mode);
return dstRenderTargetContext;
- }
+ }
sk_sp<GrRenderTargetContext> tmpRenderTargetContext(context->makeDeferredRenderTargetContext(
fit, width, height, config, colorSpace, 0, kBottomLeft_GrSurfaceOrigin));
@@ -257,12 +260,15 @@ sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context,
SkASSERT(SkIsPow2(scaleFactorX) && SkIsPow2(scaleFactorY));
+ // GrTextureDomainEffect does not support kRepeat_Mode with GrSamplerParams::FilterMode.
+ GrTextureDomain::Mode modeForScaling =
+ GrTextureDomain::kRepeat_Mode == mode ? GrTextureDomain::kDecal_Mode : mode;
for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
GrPaint paint;
paint.setGammaCorrect(dstRenderTargetContext->isGammaCorrect());
SkIRect dstRect(srcRect);
- if (srcBounds && i == 1) {
- SkRect domain = SkRect::Make(*srcBounds);
+ if (GrTextureDomain::kIgnore_Mode != mode && i == 1) {
+ SkRect domain = SkRect::Make(localSrcBounds);
domain.inset((i < scaleFactorX) ? SK_ScalarHalf : 0.0f,
(i < scaleFactorY) ? SK_ScalarHalf : 0.0f);
sk_sp<GrFragmentProcessor> fp(GrTextureDomainEffect::Make(
@@ -270,7 +276,7 @@ sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context,
nullptr,
SkMatrix::I(),
domain,
- GrTextureDomain::kDecal_Mode,
+ modeForScaling,
GrSamplerParams::kBilerp_FilterMode));
paint.addColorFragmentProcessor(std::move(fp));
srcRect.offset(-srcOffset);
@@ -311,7 +317,7 @@ sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context,
convolve_gaussian(dstRenderTargetContext.get(), clip, srcRect,
std::move(srcProxy), Gr1DKernelEffect::kX_Direction, radiusX, sigmaX,
- srcBounds, srcOffset);
+ localSrcBounds, srcOffset, mode);
srcRenderTargetContext = dstRenderTargetContext;
srcProxy = srcRenderTargetContext->asTextureProxyRef();
if (!srcProxy) {
@@ -320,6 +326,10 @@ sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context,
srcRect.offsetTo(0, 0);
dstRenderTargetContext.swap(tmpRenderTargetContext);
localSrcBounds = srcRect;
+ if (GrTextureDomain::kClamp_Mode == mode) {
+ // We need to adjust bounds because we only fill part of the srcRect in x-pass.
+ localSrcBounds.inset(0, radiusY);
+ }
srcOffset.set(0, 0);
}
@@ -336,7 +346,7 @@ sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context,
convolve_gaussian(dstRenderTargetContext.get(), clip, srcRect,
std::move(srcProxy), Gr1DKernelEffect::kY_Direction, radiusY, sigmaY,
- srcBounds, srcOffset);
+ localSrcBounds, srcOffset, mode);
srcRenderTargetContext = dstRenderTargetContext;
srcRect.offsetTo(0, 0);
@@ -357,15 +367,26 @@ sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context,
GrPaint paint;
paint.setGammaCorrect(dstRenderTargetContext->isGammaCorrect());
- // FIXME: this should be mitchell, not bilinear.
- GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode);
sk_sp<GrTextureProxy> proxy(srcRenderTargetContext->asTextureProxyRef());
if (!proxy) {
return nullptr;
}
- paint.addColorTextureProcessor(std::move(proxy),
- nullptr, SkMatrix::I(), params);
+ if (GrTextureDomain::kIgnore_Mode != mode) {
+ SkRect domain = SkRect::Make(localSrcBounds);
+ sk_sp<GrFragmentProcessor> fp(GrTextureDomainEffect::Make(
+ std::move(proxy),
+ nullptr,
+ SkMatrix::I(),
+ domain,
+ modeForScaling,
+ GrSamplerParams::kBilerp_FilterMode));
+ paint.addColorFragmentProcessor(std::move(fp));
+ } else {
+ // FIXME: this should be mitchell, not bilinear.
+ GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode);
+ paint.addColorTextureProcessor(std::move(proxy), nullptr, SkMatrix::I(), params);
+ }
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
SkIRect dstRect(srcRect);