From d0dc05b98b71af43b44f13beba1292db52b75539 Mon Sep 17 00:00:00 2001 From: Robert Phillips Date: Mon, 30 Jan 2017 09:14:04 -0500 Subject: [PATCH] Make blur utils take GrTextureProxies Change-Id: I1c5054de6d9827eece2f73c4c78818b4db0bc611 Reviewed-on: https://skia-review.googlesource.com/7738 Reviewed-by: Brian Salomon Commit-Queue: Robert Phillips --- src/core/SkBlurImageFilter.cpp | 4 +- src/core/SkGpuBlurUtils.cpp | 93 +++++++++++----------- src/core/SkGpuBlurUtils.h | 4 +- src/effects/SkBlurMaskFilter.cpp | 17 ++-- .../GrGaussianConvolutionFragmentProcessor.cpp | 40 ++++++---- .../GrGaussianConvolutionFragmentProcessor.h | 12 +-- src/gpu/effects/GrProxyMove.h | 4 +- 7 files changed, 91 insertions(+), 83 deletions(-) diff --git a/src/core/SkBlurImageFilter.cpp b/src/core/SkBlurImageFilter.cpp index 6f7a2e3..1a0515b 100644 --- a/src/core/SkBlurImageFilter.cpp +++ b/src/core/SkBlurImageFilter.cpp @@ -141,7 +141,7 @@ sk_sp SkBlurImageFilterImpl::onFilterImage(SkSpecialImage* sourc // xform during the filter itself. input = ImageToColorSpace(input.get(), ctx.outputProperties()); - sk_sp inputTexture(input->asTextureRef(context)); + sk_sp inputTexture(input->asTextureProxy(context)); if (!inputTexture) { return nullptr; } @@ -163,7 +163,7 @@ sk_sp SkBlurImageFilterImpl::onFilterImage(SkSpecialImage* sourc // have the same gamut, so in this case, we do everything in the input's color space. sk_sp renderTargetContext(SkGpuBlurUtils::GaussianBlur( context, - inputTexture.get(), + std::move(inputTexture), sk_ref_sp(input->getColorSpace()), dstBounds, &inputBounds, diff --git a/src/core/SkGpuBlurUtils.cpp b/src/core/SkGpuBlurUtils.cpp index d7522ca..d58582d 100644 --- a/src/core/SkGpuBlurUtils.cpp +++ b/src/core/SkGpuBlurUtils.cpp @@ -66,20 +66,21 @@ static float adjust_sigma(float sigma, int maxTextureSize, int *scaleFactor, int return sigma; } -static void convolve_gaussian_1d(GrRenderTargetContext* renderTargetContext, +static void convolve_gaussian_1d(GrContext* context, + GrRenderTargetContext* renderTargetContext, const GrClip& clip, const SkIRect& dstRect, const SkIPoint& srcOffset, - GrTexture* texture, + sk_sp proxy, Gr1DKernelEffect::Direction direction, int radius, float sigma, bool useBounds, - float bounds[2]) { + int bounds[2]) { GrPaint paint; paint.setGammaCorrect(renderTargetContext->isGammaCorrect()); sk_sp conv(GrGaussianConvolutionFragmentProcessor::Make( - texture, direction, radius, sigma, useBounds, bounds)); + context, std::move(proxy), direction, radius, sigma, useBounds, bounds)); paint.addColorFragmentProcessor(std::move(conv)); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); SkMatrix localMatrix = SkMatrix::MakeTrans(-SkIntToScalar(srcOffset.x()), @@ -88,11 +89,12 @@ static void convolve_gaussian_1d(GrRenderTargetContext* renderTargetContext, SkRect::Make(dstRect), localMatrix); } -static void convolve_gaussian_2d(GrRenderTargetContext* renderTargetContext, +static void convolve_gaussian_2d(GrContext* context, + GrRenderTargetContext* renderTargetContext, const GrClip& clip, const SkIRect& dstRect, const SkIPoint& srcOffset, - GrTexture* texture, + sk_sp proxy, int radiusX, int radiusY, SkScalar sigmaX, @@ -107,7 +109,7 @@ static void convolve_gaussian_2d(GrRenderTargetContext* renderTargetContext, SkIRect bounds = srcBounds ? *srcBounds : SkIRect::EmptyIRect(); sk_sp conv(GrMatrixConvolutionEffect::MakeGaussian( - texture, bounds, size, 1.0, 0.0, kernelOffset, + context, std::move(proxy), bounds, size, 1.0, 0.0, kernelOffset, srcBounds ? GrTextureDomain::kDecal_Mode : GrTextureDomain::kIgnore_Mode, true, sigmaX, sigmaY)); paint.addColorFragmentProcessor(std::move(conv)); @@ -116,28 +118,29 @@ static void convolve_gaussian_2d(GrRenderTargetContext* renderTargetContext, SkRect::Make(dstRect), localMatrix); } -static void convolve_gaussian(GrRenderTargetContext* renderTargetContext, +static void convolve_gaussian(GrContext* context, + GrRenderTargetContext* renderTargetContext, const GrClip& clip, const SkIRect& srcRect, - GrTexture* texture, + sk_sp proxy, Gr1DKernelEffect::Direction direction, int radius, float sigma, const SkIRect* srcBounds, const SkIPoint& srcOffset) { - float bounds[2] = { 0.0f, 1.0f }; + int bounds[2] = { 0, 0 }; SkIRect dstRect = SkIRect::MakeWH(srcRect.width(), srcRect.height()); if (!srcBounds) { - convolve_gaussian_1d(renderTargetContext, clip, dstRect, srcOffset, texture, - direction, radius, sigma, false, bounds); + convolve_gaussian_1d(context, renderTargetContext, clip, dstRect, srcOffset, + std::move(proxy), direction, radius, sigma, false, bounds); return; } SkIRect midRect = *srcBounds, leftRect, rightRect; midRect.offset(srcOffset); SkIRect topRect, bottomRect; if (direction == Gr1DKernelEffect::kX_Direction) { - bounds[0] = SkIntToFloat(srcBounds->left()) / texture->width(); - bounds[1] = SkIntToFloat(srcBounds->right()) / texture->width(); + 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); @@ -147,8 +150,8 @@ static void convolve_gaussian(GrRenderTargetContext* renderTargetContext, dstRect.fTop = midRect.top(); dstRect.fBottom = midRect.bottom(); } else { - bounds[0] = SkIntToFloat(srcBounds->top()) / texture->height(); - bounds[1] = SkIntToFloat(srcBounds->bottom()) / texture->height(); + 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); @@ -167,23 +170,23 @@ static void convolve_gaussian(GrRenderTargetContext* renderTargetContext, } if (midRect.isEmpty()) { // Blur radius covers srcBounds; use bounds over entire draw - convolve_gaussian_1d(renderTargetContext, clip, dstRect, srcOffset, texture, - direction, radius, sigma, true, bounds); + convolve_gaussian_1d(context, renderTargetContext, clip, dstRect, srcOffset, + std::move(proxy), direction, radius, sigma, true, bounds); } else { // Draw right and left margins with bounds; middle without. - convolve_gaussian_1d(renderTargetContext, clip, leftRect, srcOffset, texture, - direction, radius, sigma, true, bounds); - convolve_gaussian_1d(renderTargetContext, clip, rightRect, srcOffset, texture, - direction, radius, sigma, true, bounds); - convolve_gaussian_1d(renderTargetContext, clip, midRect, srcOffset, texture, - direction, radius, sigma, false, bounds); + convolve_gaussian_1d(context, renderTargetContext, clip, leftRect, srcOffset, + proxy, direction, radius, sigma, true, bounds); + convolve_gaussian_1d(context, renderTargetContext, clip, rightRect, srcOffset, + proxy, direction, radius, sigma, true, bounds); + convolve_gaussian_1d(context, renderTargetContext, clip, midRect, srcOffset, + std::move(proxy), direction, radius, sigma, false, bounds); } } namespace SkGpuBlurUtils { sk_sp GaussianBlur(GrContext* context, - GrTexture* origSrc, + sk_sp srcProxy, sk_sp colorSpace, const SkIRect& dstBounds, const SkIRect* srcBounds, @@ -217,18 +220,14 @@ sk_sp GaussianBlur(GrContext* context, // setup new clip GrFixedClip clip(localDstBounds); - sk_sp srcTexture(sk_ref_sp(origSrc)); + const GrPixelConfig config = srcProxy->config(); - SkASSERT(kBGRA_8888_GrPixelConfig == srcTexture->config() || - kRGBA_8888_GrPixelConfig == srcTexture->config() || - kSRGBA_8888_GrPixelConfig == srcTexture->config() || - kSBGRA_8888_GrPixelConfig == srcTexture->config() || - kRGBA_half_GrPixelConfig == srcTexture->config() || - kAlpha_8_GrPixelConfig == srcTexture->config()); + SkASSERT(kBGRA_8888_GrPixelConfig == config || kRGBA_8888_GrPixelConfig == config || + kSRGBA_8888_GrPixelConfig == config || kSBGRA_8888_GrPixelConfig == config || + kRGBA_half_GrPixelConfig == config || kAlpha_8_GrPixelConfig == config); const int width = dstBounds.width(); const int height = dstBounds.height(); - const GrPixelConfig config = srcTexture->config(); sk_sp dstRenderTargetContext(context->makeDeferredRenderTargetContext( fit, width, height, config, colorSpace, 0, kBottomLeft_GrSurfaceOrigin)); @@ -243,8 +242,8 @@ sk_sp 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, - srcTexture.get(), radiusX, radiusY, sigmaX, sigmaY, srcBounds); + convolve_gaussian_2d(context, dstRenderTargetContext.get(), clip, localDstBounds, srcOffset, + std::move(srcProxy), radiusX, radiusY, sigmaX, sigmaY, srcBounds); return dstRenderTargetContext; } @@ -268,7 +267,8 @@ sk_sp GaussianBlur(GrContext* context, domain.inset((i < scaleFactorX) ? SK_ScalarHalf : 0.0f, (i < scaleFactorY) ? SK_ScalarHalf : 0.0f); sk_sp fp(GrTextureDomainEffect::Make( - srcTexture.get(), + context, + std::move(srcProxy), nullptr, SkMatrix::I(), domain, @@ -279,7 +279,8 @@ sk_sp GaussianBlur(GrContext* context, srcOffset.set(0, 0); } else { GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode); - paint.addColorTextureProcessor(srcTexture.get(), nullptr, SkMatrix::I(), params); + paint.addColorTextureProcessor(context, std::move(srcProxy), nullptr, + SkMatrix::I(), params); } paint.setPorterDuffXPFactory(SkBlendMode::kSrc); shrink_irect_by_2(&dstRect, i < scaleFactorX, i < scaleFactorY); @@ -289,8 +290,8 @@ sk_sp GaussianBlur(GrContext* context, srcRenderTargetContext = dstRenderTargetContext; srcRect = dstRect; - srcTexture = srcRenderTargetContext->asTexture(); - if (!srcTexture) { + srcProxy = sk_ref_sp(srcRenderTargetContext->asDeferredTexture()); + if (!srcProxy) { return nullptr; } dstRenderTargetContext.swap(tmpRenderTargetContext); @@ -310,12 +311,12 @@ sk_sp GaussianBlur(GrContext* context, srcRenderTargetContext->priv().absClear(&clearRect, 0x0); } - convolve_gaussian(dstRenderTargetContext.get(), clip, srcRect, - srcTexture.get(), Gr1DKernelEffect::kX_Direction, radiusX, sigmaX, + convolve_gaussian(context, dstRenderTargetContext.get(), clip, srcRect, + std::move(srcProxy), Gr1DKernelEffect::kX_Direction, radiusX, sigmaX, srcBounds, srcOffset); srcRenderTargetContext = dstRenderTargetContext; - srcTexture = srcRenderTargetContext->asTexture(); - if (!srcTexture) { + srcProxy = sk_ref_sp(srcRenderTargetContext->asDeferredTexture()); + if (!srcProxy) { return nullptr; } srcRect.offsetTo(0, 0); @@ -335,8 +336,8 @@ sk_sp GaussianBlur(GrContext* context, srcRenderTargetContext->priv().absClear(&clearRect, 0x0); } - convolve_gaussian(dstRenderTargetContext.get(), clip, srcRect, - srcTexture.get(), Gr1DKernelEffect::kY_Direction, radiusY, sigmaY, + convolve_gaussian(context, dstRenderTargetContext.get(), clip, srcRect, + std::move(srcProxy), Gr1DKernelEffect::kY_Direction, radiusY, sigmaY, srcBounds, srcOffset); srcRenderTargetContext = dstRenderTargetContext; @@ -345,7 +346,7 @@ sk_sp GaussianBlur(GrContext* context, } SkASSERT(srcRenderTargetContext); - srcTexture = nullptr; // we don't use this from here on out + srcProxy.reset(nullptr); // we don't use this from here on out if (scaleFactorX > 1 || scaleFactorY > 1) { // Clear one pixel to the right and below, to accommodate bilinear upsampling. diff --git a/src/core/SkGpuBlurUtils.h b/src/core/SkGpuBlurUtils.h index 7849e8c..c6c56b6 100644 --- a/src/core/SkGpuBlurUtils.h +++ b/src/core/SkGpuBlurUtils.h @@ -22,7 +22,7 @@ namespace SkGpuBlurUtils { * as a renderTargetContext in case the caller wishes to future draw into the result. * Note: one of sigmaX and sigmaY should be non-zero! * @param context The GPU context - * @param srcTexture The source texture to be blurred. + * @param src The source to be blurred. * @param colorSpace Color space of the source (used for the renderTargetContext result, * too). * @param dstBounds The destination bounds, relative to the source texture. @@ -34,7 +34,7 @@ namespace SkGpuBlurUtils { * @return The renderTargetContext containing the blurred result. */ sk_sp GaussianBlur(GrContext* context, - GrTexture* srcTexture, + sk_sp src, sk_sp colorSpace, const SkIRect& dstBounds, const SkIRect* srcBounds, diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp index bf54407..594a94e 100644 --- a/src/effects/SkBlurMaskFilter.cpp +++ b/src/effects/SkBlurMaskFilter.cpp @@ -1135,12 +1135,12 @@ static sk_sp find_or_create_rrect_blur_mask(GrContext* context, rtc->drawRRect(GrNoClip(), std::move(paint), GrAA::kYes, SkMatrix::I(), rrectToDraw, GrStyle::SimpleFill()); - sk_sp srcTexture(rtc->asTexture()); - if (!srcTexture) { + sk_sp srcProxy(sk_ref_sp(rtc->asDeferredTexture())); + if (!srcProxy) { return nullptr; } sk_sp rtc2(SkGpuBlurUtils::GaussianBlur(context, - srcTexture.get(), + std::move(srcProxy), nullptr, SkIRect::MakeWH( size.fWidth, @@ -1498,16 +1498,11 @@ sk_sp SkBlurMaskFilterImpl::filterMaskGPU(GrContext* context, SkScalar xformedSigma = this->computeXformedSigma(ctm); SkASSERT(xformedSigma > 0); - // TODO: defer this further (i.e., push the proxy into GaussianBlur) - GrTexture* src = srcProxy->instantiate(context->textureProvider()); - if (!src) { - return nullptr; - } - // 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); - sk_sp renderTargetContext(SkGpuBlurUtils::GaussianBlur(context, src, + sk_sp renderTargetContext(SkGpuBlurUtils::GaussianBlur(context, + srcProxy, nullptr, clipRect, nullptr, xformedSigma, @@ -1520,7 +1515,7 @@ sk_sp SkBlurMaskFilterImpl::filterMaskGPU(GrContext* context, GrPaint paint; // Blend pathTexture over blurTexture. paint.addCoverageFragmentProcessor( - GrSimpleTextureEffect::Make(src, nullptr, SkMatrix::I())); + GrSimpleTextureEffect::Make(context, std::move(srcProxy), nullptr, SkMatrix::I())); if (kInner_SkBlurStyle == fBlurStyle) { // inner: dst = dst * src paint.setCoverageSetOpXPFactory(SkRegion::kIntersect_Op); diff --git a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp index c5f554f..66aba13 100644 --- a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp +++ b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp @@ -115,12 +115,17 @@ void GrGLConvolutionEffect::onSetData(const GrGLSLProgramDataManager& pdman, } pdman.set2fv(fImageIncrementUni, 1, imageIncrement); if (conv.useBounds()) { - const float* bounds = conv.bounds(); - if (Gr1DKernelEffect::kY_Direction == conv.direction() && - texture.origin() != kTopLeft_GrSurfaceOrigin) { - pdman.set2f(fBoundsUni, 1.0f - bounds[1], 1.0f - bounds[0]); + const int* bounds = conv.bounds(); + if (Gr1DKernelEffect::kX_Direction == conv.direction()) { + SkScalar inv = SkScalarInvert(SkIntToScalar(texture.width())); + pdman.set2f(fBoundsUni, inv * bounds[0], inv * bounds[1]); } else { - pdman.set2f(fBoundsUni, bounds[0], bounds[1]); + SkScalar inv = SkScalarInvert(SkIntToScalar(texture.height())); + if (texture.origin() != kTopLeft_GrSurfaceOrigin) { + pdman.set2f(fBoundsUni, 1.0f - (inv * bounds[1]), 1.0f - (inv * bounds[0])); + } else { + pdman.set2f(fBoundsUni, inv * bounds[1], inv * bounds[0]); + } } } int width = Gr1DKernelEffect::WidthFromRadius(conv.radius()); @@ -144,8 +149,6 @@ void GrGLConvolutionEffect::GenKey(const GrProcessor& processor, const GrShaderC } /////////////////////////////////////////////////////////////////////////////// - - static void fill_in_1D_guassian_kernel(float* kernel, int width, float gaussianSigma, int radius) { const float denom = 1.0f / (2.0f * gaussianSigma * gaussianSigma); @@ -169,7 +172,7 @@ GrGaussianConvolutionFragmentProcessor::GrGaussianConvolutionFragmentProcessor(G int radius, float gaussianSigma, bool useBounds, - float bounds[2]) + int bounds[2]) : INHERITED(texture, direction, radius, ModulationFlags(texture->config())) , fUseBounds(useBounds) { this->initClassID(); @@ -187,7 +190,7 @@ GrGaussianConvolutionFragmentProcessor::GrGaussianConvolutionFragmentProcessor( int radius, float gaussianSigma, bool useBounds, - float bounds[2]) + int bounds[2]) : INHERITED{context, ModulationFlags(proxy->config()), GR_PROXY_MOVE(proxy), @@ -230,16 +233,25 @@ sk_sp GrGaussianConvolutionFragmentProcessor::TestCreate( GrProcessorTestData* d) { int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : GrProcessorUnitTest::kAlphaTextureIdx; - Direction dir = d->fRandom->nextBool() ? kX_Direction : kY_Direction; - int radius = d->fRandom->nextRangeU(1, kMaxKernelRadius); + sk_sp proxy = d->textureProxy(texIdx); bool useBounds = d->fRandom->nextBool(); - float bounds[2]; - for (size_t i = 0; i < SK_ARRAY_COUNT(bounds); ++i) { - bounds[i] = d->fRandom->nextF(); + int bounds[2]; + + Direction dir; + if (d->fRandom->nextBool()) { + dir = kX_Direction; + bounds[0] = d->fRandom->nextRangeU(0, proxy->width()-1); + bounds[1] = d->fRandom->nextRangeU(bounds[0], proxy->width()-1); + } else { + dir = kY_Direction; + bounds[0] = d->fRandom->nextRangeU(0, proxy->height()-1); + bounds[1] = d->fRandom->nextRangeU(bounds[0], proxy->height()-1); } + int radius = d->fRandom->nextRangeU(1, kMaxKernelRadius); float sigma = radius / 3.f; + return GrGaussianConvolutionFragmentProcessor::Make( d->context(), d->textureProxy(texIdx), dir, radius, sigma, useBounds, bounds); } diff --git a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h index b4f5cb7..0bb9c5e 100644 --- a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h +++ b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h @@ -24,7 +24,7 @@ public: int halfWidth, float gaussianSigma, bool useBounds, - float* bounds) { + int* bounds) { return sk_sp(new GrGaussianConvolutionFragmentProcessor( tex, dir, halfWidth, gaussianSigma, useBounds, bounds)); } @@ -35,7 +35,7 @@ public: int halfWidth, float gaussianSigma, bool useBounds, - float* bounds) { + int* bounds) { return sk_sp(new GrGaussianConvolutionFragmentProcessor( context, std::move(proxy), dir, halfWidth, gaussianSigma, useBounds, bounds)); } @@ -44,7 +44,7 @@ public: const float* kernel() const { return fKernel; } - const float* bounds() const { return fBounds; } + const int* bounds() const { return fBounds; } bool useBounds() const { return fUseBounds; } const char* name() const override { return "GaussianConvolution"; } @@ -61,11 +61,11 @@ public: private: /// Convolve with a Gaussian kernel GrGaussianConvolutionFragmentProcessor(GrTexture*, Direction, int halfWidth, - float gaussianSigma, bool useBounds, float bounds[2]); + float gaussianSigma, bool useBounds, int bounds[2]); GrGaussianConvolutionFragmentProcessor(GrContext*, sk_sp, Direction, int halfWidth, float gaussianSigma, bool useBounds, - float bounds[2]); + int bounds[2]); GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; @@ -85,7 +85,7 @@ private: // some of the logic from SkGpuBlurUtils into this class related to radius/sigma calculations. float fKernel[kMaxKernelWidth]; bool fUseBounds; - float fBounds[2]; + int fBounds[2]; typedef Gr1DKernelEffect INHERITED; }; diff --git a/src/gpu/effects/GrProxyMove.h b/src/gpu/effects/GrProxyMove.h index 643e01b..87612f7 100644 --- a/src/gpu/effects/GrProxyMove.h +++ b/src/gpu/effects/GrProxyMove.h @@ -3,8 +3,8 @@ * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. - */ - + */ + #ifndef GrProxyMove_DEFINED #define GrProxyMove_DEFINED -- 2.7.4