diff options
Diffstat (limited to 'src/effects')
-rw-r--r-- | src/effects/SkBlurMask.cpp | 70 | ||||
-rw-r--r-- | src/effects/SkBlurMask.h | 35 | ||||
-rw-r--r-- | src/effects/SkBlurMaskFilter.cpp | 276 |
3 files changed, 34 insertions, 347 deletions
diff --git a/src/effects/SkBlurMask.cpp b/src/effects/SkBlurMask.cpp index f61536e65a..32a3d20d31 100644 --- a/src/effects/SkBlurMask.cpp +++ b/src/effects/SkBlurMask.cpp @@ -671,7 +671,7 @@ static float gaussianIntegral(float x) { return 0.4375f + (-x3 / 6.0f - 3.0f * x2 * 0.25f - 1.125f * x); } -/* ComputeBlurProfile allocates and fills in an array of floating +/* compute_profile allocates and fills in an array of floating point values between 0 and 255 for the profile signature of a blurred half-plane with the given blur radius. Since we're going to be doing screened multiplications (i.e., 1 - (1-x)(1-y)) @@ -682,11 +682,11 @@ static float gaussianIntegral(float x) { memory returned in profile_out. */ -void SkBlurMask::ComputeBlurProfile(SkScalar sigma, uint8_t **profile_out) { +static void compute_profile(SkScalar sigma, unsigned int **profile_out) { int size = SkScalarCeilToInt(6*sigma); int center = size >> 1; - uint8_t *profile = SkNEW_ARRAY(uint8_t, size); + unsigned int *profile = SkNEW_ARRAY(unsigned int, size); float invr = 1.f/(2*sigma); @@ -707,7 +707,7 @@ void SkBlurMask::ComputeBlurProfile(SkScalar sigma, uint8_t **profile_out) { // Implementation adapted from Michael Herf's approach: // http://stereopsis.com/shadowrect/ -uint8_t SkBlurMask::ProfileLookup(const uint8_t *profile, int loc, int blurred_width, int sharp_width) { +static inline unsigned int profile_lookup( unsigned int *profile, int loc, int blurred_width, int sharp_width ) { int dx = SkAbs32(((loc << 1) + 1) - blurred_width) - sharp_width; // how far are we from the original edge? int ox = dx >> 1; if (ox < 0) { @@ -717,30 +717,6 @@ uint8_t SkBlurMask::ProfileLookup(const uint8_t *profile, int loc, int blurred_w return profile[ox]; } -void SkBlurMask::ComputeBlurredScanline(uint8_t *pixels, const uint8_t *profile, - unsigned int width, SkScalar sigma) { - - unsigned int profile_size = SkScalarCeilToInt(6*sigma); - SkAutoTMalloc<uint8_t> horizontalScanline(width); - - unsigned int sw = width - profile_size; - // nearest odd number less than the profile size represents the center - // of the (2x scaled) profile - int center = ( profile_size & ~1 ) - 1; - - int w = sw - center; - - for (unsigned int x = 0 ; x < width ; ++x) { - if (profile_size <= sw) { - pixels[x] = ProfileLookup(profile, x, width, w); - } else { - float span = float(sw)/(2*sigma); - float giX = 1.5f - (x+.5f)/(2*sigma); - pixels[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegral(giX + span))); - } - } -} - bool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src, SkScalar radius, Style style, SkIPoint *margin, SkMask::CreateMode createMode) { @@ -781,10 +757,10 @@ bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst, } return true; } - uint8_t *profile = NULL; + unsigned int *profile = NULL; - ComputeBlurProfile(sigma, &profile); - SkAutoTDeleteArray<uint8_t> ada(profile); + compute_profile(sigma, &profile); + SkAutoTDeleteArray<unsigned int> ada(profile); size_t dstSize = dst->computeImageSize(); if (0 == dstSize) { @@ -798,17 +774,39 @@ bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst, int dstHeight = dst->fBounds.height(); int dstWidth = dst->fBounds.width(); + // nearest odd number less than the profile size represents the center + // of the (2x scaled) profile + int center = ( profile_size & ~1 ) - 1; + + int w = sw - center; + int h = sh - center; + uint8_t *outptr = dp; SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth); - SkAutoTMalloc<uint8_t> verticalScanline(dstHeight); - - ComputeBlurredScanline(horizontalScanline, profile, dstWidth, sigma); - ComputeBlurredScanline(verticalScanline, profile, dstHeight, sigma); + + for (int x = 0 ; x < dstWidth ; ++x) { + if (profile_size <= sw) { + horizontalScanline[x] = profile_lookup(profile, x, dstWidth, w); + } else { + float span = float(sw)/(2*sigma); + float giX = 1.5f - (x+.5f)/(2*sigma); + horizontalScanline[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegral(giX + span))); + } + } for (int y = 0 ; y < dstHeight ; ++y) { + unsigned int profile_y; + if (profile_size <= sh) { + profile_y = profile_lookup(profile, y, dstHeight, h); + } else { + float span = float(sh)/(2*sigma); + float giY = 1.5f - (y+.5f)/(2*sigma); + profile_y = (uint8_t) (255 * (gaussianIntegral(giY) - gaussianIntegral(giY + span))); + } + for (int x = 0 ; x < dstWidth ; x++) { - unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], verticalScanline[y]); + unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], profile_y); *(outptr++) = maskval; } } diff --git a/src/effects/SkBlurMask.h b/src/effects/SkBlurMask.h index f95c110c90..e0b8d54ce1 100644 --- a/src/effects/SkBlurMask.h +++ b/src/effects/SkBlurMask.h @@ -62,41 +62,6 @@ public: SkIPoint* margin = NULL); static SkScalar ConvertRadiusToSigma(SkScalar radius); - - /* Helper functions for analytic rectangle blurs */ - - /** Look up the intensity of the (one dimnensional) blurred half-plane. - @param profile The precomputed 1D blur profile; memory allocated by and managed by - ComputeBlurProfile below. - @param loc the location to look up; The lookup will clamp invalid inputs, but - meaningful data are available between 0 and blurred_width - @param blurred_width The width of the final, blurred rectangle - @param sharp_width The width of the original, unblurred rectangle. - */ - static uint8_t ProfileLookup(const uint8_t* profile, int loc, int blurred_width, int sharp_width); - - /** Allocate memory for and populate the profile of a 1D blurred halfplane. The caller - must free the memory. The amount of memory allocated will be exactly 6*sigma bytes. - @param sigma The standard deviation of the gaussian blur kernel - @param profile_out The location to store the allocated profile curve - */ - - static void ComputeBlurProfile(SkScalar sigma, uint8_t** profile_out); - - /** Compute an entire scanline of a blurred step function. This is a 1D helper that - will produce both the horizontal and vertical profiles of the blurry rectangle. - @param pixels Location to store the resulting pixel data; allocated and managed by caller - @param profile Precomputed blur profile computed by ComputeBlurProfile above. - @param width Size of the pixels array. - @param sigma Standard deviation of the gaussian blur kernel used to compute the profile; - this implicitly gives the size of the pixels array. - */ - - static void ComputeBlurredScanline(uint8_t* pixels, const uint8_t* profile, - unsigned int width, SkScalar sigma); - - - }; #endif diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp index 05f9e88594..14be6a50b3 100644 --- a/src/effects/SkBlurMaskFilter.cpp +++ b/src/effects/SkBlurMaskFilter.cpp @@ -19,10 +19,7 @@ #if SK_SUPPORT_GPU #include "GrContext.h" #include "GrTexture.h" -#include "GrEffect.h" -#include "gl/GrGLEffect.h" #include "effects/GrSimpleTextureEffect.h" -#include "GrTBackendEffectFactory.h" #include "SkGrPixelRef.h" #endif @@ -40,11 +37,6 @@ public: const SkIRect& clipBounds, const SkMatrix& ctm, SkRect* maskRect) const SK_OVERRIDE; - virtual bool directFilterMaskGPU(GrContext* context, - GrPaint* grp, - const SkStrokeRec& strokeRec, - const SkPath& path) const SK_OVERRIDE; - virtual bool filterMaskGPU(GrTexture* src, const SkMatrix& ctm, const SkRect& maskRect, @@ -508,274 +500,6 @@ void SkBlurMaskFilterImpl::flatten(SkFlattenableWriteBuffer& buffer) const { #if SK_SUPPORT_GPU -class GrGLRectBlurEffect; - -class GrRectBlurEffect : public GrEffect { -public: - virtual ~GrRectBlurEffect(); - - static const char* Name() { return "RectBlur"; } - - typedef GrGLRectBlurEffect GLEffect; - - virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; - virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; - - /** - * Create a simple filter effect with custom bicubic coefficients. - */ - static GrEffectRef* Create(GrContext *context, const SkRect& rect, - float sigma) { - GrTexture *horizontalScanline, *verticalScanline; - bool createdScanlines = CreateScanlineTextures(context, sigma, - SkScalarCeilToInt(rect.width()), - SkScalarCeilToInt(rect.height()), - &horizontalScanline, &verticalScanline); - if (!createdScanlines) { - return NULL; - } - AutoEffectUnref effect(SkNEW_ARGS(GrRectBlurEffect, (rect, sigma, - horizontalScanline, verticalScanline))); - return CreateEffectRef(effect); - } - - unsigned int getWidth() const { return fWidth; } - unsigned int getHeight() const { return fHeight; } - float getSigma() const { return fSigma; } - -private: - GrRectBlurEffect(const SkRect& rect, float sigma, - GrTexture *horizontal_scanline, GrTexture *vertical_scanline); - 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); - - unsigned int fWidth, fHeight; - float fSigma; - GrTextureAccess fHorizontalScanlineAccess; - GrTextureAccess fVerticalScanlineAccess; - GrCoordTransform fTransform; - - GR_DECLARE_EFFECT_TEST; - - typedef GrEffect INHERITED; -}; - -class GrGLRectBlurEffect : public GrGLEffect { -public: - GrGLRectBlurEffect(const GrBackendEffectFactory& factory, - const GrDrawEffect&); - virtual void emitCode(GrGLShaderBuilder*, - const GrDrawEffect&, - EffectKey, - const char* outputColor, - const char* inputColor, - const TransformedCoordsArray&, - const TextureSamplerArray&) SK_OVERRIDE; - - virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; - -private: - typedef GrGLUniformManager::UniformHandle UniformHandle; - - UniformHandle fWidthUni; - UniformHandle fHeightUni; - - typedef GrGLEffect INHERITED; -}; - -GrGLRectBlurEffect::GrGLRectBlurEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) - : INHERITED(factory) { -} - -void GrGLRectBlurEffect::emitCode(GrGLShaderBuilder* builder, - const GrDrawEffect&, - EffectKey key, - const char* outputColor, - const char* inputColor, - const TransformedCoordsArray& coords, - const TextureSamplerArray& samplers) { - - SkString texture_coords = builder->ensureFSCoords2D(coords, 0); - - if (inputColor) { - builder->fsCodeAppendf("\tvec4 src=%s;\n", inputColor); - } else { - 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("\tfloat final = (horiz*vert).r;\n"); - builder->fsCodeAppendf("\t%s = final*src;\n", outputColor); -} - -void GrGLRectBlurEffect::setData(const GrGLUniformManager& uman, - const GrDrawEffect& drawEffect) { -} - -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 = SkScalarFloorToInt(6*sigma); - - texDesc.fWidth = width; - texDesc.fHeight = 1; - texDesc.fConfig = kAlpha_8_GrPixelConfig; - - static const GrCacheID::Domain gBlurProfileDomain = GrCacheID::GenerateDomain(); - 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); - - uint8_t *profile = NULL; - SkAutoTDeleteArray<uint8_t> ada(profile); - - *horizontalScanline = context->findAndRefTexture(texDesc, horizontalCacheID, ¶ms); - - if (NULL == *horizontalScanline) { - - SkBlurMask::ComputeBlurProfile(sigma, &profile); - - SkAutoTMalloc<uint8_t> horizontalPixels(width); - SkBlurMask::ComputeBlurredScanline(horizontalPixels, profile, width, sigma); - - *horizontalScanline = context->createTexture(¶ms, texDesc, horizontalCacheID, - horizontalPixels, 0); - - 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); - } - - SkAutoTMalloc<uint8_t> verticalPixels(height); - SkBlurMask::ComputeBlurredScanline(verticalPixels, profile, height, sigma); - - *verticalScanline = context->createTexture(¶ms, texDesc, verticalCacheID, - verticalPixels, 0); - - if (NULL == *verticalScanline) { - return false; - } - - } - return true; -} - -GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma, - GrTexture *horizontal_scanline, GrTexture *vertical_scanline) - : INHERITED(), - fWidth(horizontal_scanline->width()), - fHeight(vertical_scanline->width()), - fSigma(sigma), - fHorizontalScanlineAccess(horizontal_scanline), - fVerticalScanlineAccess(vertical_scanline) { - SkMatrix mat; - mat.setRectToRect(rect, SkRect::MakeWH(1,1), SkMatrix::kFill_ScaleToFit); - fTransform = GrCoordTransform(kLocal_GrCoordSet, mat); - this->addTextureAccess(&fHorizontalScanlineAccess); - this->addTextureAccess(&fVerticalScanlineAccess); - this->addCoordTransform(&fTransform); -} - -GrRectBlurEffect::~GrRectBlurEffect() { -} - -const GrBackendEffectFactory& GrRectBlurEffect::getFactory() const { - return GrTBackendEffectFactory<GrRectBlurEffect>::getInstance(); -} - -bool GrRectBlurEffect::onIsEqual(const GrEffect& sBase) const { - const GrRectBlurEffect& s = CastEffect<GrRectBlurEffect>(sBase); - return this->getWidth() == s.getWidth() && - this->getHeight() == s.getHeight() && - this->getSigma() == s.getSigma(); -} - -void GrRectBlurEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { - *validFlags = 0; - return; -} - -GR_DEFINE_EFFECT_TEST(GrRectBlurEffect); - -GrEffectRef* GrRectBlurEffect::TestCreate(SkRandom* random, - GrContext* context, - const GrDrawTargetCaps&, - GrTexture**) { - float sigma = random->nextRangeF(3,8); - float width = random->nextRangeF(200,300); - float height = random->nextRangeF(200,300); - return GrRectBlurEffect::Create(context, SkRect::MakeWH(width, height), sigma); -} - - -bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrContext* context, - GrPaint* grp, - const SkStrokeRec& strokeRec, - const SkPath& path) const { - if (fBlurStyle != SkBlurMaskFilter::kNormal_BlurStyle) { - return false; - } - - SkRect rect; - if (!path.isRect(&rect)) { - return false; - } - - if (!strokeRec.isFillStyle()) { - return false; - } - - SkMatrix ctm = context->getMatrix(); - SkScalar xformedSigma = this->computeXformedSigma(ctm); - rect.outset(3*xformedSigma, 3*xformedSigma); - - SkAutoTUnref<GrEffectRef> effect(GrRectBlurEffect::Create( - context, rect, xformedSigma)); - if (!effect) { - return false; - } - - GrContext::AutoMatrix am; - if (!am.setIdentity(context, grp)) { - return false; - } - - - grp->addCoverageEffect(effect); - - context->drawRect(*grp, rect); - return true; -} - bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds, const SkIRect& clipBounds, const SkMatrix& ctm, |