| Index: src/effects/SkBlurMaskFilter.cpp
|
| diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
|
| index 778332ffc2cf2337f72be974b65254451f7e24ab..e808885dddbe8a3143db1a7973dce6b11dd6aa28 100644
|
| --- a/src/effects/SkBlurMaskFilter.cpp
|
| +++ b/src/effects/SkBlurMaskFilter.cpp
|
| @@ -557,38 +557,40 @@ public:
|
| */
|
| static GrEffectRef* Create(GrContext *context, const SkRect& rect,
|
| float sigma) {
|
| - 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.
|
| -
|
| + GrTexture *horizontalScanline = NULL, *verticalScanline = NULL;
|
| + bool createdScanlines = CreateScanlineTextures(context, sigma,
|
| + SkScalarCeilToInt(rect.width()),
|
| + SkScalarCeilToInt(rect.height()),
|
| + &horizontalScanline, &verticalScanline);
|
| + SkAutoTUnref<GrTexture> hunref(horizontalScanline), vunref(verticalScanline);
|
| + if (!createdScanlines) {
|
| return NULL;
|
| }
|
| -
|
| - bool createdBlurProfileTexture = CreateBlurProfileTexture(context, sigma, &blurProfileTexture);
|
| - SkAutoTUnref<GrTexture> hunref(blurProfileTexture);
|
| - if (!createdBlurProfileTexture) {
|
| - return NULL;
|
| - }
|
| - AutoEffectUnref effect(SkNEW_ARGS(GrRectBlurEffect, (rect, sigma, blurProfileTexture)));
|
| + AutoEffectUnref effect(SkNEW_ARGS(GrRectBlurEffect, (rect, sigma,
|
| + horizontalScanline, verticalScanline)));
|
| return CreateEffectRef(effect);
|
| }
|
|
|
| - const SkRect& getRect() const { return fRect; }
|
| + unsigned int getWidth() const { return fWidth; }
|
| + unsigned int getHeight() const { return fHeight; }
|
| float getSigma() const { return fSigma; }
|
| + const GrCoordTransform& getTransform() const { return fTransform; }
|
|
|
| private:
|
| - GrRectBlurEffect(const SkRect& rect, float sigma, GrTexture *blur_profile);
|
| + GrRectBlurEffect(const SkRect& rect, float sigma,
|
| + GrTexture *horizontal_scanline, GrTexture *vertical_scanline);
|
| virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
|
|
|
| - static bool CreateBlurProfileTexture(GrContext *context, float sigma,
|
| - GrTexture **blurProfileTexture);
|
| + static bool CreateScanlineTextures(GrContext *context, float sigma,
|
| + unsigned int width, unsigned int height,
|
| + GrTexture **horizontalScanline,
|
| + GrTexture **verticalScanline);
|
|
|
| - SkRect fRect;
|
| - float fSigma;
|
| - GrTextureAccess fBlurProfileAccess;
|
| + unsigned int fWidth, fHeight;
|
| + float fSigma;
|
| + GrTextureAccess fHorizontalScanlineAccess;
|
| + GrTextureAccess fVerticalScanlineAccess;
|
| + GrCoordTransform fTransform;
|
|
|
| GR_DECLARE_EFFECT_TEST;
|
|
|
| @@ -612,31 +614,16 @@ public:
|
| private:
|
| typedef GrGLUniformManager::UniformHandle UniformHandle;
|
|
|
| - UniformHandle fProxyRectUniform;
|
| - UniformHandle fProfileSizeUniform;
|
| + UniformHandle fWidthUni;
|
| + UniformHandle fHeightUni;
|
|
|
| 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("\t\tfloat coord = (0.5 * (abs(2.0*%s - %s) - %s))/%s;\n",
|
| - loc, blurred_width, sharp_width, profileSize);
|
| - builder->fsCodeAppendf("\t\t%s = ", output);
|
| - builder->fsAppendTextureLookup(sampler, "vec2(coord,0.5)");
|
| - builder->fsCodeAppend(".a;\n");
|
| -}
|
| -
|
| void GrGLRectBlurEffect::emitCode(GrGLShaderBuilder* builder,
|
| const GrDrawEffect&,
|
| EffectKey key,
|
| @@ -645,19 +632,7 @@ void GrGLRectBlurEffect::emitCode(GrGLShaderBuilder* builder,
|
| const TransformedCoordsArray& coords,
|
| const TextureSamplerArray& samplers) {
|
|
|
| - 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();
|
| + SkString texture_coords = builder->ensureFSCoords2D(coords, 0);
|
|
|
| if (inputColor) {
|
| builder->fsCodeAppendf("\tvec4 src=%s;\n", inputColor);
|
| @@ -665,46 +640,31 @@ void GrGLRectBlurEffect::emitCode(GrGLShaderBuilder* builder,
|
| builder->fsCodeAppendf("\tvec4 src=vec4(1)\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 horiz_lookup;\n");
|
| - builder->fsCodeAppendf("\tif (%s <= smallDims.x) {\n", profileSizeName);
|
| - OutputRectBlurProfileLookup(builder, samplers[0], "horiz_lookup", profileSizeName, "translatedPos.x", "width", "wh.x");
|
| - builder->fsCodeAppendf("\t}\n");
|
| -
|
| - builder->fsCodeAppendf("\tfloat vert_lookup;\n");
|
| - builder->fsCodeAppendf("\tif (%s <= smallDims.y) {\n", profileSizeName);
|
| - OutputRectBlurProfileLookup(builder, samplers[0], "vert_lookup", profileSizeName, "translatedPos.y", "height", "wh.y");
|
| - builder->fsCodeAppendf("\t}\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("\tfloat final = 1.0 - horiz_lookup * vert_lookup;\n");
|
| -
|
| - builder->fsCodeAppendf("\t%s = vec4(final, final, final, 1.0);\n", outputColor );
|
| + builder->fsCodeAppendf("\tfloat final = (horiz*vert).r;\n");
|
| + builder->fsCodeAppendf("\t%s = final*src;\n", outputColor);
|
| }
|
|
|
| void GrGLRectBlurEffect::setData(const GrGLUniformManager& uman,
|
| - const GrDrawEffect& drawEffect) {
|
| - const GrRectBlurEffect& rbe = drawEffect.castEffect<GrRectBlurEffect>();
|
| - SkRect rect = rbe.getRect();
|
| -
|
| - uman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
|
| - uman.set1f(fProfileSizeUniform, SkScalarCeilToScalar(6*rbe.getSigma()));
|
| + const GrDrawEffect& drawEffect) {
|
| }
|
|
|
| -bool GrRectBlurEffect::CreateBlurProfileTexture(GrContext *context, float sigma,
|
| - GrTexture **blurProfileTexture) {
|
| +bool GrRectBlurEffect::CreateScanlineTextures(GrContext *context, float sigma,
|
| + unsigned int width, unsigned int height,
|
| + GrTexture **horizontalScanline,
|
| + GrTexture **verticalScanline) {
|
| GrTextureParams params;
|
| GrTextureDesc texDesc;
|
|
|
| - unsigned int profile_size = SkScalarCeilToInt(6*sigma);
|
| + unsigned int profile_size = SkScalarFloorToInt(6*sigma);
|
|
|
| - texDesc.fWidth = profile_size;
|
| + texDesc.fWidth = width;
|
| texDesc.fHeight = 1;
|
| texDesc.fConfig = kAlpha_8_GrPixelConfig;
|
|
|
| @@ -712,38 +672,73 @@ bool GrRectBlurEffect::CreateBlurProfileTexture(GrContext *context, float sigma,
|
| GrCacheID::Key key;
|
| memset(&key, 0, sizeof(key));
|
| key.fData32[0] = profile_size;
|
| - key.fData32[1] = 1;
|
| - GrCacheID blurProfileKey(gBlurProfileDomain, key);
|
| + key.fData32[1] = width;
|
| + key.fData32[2] = 1;
|
| + GrCacheID horizontalCacheID(gBlurProfileDomain, key);
|
|
|
| uint8_t *profile = NULL;
|
| SkAutoTDeleteArray<uint8_t> ada(NULL);
|
|
|
| - *blurProfileTexture = context->findAndRefTexture(texDesc, blurProfileKey, ¶ms);
|
| + *horizontalScanline = context->findAndRefTexture(texDesc, horizontalCacheID, ¶ms);
|
|
|
| - if (NULL == *blurProfileTexture) {
|
| + if (NULL == *horizontalScanline) {
|
|
|
| SkBlurMask::ComputeBlurProfile(sigma, &profile);
|
| ada.reset(profile);
|
|
|
| - *blurProfileTexture = context->createTexture(¶ms, texDesc, blurProfileKey,
|
| - profile, 0);
|
| + SkAutoTMalloc<uint8_t> horizontalPixels(width);
|
| + SkBlurMask::ComputeBlurredScanline(horizontalPixels, profile, width, sigma);
|
| +
|
| + *horizontalScanline = context->createTexture(¶ms, texDesc, horizontalCacheID,
|
| + horizontalPixels, 0);
|
|
|
| - if (NULL == *blurProfileTexture) {
|
| + if (NULL == *horizontalScanline) {
|
| 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<uint8_t> 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 *blur_profile)
|
| + GrTexture *horizontal_scanline, GrTexture *vertical_scanline)
|
| : INHERITED(),
|
| - fRect(rect),
|
| + fWidth(horizontal_scanline->width()),
|
| + fHeight(vertical_scanline->width()),
|
| fSigma(sigma),
|
| - fBlurProfileAccess(blur_profile) {
|
| - this->addTextureAccess(&fBlurProfileAccess);
|
| - this->setWillReadFragmentPosition();
|
| + 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);
|
| }
|
|
|
| GrRectBlurEffect::~GrRectBlurEffect() {
|
| @@ -755,7 +750,10 @@ const GrBackendEffectFactory& GrRectBlurEffect::getFactory() const {
|
|
|
| bool GrRectBlurEffect::onIsEqual(const GrEffect& sBase) const {
|
| const GrRectBlurEffect& s = CastEffect<GrRectBlurEffect>(sBase);
|
| - return this->getSigma() == s.getSigma();
|
| + return this->getWidth() == s.getWidth() &&
|
| + this->getHeight() == s.getHeight() &&
|
| + this->getSigma() == s.getSigma() &&
|
| + this->getTransform() == s.getTransform();
|
| }
|
|
|
| void GrRectBlurEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
|
| @@ -795,9 +793,7 @@ bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrContext* context,
|
|
|
| SkMatrix ctm = context->getMatrix();
|
| SkScalar xformedSigma = this->computeXformedSigma(ctm);
|
| -
|
| - int pad=SkScalarCeilToInt(6*xformedSigma)/2;
|
| - rect.outset(SkIntToScalar(pad), SkIntToScalar(pad));
|
| + rect.outset(3*xformedSigma, 3*xformedSigma);
|
|
|
| SkAutoTUnref<GrEffectRef> effect(GrRectBlurEffect::Create(
|
| context, rect, xformedSigma));
|
| @@ -810,6 +806,7 @@ bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrContext* context,
|
| return false;
|
| }
|
|
|
| +
|
| grp->addCoverageEffect(effect);
|
|
|
| context->drawRect(*grp, rect);
|
|
|