Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(514)

Unified Diff: src/effects/SkBlurMaskFilter.cpp

Issue 119343003: Fast blurred rectangles on GPU (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: cleanup patch + check for fill vs. stroke Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/effects/SkBlurMaskFilter.cpp
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index d2c43d719bcd707ddd58a3adacfe27b6a1015476..e8a23e1873752ae4e3d155097d7819428c86b63f 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -19,7 +19,10 @@
#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
@@ -37,6 +40,11 @@ public:
const SkIRect& clipBounds,
const SkMatrix& ctm,
SkRect* maskRect) const SK_OVERRIDE;
+ virtual bool directFilterMaskGPU(GrContext *context,
+ GrPaint *grp,
+ bool doFill,
+ SkPath *path) const SK_OVERRIDE;
+
virtual bool filterMaskGPU(GrTexture* src,
const SkRect& maskRect,
GrTexture** result,
@@ -502,6 +510,257 @@ 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, unsigned int width, unsigned int height,
+ float sigma) {
+ GrTexture *horizontalScanline, *verticalScanline;
+ bool createdScanlines = CreateScanlineTextures(context, sigma, width, height,
+ &horizontalScanline, &verticalScanline);
+ if (!createdScanlines) {
+ return NULL;
+ }
+ AutoEffectUnref effect(SkNEW_ARGS(GrRectBlurEffect, (width, height, sigma,
+ horizontalScanline, verticalScanline)));
+ return CreateEffectRef(effect);
+ }
+
+ unsigned int getWidth() const { return fWidth; }
+ unsigned int getHeight() const { return fHeight; }
+ unsigned int getSigma() const { return fSigma; }
+
+private:
+ GrRectBlurEffect(unsigned int width, unsigned int height, 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 fTrivialTransform;
+
+ 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);
+
+ 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*%s;\n", outputColor, inputColor);
bsalomon 2013/12/21 02:50:09 There is a weird case where inputColor may be NULL
+}
+
+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 = 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, &params);
+
+ if (NULL == *horizontalScanline) {
+
+ SkBlurMask::ComputeBlurProfile(sigma, &profile);
+
+ SkAutoTMalloc<uint8_t> horizontalPixels(width);
+ SkBlurMask::ComputeBlurredScanline(horizontalPixels, profile, profile_size, width, sigma);
+
+ *horizontalScanline = context->createTexture(&params, texDesc, horizontalCacheID,
+ horizontalPixels, 0);
+
+ if (NULL == *horizontalScanline) {
+ return false;
+ }
+ }
+
+ texDesc.fWidth = 1;
+ texDesc.fHeight = height;
+ key.fData32[1] = 1;
bsalomon 2013/12/21 02:50:09 This guy doesn't also need the profile size?
humper 2013/12/23 13:26:58 He's already got it; I'm only overwriting the widt
+ key.fData32[2] = height;
+ GrCacheID verticalCacheID(gBlurProfileDomain, key);
+
+ *verticalScanline = context->findAndRefTexture(texDesc, verticalCacheID, &params);
+ if (NULL == *verticalScanline) {
+ if (NULL == profile) {
+ SkBlurMask::ComputeBlurProfile(sigma, &profile);
+ }
+
+ SkAutoTMalloc<uint8_t> verticalPixels(height);
+ SkBlurMask::ComputeBlurredScanline(verticalPixels, profile, profile_size, height, sigma);
+
+ *verticalScanline = context->createTexture(&params, texDesc, verticalCacheID,
+ verticalPixels, 0);
+
+ if (NULL == *verticalScanline) {
+ return false;
+ }
+
+ }
+ return true;
+}
+
+GrRectBlurEffect::GrRectBlurEffect(unsigned int width, unsigned int height, float sigma,
+ GrTexture *horizontal_scanline, GrTexture *vertical_scanline)
+ : INHERITED(),
+ fWidth(width),
+ fHeight(height),
+ fSigma(sigma),
+ fHorizontalScanlineAccess(horizontal_scanline),
+ fVerticalScanlineAccess(vertical_scanline),
+ fTrivialTransform(kLocal_GrCoordSet, SkMatrix()) {
bsalomon 2013/12/21 02:50:09 I thought SkMatrix didn't have a default cons and
humper 2013/12/23 13:26:58 Has to be the identity. I believe that's the defa
+ this->addTextureAccess(&fHorizontalScanlineAccess);
+ this->addTextureAccess(&fVerticalScanlineAccess);
+ this->addCoordTransform(&fTrivialTransform);
+}
+
+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 {
+ // FIXME: Perhaps we can do better.
bsalomon 2013/12/21 02:50:09 I think this comment can be removed. It's not obvi
+ *validFlags = 0;
+ return;
+}
+
+GR_DEFINE_EFFECT_TEST(GrRectBlurEffect);
+
+GrEffectRef* GrRectBlurEffect::TestCreate(SkRandom* random,
+ GrContext* context,
+ const GrDrawTargetCaps&,
+ GrTexture**) {
+ float sigma = random->nextRangeF(3,8);
+ unsigned int width = random->nextRangeU(200,300);
+ unsigned int height = random->nextRangeU(200,300);
+ return GrRectBlurEffect::Create(context, width, height, sigma);
+}
+
+
+bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrContext *context,
+ GrPaint *grp,
+ bool doFill,
+ SkPath *path) const {
+ GrContext::AutoMatrix am;
+ if (!am.setIdentity(context, grp)) {
+ return false;
+ }
+
+ SkRect rect;
+ if (!path->isRect(&rect)) {
+ return false;
+ }
+
+ if (!doFill) {
+ return false;
+ }
+
+ rect.outset(3*fSigma, 3*fSigma);
+
+ SkAutoTUnref<GrEffectRef> effect(GrRectBlurEffect::Create(
+ context, rect.width(), rect.height(), fSigma));
+ if (!effect) {
+ return false;
+ }
+ grp->addCoverageEffect(effect);
+
+ context->drawRectToRect(*grp, rect, SkRect::MakeWH(1,1));
+ return true;
+}
+
bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds,
const SkIRect& clipBounds,
const SkMatrix& ctm,

Powered by Google App Engine
This is Rietveld 408576698