aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/SkBlurImageFilter.cpp45
-rw-r--r--src/core/SkGpuBlurUtils.cpp99
-rw-r--r--src/core/SkGpuBlurUtils.h20
3 files changed, 108 insertions, 56 deletions
diff --git a/src/core/SkBlurImageFilter.cpp b/src/core/SkBlurImageFilter.cpp
index 6c18962fba..428b9375fb 100644
--- a/src/core/SkBlurImageFilter.cpp
+++ b/src/core/SkBlurImageFilter.cpp
@@ -26,7 +26,8 @@ public:
SkBlurImageFilterImpl(SkScalar sigmaX,
SkScalar sigmaY,
sk_sp<SkImageFilter> input,
- const CropRect* cropRect);
+ const CropRect* cropRect,
+ SkBlurImageFilter::TileMode tileMode);
SkRect computeFastBounds(const SkRect&) const override;
@@ -42,6 +43,7 @@ protected:
private:
SkSize fSigma;
+ SkBlurImageFilter::TileMode fTileMode;
typedef SkImageFilter INHERITED;
friend class SkImageFilter;
@@ -55,11 +57,13 @@ SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
sk_sp<SkImageFilter> SkBlurImageFilter::Make(SkScalar sigmaX, SkScalar sigmaY,
sk_sp<SkImageFilter> input,
- const SkImageFilter::CropRect* cropRect) {
+ const SkImageFilter::CropRect* cropRect,
+ TileMode tileMode) {
if (0 == sigmaX && 0 == sigmaY && !cropRect) {
return input;
}
- return sk_sp<SkImageFilter>(new SkBlurImageFilterImpl(sigmaX, sigmaY, input, cropRect));
+ return sk_sp<SkImageFilter>(
+ new SkBlurImageFilterImpl(sigmaX, sigmaY, input, cropRect, tileMode));
}
// This rather arbitrary-looking value results in a maximum box blur kernel size
@@ -77,9 +81,12 @@ static SkVector map_sigma(const SkSize& localSigma, const SkMatrix& ctm) {
return sigma;
}
-SkBlurImageFilterImpl::SkBlurImageFilterImpl(
- SkScalar sigmaX, SkScalar sigmaY, sk_sp<SkImageFilter> input, const CropRect* cropRect)
- : INHERITED(&input, 1, cropRect), fSigma{sigmaX, sigmaY} {}
+SkBlurImageFilterImpl::SkBlurImageFilterImpl(SkScalar sigmaX,
+ SkScalar sigmaY,
+ sk_sp<SkImageFilter> input,
+ const CropRect* cropRect,
+ SkBlurImageFilter::TileMode tileMode)
+ : INHERITED(&input, 1, cropRect), fSigma{sigmaX, sigmaY}, fTileMode(tileMode) {}
sk_sp<SkFlattenable> SkBlurImageFilterImpl::CreateProc(SkReadBuffer& buffer) {
SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
@@ -94,6 +101,24 @@ void SkBlurImageFilterImpl::flatten(SkWriteBuffer& buffer) const {
buffer.writeScalar(fSigma.fHeight);
}
+#if SK_SUPPORT_GPU
+static GrTextureDomain::Mode to_texture_domain_mode(SkBlurImageFilter::TileMode tileMode) {
+ switch (tileMode) {
+ case SkBlurImageFilter::TileMode::kIgnore_TileMode:
+ return GrTextureDomain::kIgnore_Mode;
+ case SkBlurImageFilter::TileMode::kClamp_TileMode:
+ return GrTextureDomain::kClamp_Mode;
+ case SkBlurImageFilter::TileMode::kClampToBlack_TileMode:
+ return GrTextureDomain::kDecal_Mode;
+ case SkBlurImageFilter::TileMode::kRepeat_TileMode:
+ return GrTextureDomain::kRepeat_Mode;
+ default:
+ SkFAIL("Unsupported tile mode.");
+ return GrTextureDomain::kDecal_Mode;
+ }
+}
+#endif
+
static void get_box3_params(SkScalar s, int *kernelSize, int* kernelSize3, int *lowOffset,
int *highOffset) {
float pi = SkScalarToFloat(SK_ScalarPI);
@@ -165,9 +190,10 @@ sk_sp<SkSpecialImage> SkBlurImageFilterImpl::onFilterImage(SkSpecialImage* sourc
std::move(inputTexture),
sk_ref_sp(input->getColorSpace()),
dstBounds,
- &inputBounds,
+ inputBounds,
sigma.x(),
- sigma.y()));
+ sigma.y(),
+ to_texture_domain_mode(fTileMode)));
if (!renderTargetContext) {
return nullptr;
}
@@ -182,6 +208,7 @@ sk_sp<SkSpecialImage> SkBlurImageFilterImpl::onFilterImage(SkSpecialImage* sourc
}
#endif
+ // TODO: Implement CPU backend for different fTileMode.
int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX;
int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY;
get_box3_params(sigma.x(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffsetX);
@@ -279,7 +306,7 @@ const {
sk_sp<SkImageFilter> input = this->getInput(0)->makeColorSpace(xformer);
return SkBlurImageFilter::Make(fSigma.width(), fSigma.height(), std::move(input),
- this->getCropRectIfSet());
+ this->getCropRectIfSet(), fTileMode);
}
SkRect SkBlurImageFilterImpl::computeFastBounds(const SkRect& src) const {
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);
diff --git a/src/core/SkGpuBlurUtils.h b/src/core/SkGpuBlurUtils.h
index c6c56b61f7..8a6f7b1922 100644
--- a/src/core/SkGpuBlurUtils.h
+++ b/src/core/SkGpuBlurUtils.h
@@ -10,6 +10,7 @@
#if SK_SUPPORT_GPU
#include "GrRenderTargetContext.h"
+#include "effects/GrTextureDomain.h"
class GrContext;
class GrTexture;
@@ -30,17 +31,20 @@ namespace SkGpuBlurUtils {
* no pixels will be sampled outside of this rectangle.
* @param sigmaX The blur's standard deviation in X.
* @param sigmaY The blur's standard deviation in Y.
+ * @param mode The mode to handle samples outside bounds.
* @param fit backing fit for the returned render target context
* @return The renderTargetContext containing the blurred result.
*/
- sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context,
- sk_sp<GrTextureProxy> src,
- sk_sp<SkColorSpace> colorSpace,
- const SkIRect& dstBounds,
- const SkIRect* srcBounds,
- float sigmaX,
- float sigmaY,
- SkBackingFit fit = SkBackingFit::kApprox);
+ sk_sp<GrRenderTargetContext> GaussianBlur(
+ GrContext* context,
+ sk_sp<GrTextureProxy> src,
+ sk_sp<SkColorSpace> colorSpace,
+ const SkIRect& dstBounds,
+ const SkIRect& srcBounds,
+ float sigmaX,
+ float sigmaY,
+ GrTextureDomain::Mode mode,
+ SkBackingFit fit = SkBackingFit::kApprox);
};
#endif