From 4a24cd8ff41a8b3d292d60e4351a631240a7ed75 Mon Sep 17 00:00:00 2001 From: humper Date: Tue, 17 Jun 2014 13:39:29 -0700 Subject: Fifth attempt to land faster rect blur. Remove unnecessary conditionals from the shader. approved over in https://codereview.chromium.org/331863006/; reuploading because it had the wrong base url BUG=skia:2095 R=bsalomon@google.com TBR=bsalomon Author: humper@google.com Review URL: https://codereview.chromium.org/341543005 --- src/effects/SkBlurMaskFilter.cpp | 186 +++++++++++++++++++-------------------- src/gpu/gl/GrGLShaderBuilder.cpp | 2 +- 2 files changed, 93 insertions(+), 95 deletions(-) (limited to 'src') diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp index e808885ddd..fca38a1eaa 100644 --- a/src/effects/SkBlurMaskFilter.cpp +++ b/src/effects/SkBlurMaskFilter.cpp @@ -557,40 +557,38 @@ public: */ static GrEffectRef* Create(GrContext *context, const SkRect& rect, float sigma) { - GrTexture *horizontalScanline = NULL, *verticalScanline = NULL; - bool createdScanlines = CreateScanlineTextures(context, sigma, - SkScalarCeilToInt(rect.width()), - SkScalarCeilToInt(rect.height()), - &horizontalScanline, &verticalScanline); - SkAutoTUnref hunref(horizontalScanline), vunref(verticalScanline); - if (!createdScanlines) { + GrTexture *blurProfileTexture = NULL; + int doubleProfileSize = SkScalarCeilToInt(12*sigma); + + if (doubleProfileSize >= rect.width() || doubleProfileSize >= rect.height()) { + // if the blur sigma is too large so the gaussian overlaps the whole + // rect in either direction, fall back to CPU path for now. + return NULL; } - AutoEffectUnref effect(SkNEW_ARGS(GrRectBlurEffect, (rect, sigma, - horizontalScanline, verticalScanline))); + + bool createdBlurProfileTexture = CreateBlurProfileTexture(context, sigma, &blurProfileTexture); + SkAutoTUnref hunref(blurProfileTexture); + if (!createdBlurProfileTexture) { + return NULL; + } + AutoEffectUnref effect(SkNEW_ARGS(GrRectBlurEffect, (rect, sigma, blurProfileTexture))); return CreateEffectRef(effect); } - unsigned int getWidth() const { return fWidth; } - unsigned int getHeight() const { return fHeight; } + const SkRect& getRect() const { return fRect; } float getSigma() const { return fSigma; } - const GrCoordTransform& getTransform() const { return fTransform; } private: - GrRectBlurEffect(const SkRect& rect, float sigma, - GrTexture *horizontal_scanline, GrTexture *vertical_scanline); + GrRectBlurEffect(const SkRect& rect, float sigma, GrTexture *blur_profile); virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE; - static bool CreateScanlineTextures(GrContext *context, float sigma, - unsigned int width, unsigned int height, - GrTexture **horizontalScanline, - GrTexture **verticalScanline); + static bool CreateBlurProfileTexture(GrContext *context, float sigma, + GrTexture **blurProfileTexture); - unsigned int fWidth, fHeight; - float fSigma; - GrTextureAccess fHorizontalScanlineAccess; - GrTextureAccess fVerticalScanlineAccess; - GrCoordTransform fTransform; + SkRect fRect; + float fSigma; + GrTextureAccess fBlurProfileAccess; GR_DECLARE_EFFECT_TEST; @@ -614,16 +612,34 @@ public: private: typedef GrGLUniformManager::UniformHandle UniformHandle; - UniformHandle fWidthUni; - UniformHandle fHeightUni; + UniformHandle fProxyRectUniform; + UniformHandle fProfileSizeUniform; typedef GrGLEffect INHERITED; }; + + GrGLRectBlurEffect::GrGLRectBlurEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) : INHERITED(factory) { } +void OutputRectBlurProfileLookup(GrGLShaderBuilder* builder, + const GrGLShaderBuilder::TextureSampler& sampler, + const char *output, + const char *profileSize, const char *loc, + const char *blurred_width, + const char *sharp_width) { + builder->fsCodeAppendf("\tfloat %s;\n", output); + builder->fsCodeAppendf("\t\t{\n"); + builder->fsCodeAppendf("\t\t\tfloat coord = (0.5 * (abs(2.0*%s - %s) - %s))/%s;\n", + loc, blurred_width, sharp_width, profileSize); + builder->fsCodeAppendf("\t\t\t%s = ", output); + builder->fsAppendTextureLookup(sampler, "vec2(coord,0.5)"); + builder->fsCodeAppend(".a;\n"); + builder->fsCodeAppendf("\t\t}\n"); +} + void GrGLRectBlurEffect::emitCode(GrGLShaderBuilder* builder, const GrDrawEffect&, EffectKey key, @@ -632,7 +648,19 @@ void GrGLRectBlurEffect::emitCode(GrGLShaderBuilder* builder, const TransformedCoordsArray& coords, const TextureSamplerArray& samplers) { - SkString texture_coords = builder->ensureFSCoords2D(coords, 0); + const char *rectName; + const char *profileSizeName; + + fProxyRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, + kVec4f_GrSLType, + "proxyRect", + &rectName); + fProfileSizeUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, + kFloat_GrSLType, + "profileSize", + &profileSizeName); + + const char *fragmentPos = builder->fragmentPosition(); if (inputColor) { builder->fsCodeAppendf("\tvec4 src=%s;\n", inputColor); @@ -640,31 +668,38 @@ void GrGLRectBlurEffect::emitCode(GrGLShaderBuilder* builder, builder->fsCodeAppendf("\tvec4 src=vec4(1)\n;"); } - builder->fsCodeAppendf("\tvec4 horiz = "); - builder->fsAppendTextureLookup( samplers[0], texture_coords.c_str() ); - builder->fsCodeAppendf(";\n"); - builder->fsCodeAppendf("\tvec4 vert = "); - builder->fsAppendTextureLookup( samplers[1], texture_coords.c_str() ); - builder->fsCodeAppendf(";\n"); + builder->fsCodeAppendf("\tvec2 translatedPos = %s.xy - %s.xy;\n", fragmentPos, rectName ); + builder->fsCodeAppendf("\tfloat width = %s.z - %s.x;\n", rectName, rectName); + builder->fsCodeAppendf("\tfloat height = %s.w - %s.y;\n", rectName, rectName); + + builder->fsCodeAppendf("\tvec2 smallDims = vec2(width - %s, height-%s);\n", profileSizeName, profileSizeName); + builder->fsCodeAppendf("\tfloat center = 2.0 * floor(%s/2.0 + .25) - 1.0;\n", profileSizeName); + builder->fsCodeAppendf("\tvec2 wh = smallDims - vec2(center,center);\n"); - builder->fsCodeAppendf("\tfloat final = (horiz*vert).r;\n"); - builder->fsCodeAppendf("\t%s = final*src;\n", outputColor); + OutputRectBlurProfileLookup(builder, samplers[0], "horiz_lookup", profileSizeName, "translatedPos.x", "width", "wh.x"); + OutputRectBlurProfileLookup(builder, samplers[0], "vert_lookup", profileSizeName, "translatedPos.y", "height", "wh.y"); + + builder->fsCodeAppendf("\tfloat final = horiz_lookup * vert_lookup;\n"); + builder->fsCodeAppendf("\t%s = src * vec4(final);\n", outputColor ); } void GrGLRectBlurEffect::setData(const GrGLUniformManager& uman, - const GrDrawEffect& drawEffect) { + const GrDrawEffect& drawEffect) { + const GrRectBlurEffect& rbe = drawEffect.castEffect(); + SkRect rect = rbe.getRect(); + + uman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); + uman.set1f(fProfileSizeUniform, SkScalarCeilToScalar(6*rbe.getSigma())); } -bool GrRectBlurEffect::CreateScanlineTextures(GrContext *context, float sigma, - unsigned int width, unsigned int height, - GrTexture **horizontalScanline, - GrTexture **verticalScanline) { +bool GrRectBlurEffect::CreateBlurProfileTexture(GrContext *context, float sigma, + GrTexture **blurProfileTexture) { GrTextureParams params; GrTextureDesc texDesc; - unsigned int profile_size = SkScalarFloorToInt(6*sigma); + unsigned int profile_size = SkScalarCeilToInt(6*sigma); - texDesc.fWidth = width; + texDesc.fWidth = profile_size; texDesc.fHeight = 1; texDesc.fConfig = kAlpha_8_GrPixelConfig; @@ -672,73 +707,38 @@ bool GrRectBlurEffect::CreateScanlineTextures(GrContext *context, float sigma, GrCacheID::Key key; memset(&key, 0, sizeof(key)); key.fData32[0] = profile_size; - key.fData32[1] = width; - key.fData32[2] = 1; - GrCacheID horizontalCacheID(gBlurProfileDomain, key); + key.fData32[1] = 1; + GrCacheID blurProfileKey(gBlurProfileDomain, key); uint8_t *profile = NULL; SkAutoTDeleteArray ada(NULL); - *horizontalScanline = context->findAndRefTexture(texDesc, horizontalCacheID, ¶ms); + *blurProfileTexture = context->findAndRefTexture(texDesc, blurProfileKey, ¶ms); - if (NULL == *horizontalScanline) { + if (NULL == *blurProfileTexture) { SkBlurMask::ComputeBlurProfile(sigma, &profile); ada.reset(profile); - SkAutoTMalloc horizontalPixels(width); - SkBlurMask::ComputeBlurredScanline(horizontalPixels, profile, width, sigma); - - *horizontalScanline = context->createTexture(¶ms, texDesc, horizontalCacheID, - horizontalPixels, 0); + *blurProfileTexture = context->createTexture(¶ms, texDesc, blurProfileKey, + profile, 0); - if (NULL == *horizontalScanline) { + if (NULL == *blurProfileTexture) { return false; } } - texDesc.fWidth = 1; - texDesc.fHeight = height; - key.fData32[1] = 1; - key.fData32[2] = height; - GrCacheID verticalCacheID(gBlurProfileDomain, key); - - *verticalScanline = context->findAndRefTexture(texDesc, verticalCacheID, ¶ms); - if (NULL == *verticalScanline) { - if (NULL == profile) { - SkBlurMask::ComputeBlurProfile(sigma, &profile); - ada.reset(profile); - } - - SkAutoTMalloc verticalPixels(height); - SkBlurMask::ComputeBlurredScanline(verticalPixels, profile, height, sigma); - - *verticalScanline = context->createTexture(¶ms, texDesc, verticalCacheID, - verticalPixels, 0); - - if (NULL == *verticalScanline) { - SkSafeSetNull(*horizontalScanline); - return false; - } - - } return true; } GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma, - GrTexture *horizontal_scanline, GrTexture *vertical_scanline) + GrTexture *blur_profile) : INHERITED(), - fWidth(horizontal_scanline->width()), - fHeight(vertical_scanline->width()), + fRect(rect), fSigma(sigma), - fHorizontalScanlineAccess(horizontal_scanline), - fVerticalScanlineAccess(vertical_scanline) { - SkMatrix mat; - mat.setRectToRect(rect, SkRect::MakeWH(1,1), SkMatrix::kFill_ScaleToFit); - fTransform.reset(kLocal_GrCoordSet, mat); - this->addTextureAccess(&fHorizontalScanlineAccess); - this->addTextureAccess(&fVerticalScanlineAccess); - this->addCoordTransform(&fTransform); + fBlurProfileAccess(blur_profile) { + this->addTextureAccess(&fBlurProfileAccess); + this->setWillReadFragmentPosition(); } GrRectBlurEffect::~GrRectBlurEffect() { @@ -750,10 +750,7 @@ const GrBackendEffectFactory& GrRectBlurEffect::getFactory() const { bool GrRectBlurEffect::onIsEqual(const GrEffect& sBase) const { const GrRectBlurEffect& s = CastEffect(sBase); - return this->getWidth() == s.getWidth() && - this->getHeight() == s.getHeight() && - this->getSigma() == s.getSigma() && - this->getTransform() == s.getTransform(); + return this->getSigma() == s.getSigma() && this->getRect() == s.getRect(); } void GrRectBlurEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { @@ -793,7 +790,9 @@ bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrContext* context, SkMatrix ctm = context->getMatrix(); SkScalar xformedSigma = this->computeXformedSigma(ctm); - rect.outset(3*xformedSigma, 3*xformedSigma); + + int pad=SkScalarCeilToInt(6*xformedSigma)/2; + rect.outset(SkIntToScalar(pad), SkIntToScalar(pad)); SkAutoTUnref effect(GrRectBlurEffect::Create( context, rect, xformedSigma)); @@ -806,7 +805,6 @@ bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrContext* context, return false; } - grp->addCoverageEffect(effect); context->drawRect(*grp, rect); diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp index f8f810ff78..4b2778c503 100644 --- a/src/gpu/gl/GrGLShaderBuilder.cpp +++ b/src/gpu/gl/GrGLShaderBuilder.cpp @@ -216,7 +216,7 @@ bool GrGLShaderBuilder::genProgram(const GrEffectStage* colorStages[], if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCoverageOutput) { // Get (1-A) into coeff coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inputColor.a()); - } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == + } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == header.fCoverageOutput){ // Get (1-RGBA) into coeff coeff = GrGLSLExpr4(1) - inputColor; -- cgit v1.2.3