diff --git a/src/core/SkBlurMF.cpp b/src/core/SkBlurMF.cpp index 30be330cf0..aa00e50799 100644 --- a/src/core/SkBlurMF.cpp +++ b/src/core/SkBlurMF.cpp @@ -883,18 +883,17 @@ sk_sp SkBlurMaskFilterImpl::filterMaskGPU(GrRecordingContext* co // 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 = (kNormal_SkBlurStyle == fBlurStyle); - auto renderTargetContext = - SkGpuBlurUtils::GaussianBlur(context, - srcProxy, - srcColorType, - srcAlphaType, - SkIPoint::Make(0, 0), - nullptr, - clipRect, - SkIRect::MakeSize(srcProxy->dimensions()), - xformedSigma, - xformedSigma, - SkTileMode::kClamp); + auto renderTargetContext = SkGpuBlurUtils::GaussianBlur(context, + srcProxy, + srcColorType, + srcAlphaType, + SkIPoint::Make(0, 0), + nullptr, + clipRect, + SkIRect::MakeEmpty(), + xformedSigma, + xformedSigma, + GrTextureDomain::kIgnore_Mode); if (!renderTargetContext) { return nullptr; } diff --git a/src/core/SkGpuBlurUtils.cpp b/src/core/SkGpuBlurUtils.cpp index 28105c856d..b4d265b6e5 100644 --- a/src/core/SkGpuBlurUtils.cpp +++ b/src/core/SkGpuBlurUtils.cpp @@ -71,21 +71,6 @@ static float adjust_sigma(float sigma, int maxTextureSize, int *scaleFactor, int return sigma; } -static GrTextureDomain::Mode to_texture_domain_mode(SkTileMode tileMode) { - switch (tileMode) { - case SkTileMode::kClamp: - return GrTextureDomain::kClamp_Mode; - case SkTileMode::kDecal: - return GrTextureDomain::kDecal_Mode; - case SkTileMode::kMirror: - // TODO (michaelludwig) - Support mirror mode, treat as repeat for now - case SkTileMode::kRepeat: - return GrTextureDomain::kRepeat_Mode; - default: - SK_ABORT("Unsupported tile mode."); - } -} - static void convolve_gaussian_1d(GrRenderTargetContext* renderTargetContext, const GrClip& clip, const SkIRect& dstRect, @@ -95,12 +80,11 @@ static void convolve_gaussian_1d(GrRenderTargetContext* renderTargetContext, Direction direction, int radius, float sigma, - SkTileMode mode, + GrTextureDomain::Mode mode, int bounds[2]) { GrPaint paint; - auto domainMode = to_texture_domain_mode(mode); std::unique_ptr conv(GrGaussianConvolutionFragmentProcessor::Make( - std::move(proxy), srcAlphaType, direction, radius, sigma, domainMode, bounds)); + std::move(proxy), srcAlphaType, direction, radius, sigma, mode, bounds)); paint.addColorFragmentProcessor(std::move(conv)); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); SkMatrix localMatrix = SkMatrix::MakeTrans(-SkIntToScalar(srcOffset.x()), @@ -118,7 +102,7 @@ static std::unique_ptr convolve_gaussian_2d(GrRecordingCo int radiusY, SkScalar sigmaX, SkScalar sigmaY, - SkTileMode mode, + GrTextureDomain::Mode mode, int finalW, int finalH, sk_sp finalCS, @@ -135,9 +119,8 @@ static std::unique_ptr convolve_gaussian_2d(GrRecordingCo SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1); SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY); GrPaint paint; - auto domainMode = to_texture_domain_mode(mode); auto conv = GrMatrixConvolutionEffect::MakeGaussian(std::move(srcProxy), srcBounds, size, - 1.0, 0.0, kernelOffset, domainMode, true, + 1.0, 0.0, kernelOffset, mode, true, sigmaX, sigmaY); paint.addColorFragmentProcessor(std::move(conv)); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); @@ -167,7 +150,7 @@ static std::unique_ptr convolve_gaussian(GrRecordingConte int radius, float sigma, SkIRect* contentRect, - SkTileMode mode, + GrTextureDomain::Mode mode, int finalW, int finalH, sk_sp finalCS, @@ -186,14 +169,11 @@ static std::unique_ptr convolve_gaussian(GrRecordingConte int bounds[2] = { 0, 0 }; SkIRect dstRect = SkIRect::MakeWH(srcRect.width(), srcRect.height()); SkIPoint netOffset = srcOffset - proxyOffset; - if (SkTileMode::kClamp == mode && proxyOffset.isZero() && - contentRect->contains(SkIRect::MakeSize(srcProxy->backingStoreDimensions()))) { - bounds[0] = direction == Direction::kX ? contentRect->left() : contentRect->top(); - bounds[1] = direction == Direction::kX ? contentRect->right() : contentRect->bottom(); + if (GrTextureDomain::kIgnore_Mode == mode) { *contentRect = dstRect; convolve_gaussian_1d(dstRenderTargetContext.get(), clip, dstRect, netOffset, std::move(srcProxy), srcAlphaType, direction, radius, sigma, - SkTileMode::kClamp, bounds); + GrTextureDomain::kIgnore_Mode, bounds); return dstRenderTargetContext; } // These destination rects need to be adjusted by srcOffset, but should *not* be adjusted by @@ -255,11 +235,9 @@ static std::unique_ptr convolve_gaussian(GrRecordingConte srcAlphaType, direction, radius, sigma, mode, bounds); convolve_gaussian_1d(dstRenderTargetContext.get(), clip, rightRect, netOffset, srcProxy, srcAlphaType, direction, radius, sigma, mode, bounds); - bounds[0] = 0; - bounds[1] = direction == Direction::kX ? srcProxy->width() : srcProxy->height(); convolve_gaussian_1d(dstRenderTargetContext.get(), clip, midRect, netOffset, std::move(srcProxy), srcAlphaType, direction, radius, sigma, - SkTileMode::kClamp, bounds); + GrTextureDomain::kIgnore_Mode, bounds); } return dstRenderTargetContext; @@ -275,15 +253,22 @@ static sk_sp decimate(GrRecordingContext* context, const SkIPoint& proxyOffset, SkIPoint* srcOffset, SkIRect* contentRect, - int scaleFactorX, - int scaleFactorY, - SkTileMode mode, + int scaleFactorX, int scaleFactorY, + int radiusX, int radiusY, + GrTextureDomain::Mode mode, + int finalW, + int finalH, sk_sp finalCS) { SkASSERT(SkIsPow2(scaleFactorX) && SkIsPow2(scaleFactorY)); SkASSERT(scaleFactorX > 1 || scaleFactorY > 1); - SkIRect srcRect = *contentRect; - srcRect.offset(*srcOffset); + SkIRect srcRect; + if (GrTextureDomain::kIgnore_Mode == mode) { + srcRect = SkIRect::MakeWH(finalW, finalH); + } else { + srcRect = *contentRect; + srcRect.offset(*srcOffset); + } scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); scale_irect(&srcRect, scaleFactorX, scaleFactorY); @@ -309,16 +294,13 @@ static sk_sp decimate(GrRecordingContext* context, GrPaint paint; auto fp = GrTextureEffect::Make(std::move(srcProxy), srcAlphaType, SkMatrix::I(), GrSamplerState::Filter::kBilerp); - if (i == 1) { + if (GrTextureDomain::kIgnore_Mode != mode && i == 1) { // GrDomainEffect does not support kRepeat_Mode with GrSamplerState::Filter. - GrTextureDomain::Mode domainMode; - if (mode == SkTileMode::kClamp) { - domainMode = GrTextureDomain::kClamp_Mode; - } else { - // GrDomainEffect does not support k[Mirror]Repeat with GrSamplerState::Filter. - // So we use decal. - domainMode = GrTextureDomain::kDecal_Mode; - } + GrTextureDomain::Mode modeForScaling = (GrTextureDomain::kRepeat_Mode == mode || + GrTextureDomain::kMirrorRepeat_Mode == mode) + ? GrTextureDomain::kDecal_Mode + : mode; + SkRect domain = SkRect::Make(*contentRect); domain.inset((i < scaleFactorX) ? SK_ScalarHalf + SK_ScalarNearlyZero : 0.0f, (i < scaleFactorY) ? SK_ScalarHalf + SK_ScalarNearlyZero : 0.0f); @@ -330,7 +312,7 @@ static sk_sp decimate(GrRecordingContext* context, domain.fTop = domain.fBottom = SkScalarAve(domain.fTop, domain.fBottom); } domain.offset(proxyOffset.x(), proxyOffset.y()); - fp = GrDomainEffect::Make(std::move(fp), domain, domainMode, true); + fp = GrDomainEffect::Make(std::move(fp), domain, modeForScaling, true); srcRect.offset(-(*srcOffset)); // TODO: consume the srcOffset in both first draws and always set it to zero // back in GaussianBlur @@ -421,7 +403,7 @@ std::unique_ptr GaussianBlur(GrRecordingContext* context, const SkIRect& srcBounds, float sigmaX, float sigmaY, - SkTileMode mode, + GrTextureDomain::Mode mode, SkBackingFit fit) { SkASSERT(context); @@ -463,14 +445,21 @@ std::unique_ptr GaussianBlur(GrRecordingContext* context, xFit = SkBackingFit::kApprox; // the y-pass will be last } + GrTextureDomain::Mode currDomainMode = mode; if (scaleFactorX > 1 || scaleFactorY > 1) { - srcProxy = decimate(context, std::move(srcProxy), srcColorType, srcAlphaType, - localProxyOffset, &srcOffset, &localSrcBounds, scaleFactorX, - scaleFactorY, mode, colorSpace); + srcProxy = + decimate(context, std::move(srcProxy), srcColorType, srcAlphaType, localProxyOffset, + &srcOffset, &localSrcBounds, scaleFactorX, scaleFactorY, radiusX, radiusY, + currDomainMode, finalW, finalH, colorSpace); if (!srcProxy) { return nullptr; } localProxyOffset.set(0, 0); + if (GrTextureDomain::kIgnore_Mode == currDomainMode) { + // decimate() always returns an approx texture, possibly with garbage after the image. + // We can't ignore the domain anymore. + currDomainMode = GrTextureDomain::kClamp_Mode; + } } std::unique_ptr dstRenderTargetContext; @@ -478,10 +467,10 @@ std::unique_ptr GaussianBlur(GrRecordingContext* context, auto srcRect = SkIRect::MakeWH(finalW, finalH); scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); if (sigmaX > 0.0f) { - dstRenderTargetContext = - convolve_gaussian(context, std::move(srcProxy), srcColorType, srcAlphaType, - localProxyOffset, srcRect, srcOffset, Direction::kX, radiusX, - sigmaX, &localSrcBounds, mode, finalW, finalH, colorSpace, xFit); + dstRenderTargetContext = convolve_gaussian( + context, std::move(srcProxy), srcColorType, srcAlphaType, localProxyOffset, srcRect, + srcOffset, Direction::kX, radiusX, sigmaX, &localSrcBounds, currDomainMode, finalW, + finalH, colorSpace, xFit); if (!dstRenderTargetContext) { return nullptr; } @@ -494,13 +483,18 @@ std::unique_ptr GaussianBlur(GrRecordingContext* context, srcRect.offsetTo(0, 0); srcOffset.set(0, 0); localProxyOffset.set(0, 0); + if (SkBackingFit::kApprox == xFit && GrTextureDomain::kIgnore_Mode == currDomainMode) { + // srcProxy is now an approx texture, possibly with garbage after the image. We can't + // ignore the domain anymore. + currDomainMode = GrTextureDomain::kClamp_Mode; + } } if (sigmaY > 0.0f) { - dstRenderTargetContext = - convolve_gaussian(context, std::move(srcProxy), srcColorType, srcAlphaType, - localProxyOffset, srcRect, srcOffset, Direction::kY, radiusY, - sigmaY, &localSrcBounds, mode, finalW, finalH, colorSpace, yFit); + dstRenderTargetContext = convolve_gaussian( + context, std::move(srcProxy), srcColorType, srcAlphaType, localProxyOffset, srcRect, + srcOffset, Direction::kY, radiusY, sigmaY, &localSrcBounds, currDomainMode, finalW, + finalH, colorSpace, yFit); if (!dstRenderTargetContext) { return nullptr; } diff --git a/src/core/SkGpuBlurUtils.h b/src/core/SkGpuBlurUtils.h index a1b3308577..9143518cd1 100644 --- a/src/core/SkGpuBlurUtils.h +++ b/src/core/SkGpuBlurUtils.h @@ -18,32 +18,32 @@ class GrTexture; struct SkRect; namespace SkGpuBlurUtils { -/** - * Applies a 2D Gaussian blur to a given texture. The blurred result is returned - * as a renderTargetContext in case the caller wishes to draw into the result. - * - * The 'proxyOffset' is kept separate form 'srcBounds' because they exist in different - * coordinate spaces. 'srcBounds' exists in the content space of the special image, and - * 'proxyOffset' maps from the content space to the proxy's space. - * - * Note: one of sigmaX and sigmaY should be non-zero! - * @param context The GPU context - * @param srcProxy The source to be blurred. - * @param srcColorType The colorType of srcProxy - * @param srcAlphaType The alphaType of srcProxy - * @param proxyOffset The offset from the top-left corner to valid texels in 'srcProxy', - which should come from the subset of the owning SkSpecialImage. - * @param colorSpace Color space of the source (used for the renderTargetContext result, - * too). - * @param dstBounds The destination bounds, relative to the source texture. - * @param srcBounds The source bounds, relative to the source texture's offset. 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 tileMode The mode to handle samples outside bounds. - * @param fit backing fit for the returned render target context - * @return The renderTargetContext containing the blurred result. - */ + /** + * Applies a 2D Gaussian blur to a given texture. The blurred result is returned + * as a renderTargetContext in case the caller wishes to draw into the result. + * + * The 'proxyOffset' is kept separate form 'srcBounds' because they exist in different + * coordinate spaces. 'srcBounds' exists in the content space of the special image, and + * 'proxyOffset' maps from the content space to the proxy's space. + * + * Note: one of sigmaX and sigmaY should be non-zero! + * @param context The GPU context + * @param srcProxy The source to be blurred. + * @param srcColorType The colorType of srcProxy + * @param srcAlphaType The alphaType of srcProxy + * @param proxyOffset The offset from the top-left corner to valid texels in 'srcProxy', + which should come from the subset of the owning SkSpecialImage. + * @param colorSpace Color space of the source (used for the renderTargetContext result, + * too). + * @param dstBounds The destination bounds, relative to the source texture. + * @param srcBounds The source bounds, relative to the source texture's offset. 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. + */ std::unique_ptr GaussianBlur(GrRecordingContext* context, sk_sp srcProxy, GrColorType srcColorType, @@ -54,7 +54,7 @@ std::unique_ptr GaussianBlur(GrRecordingContext* context, const SkIRect& srcBounds, float sigmaX, float sigmaY, - SkTileMode mode, + GrTextureDomain::Mode mode, SkBackingFit fit = SkBackingFit::kApprox); }; diff --git a/src/effects/imagefilters/SkBlurImageFilter.cpp b/src/effects/imagefilters/SkBlurImageFilter.cpp index 2bfd8e86b1..2dde5e2be7 100644 --- a/src/effects/imagefilters/SkBlurImageFilter.cpp +++ b/src/effects/imagefilters/SkBlurImageFilter.cpp @@ -131,6 +131,23 @@ void SkBlurImageFilterImpl::flatten(SkWriteBuffer& buffer) const { buffer.writeInt(static_cast(fTileMode)); } +#if SK_SUPPORT_GPU +static GrTextureDomain::Mode to_texture_domain_mode(SkTileMode tileMode) { + switch (tileMode) { + case SkTileMode::kClamp: + return GrTextureDomain::kClamp_Mode; + case SkTileMode::kDecal: + return GrTextureDomain::kDecal_Mode; + case SkTileMode::kMirror: + // TODO (michaelludwig) - Support mirror mode, treat as repeat for now + case SkTileMode::kRepeat: + return GrTextureDomain::kRepeat_Mode; + default: + SK_ABORT("Unsupported tile mode."); + } +} +#endif + // This is defined by the SVG spec: // https://drafts.fxtf.org/filter-effects/#feGaussianBlurElement static int calculate_window(double sigma) { @@ -660,7 +677,7 @@ sk_sp SkBlurImageFilterImpl::gpuFilter( inputBounds, sigma.x(), sigma.y(), - fTileMode); + to_texture_domain_mode(fTileMode)); if (!renderTargetContext) { return nullptr; } diff --git a/src/gpu/GrFragmentProcessor.h b/src/gpu/GrFragmentProcessor.h index b7206de1f7..4150dcab1d 100644 --- a/src/gpu/GrFragmentProcessor.h +++ b/src/gpu/GrFragmentProcessor.h @@ -502,13 +502,12 @@ public: bool isInitialized() const { return SkToBool(this->proxy()); } - GrSurfaceProxy* proxy() const { return fView.proxy(); } - #if GR_TEST_UTILS void set(GrSurfaceProxyView, GrSamplerState); #endif - private: + GrSurfaceProxy* proxy() const { return fView.proxy(); } + GrSurfaceProxyView fView; GrSamplerState fSamplerState; }; diff --git a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp index 35dfcd0e27..9a66a07a1b 100644 --- a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp +++ b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp @@ -229,49 +229,15 @@ GrGaussianConvolutionFragmentProcessor::GrGaussianConvolutionFragmentProcessor( , fRadius(radius) , fDirection(direction) , fMode(mode) { + // Make sure the sampler's ctor uses the clamp wrap mode + SkASSERT(fTextureSampler.samplerState().wrapModeX() == GrSamplerState::WrapMode::kClamp && + fTextureSampler.samplerState().wrapModeY() == GrSamplerState::WrapMode::kClamp); this->addCoordTransform(&fCoordTransform); this->setTextureSamplerCnt(1); SkASSERT(radius <= kMaxKernelRadius); fill_in_1D_gaussian_kernel(fKernel, this->width(), gaussianSigma, this->radius()); - // SkGpuBlurUtils is not as aggressive as it once was about avoiding domains. So we check - // here if we can omit the domain. TODO: remove this when this effect uses a child to - // sample the texture. - auto samplerProxy = fTextureSampler.proxy(); - if (!samplerProxy->isFullyLazy()) { - int wh = (fDirection == Direction::kX) ? samplerProxy->backingStoreDimensions().width() - : samplerProxy->backingStoreDimensions().height(); - if (bounds[0] == 0 && bounds[1] == wh) { - bool useSampler = false; - GrSamplerState::WrapMode samplerMode = GrSamplerState::WrapMode::kClamp; - switch (fMode) { - case GrTextureDomain::kClamp_Mode: - case GrTextureDomain::kIgnore_Mode: - useSampler = true; - break; - case GrTextureDomain::kRepeat_Mode: - useSampler = true; - samplerMode = GrSamplerState::WrapMode::kRepeat; - break; - case GrTextureDomain::kMirrorRepeat_Mode: - useSampler = true; - samplerMode = GrSamplerState::WrapMode::kMirrorRepeat; - break; - case GrTextureDomain::kDecal_Mode: - // Not sure if we support this in HW without having GrCaps here. - // Just wait until we replace this with GrTextureEffect. - break; - } - if (useSampler) { - fMode = GrTextureDomain::kIgnore_Mode; - if (fDirection == Direction::kX) { - fTextureSampler.samplerState().setWrapModeX(samplerMode); - } else { - fTextureSampler.samplerState().setWrapModeY(samplerMode); - } - } - } - } + memcpy(fBounds, bounds, sizeof(fBounds)); } diff --git a/src/gpu/effects/GrRRectBlurEffect.fp b/src/gpu/effects/GrRRectBlurEffect.fp index 9234ac693d..290295b067 100644 --- a/src/gpu/effects/GrRRectBlurEffect.fp +++ b/src/gpu/effects/GrRRectBlurEffect.fp @@ -80,10 +80,10 @@ uniform half blurRadius; SkIPoint::Make(0, 0), nullptr, SkIRect::MakeSize(dimensions), - SkIRect::MakeSize(dimensions), + SkIRect::MakeEmpty(), xformedSigma, xformedSigma, - SkTileMode::kClamp, + GrTextureDomain::kIgnore_Mode, SkBackingFit::kExact); if (!rtc2) { return nullptr; diff --git a/src/gpu/effects/generated/GrRRectBlurEffect.h b/src/gpu/effects/generated/GrRRectBlurEffect.h index 198527787e..94b6ca1485 100644 --- a/src/gpu/effects/generated/GrRRectBlurEffect.h +++ b/src/gpu/effects/generated/GrRRectBlurEffect.h @@ -80,10 +80,10 @@ public: SkIPoint::Make(0, 0), nullptr, SkIRect::MakeSize(dimensions), - SkIRect::MakeSize(dimensions), + SkIRect::MakeEmpty(), xformedSigma, xformedSigma, - SkTileMode::kClamp, + GrTextureDomain::kIgnore_Mode, SkBackingFit::kExact); if (!rtc2) { return nullptr;