Index: src/effects/SkGpuBlurUtils.cpp |
=================================================================== |
--- src/effects/SkGpuBlurUtils.cpp (revision 0) |
+++ src/effects/SkGpuBlurUtils.cpp (revision 0) |
@@ -0,0 +1,187 @@ |
+/* |
+ * Copyright 2013 Google Inc. |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+#include "SkGpuBlurUtils.h" |
+ |
+#include "SkRect.h" |
+ |
+#if SK_SUPPORT_GPU |
+#include "effects/GrConvolutionEffect.h" |
+#include "GrContext.h" |
+#endif |
+ |
+namespace SkGpuBlurUtils { |
+ |
+#if SK_SUPPORT_GPU |
+ |
+#define MAX_BLUR_SIGMA 4.0f |
+ |
+static void scale_rect(SkRect* rect, float xScale, float yScale) { |
+ rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale)); |
+ rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale)); |
+ rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale)); |
+ rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale)); |
+} |
+ |
+static float adjust_sigma(float sigma, int *scaleFactor, int *radius) { |
+ *scaleFactor = 1; |
+ while (sigma > MAX_BLUR_SIGMA) { |
+ *scaleFactor *= 2; |
+ sigma *= 0.5f; |
+ } |
+ *radius = static_cast<int>(ceilf(sigma * 3.0f)); |
+ GrAssert(*radius <= GrConvolutionEffect::kMaxKernelRadius); |
+ return sigma; |
+} |
+ |
+static void convolve_gaussian(GrContext* context, |
+ GrTexture* texture, |
+ const SkRect& rect, |
+ float sigma, |
+ int radius, |
+ Gr1DKernelEffect::Direction direction) { |
+ GrPaint paint; |
+ |
+ SkAutoTUnref<GrEffectRef> conv(GrConvolutionEffect::CreateGaussian(texture, |
+ direction, |
+ radius, |
+ sigma)); |
+ paint.addColorEffect(conv); |
+ context->drawRect(paint, rect); |
+} |
+ |
+GrTexture* GaussianBlur(GrContext* context, |
+ GrTexture* srcTexture, |
+ bool canClobberSrc, |
+ const SkRect& rect, |
+ float sigmaX, |
+ float sigmaY) { |
+ GrAssert(NULL != context); |
+ |
+ GrContext::AutoRenderTarget art(context); |
+ |
+ GrContext::AutoMatrix am; |
+ am.setIdentity(context); |
+ |
+ SkIRect clearRect; |
+ int scaleFactorX, radiusX; |
+ int scaleFactorY, radiusY; |
+ sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &radiusX); |
+ sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &radiusY); |
+ |
+ SkRect srcRect(rect); |
+ scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); |
+ srcRect.roundOut(); |
+ scale_rect(&srcRect, static_cast<float>(scaleFactorX), |
+ static_cast<float>(scaleFactorY)); |
+ |
+ GrContext::AutoClip acs(context, srcRect); |
+ |
+ GrAssert(kBGRA_8888_GrPixelConfig == srcTexture->config() || |
+ kRGBA_8888_GrPixelConfig == srcTexture->config() || |
+ kAlpha_8_GrPixelConfig == srcTexture->config()); |
+ |
+ GrTextureDesc desc; |
+ desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; |
+ desc.fWidth = SkScalarFloorToInt(srcRect.width()); |
+ desc.fHeight = SkScalarFloorToInt(srcRect.height()); |
+ desc.fConfig = srcTexture->config(); |
+ |
+ GrAutoScratchTexture temp1, temp2; |
+ GrTexture* dstTexture = temp1.set(context, desc); |
+ GrTexture* tempTexture = canClobberSrc ? srcTexture : temp2.set(context, desc); |
+ if (NULL == dstTexture || NULL == tempTexture) { |
+ return NULL; |
+ } |
+ |
+ for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { |
+ GrPaint paint; |
+ SkMatrix matrix; |
+ matrix.setIDiv(srcTexture->width(), srcTexture->height()); |
+ context->setRenderTarget(dstTexture->asRenderTarget()); |
+ SkRect dstRect(srcRect); |
+ scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f, |
+ i < scaleFactorY ? 0.5f : 1.0f); |
+ GrTextureParams params(SkShader::kClamp_TileMode, true); |
+ paint.addColorTextureEffect(srcTexture, matrix, params); |
+ context->drawRectToRect(paint, dstRect, srcRect); |
+ srcRect = dstRect; |
+ srcTexture = dstTexture; |
+ SkTSwap(dstTexture, tempTexture); |
+ } |
+ |
+ SkIRect srcIRect; |
+ srcRect.roundOut(&srcIRect); |
+ |
+ if (sigmaX > 0.0f) { |
+ if (scaleFactorX > 1) { |
+ // Clear out a radius to the right of the srcRect to prevent the |
+ // X convolution from reading garbage. |
+ clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, |
+ radiusX, srcIRect.height()); |
+ context->clear(&clearRect, 0x0); |
+ } |
+ context->setRenderTarget(dstTexture->asRenderTarget()); |
+ convolve_gaussian(context, srcTexture, srcRect, sigmaX, radiusX, |
+ Gr1DKernelEffect::kX_Direction); |
+ srcTexture = dstTexture; |
+ SkTSwap(dstTexture, tempTexture); |
+ } |
+ |
+ if (sigmaY > 0.0f) { |
+ if (scaleFactorY > 1 || sigmaX > 0.0f) { |
+ // Clear out a radius below the srcRect to prevent the Y |
+ // convolution from reading garbage. |
+ clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, |
+ srcIRect.width(), radiusY); |
+ context->clear(&clearRect, 0x0); |
+ } |
+ |
+ context->setRenderTarget(dstTexture->asRenderTarget()); |
+ convolve_gaussian(context, srcTexture, srcRect, sigmaY, radiusY, |
+ Gr1DKernelEffect::kY_Direction); |
+ srcTexture = dstTexture; |
+ SkTSwap(dstTexture, tempTexture); |
+ } |
+ |
+ if (scaleFactorX > 1 || scaleFactorY > 1) { |
+ // Clear one pixel to the right and below, to accommodate bilinear |
+ // upsampling. |
+ clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, |
+ srcIRect.width() + 1, 1); |
+ context->clear(&clearRect, 0x0); |
+ clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, |
+ 1, srcIRect.height()); |
+ context->clear(&clearRect, 0x0); |
+ SkMatrix matrix; |
+ matrix.setIDiv(srcTexture->width(), srcTexture->height()); |
+ context->setRenderTarget(dstTexture->asRenderTarget()); |
+ |
+ GrPaint paint; |
+ // FIXME: this should be mitchell, not bilinear. |
+ GrTextureParams params(SkShader::kClamp_TileMode, true); |
+ paint.addColorTextureEffect(srcTexture, matrix, params); |
+ |
+ SkRect dstRect(srcRect); |
+ scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY); |
+ context->drawRectToRect(paint, dstRect, srcRect); |
+ srcRect = dstRect; |
+ srcTexture = dstTexture; |
+ SkTSwap(dstTexture, tempTexture); |
+ } |
+ if (srcTexture == temp1.texture()) { |
+ return temp1.detach(); |
+ } else if (srcTexture == temp2.texture()) { |
+ return temp2.detach(); |
+ } else { |
+ srcTexture->ref(); |
+ return srcTexture; |
+ } |
+} |
+#endif |
+ |
+} |
Property changes on: src\effects\SkGpuBlurUtils.cpp |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |