| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkGpuBlurUtils.h" | 8 #include "SkGpuBlurUtils.h" |
| 9 | 9 |
| 10 #include "SkRect.h" | 10 #include "SkRect.h" |
| 11 | 11 |
| 12 #if SK_SUPPORT_GPU | 12 #if SK_SUPPORT_GPU |
| 13 #include "effects/GrConvolutionEffect.h" | 13 #include "effects/GrConvolutionEffect.h" |
| 14 #include "effects/GrTextureDomainEffect.h" |
| 14 #include "GrContext.h" | 15 #include "GrContext.h" |
| 15 #endif | 16 #endif |
| 16 | 17 |
| 17 namespace SkGpuBlurUtils { | 18 namespace SkGpuBlurUtils { |
| 18 | 19 |
| 19 #if SK_SUPPORT_GPU | 20 #if SK_SUPPORT_GPU |
| 20 | 21 |
| 21 #define MAX_BLUR_SIGMA 4.0f | 22 #define MAX_BLUR_SIGMA 4.0f |
| 22 | 23 |
| 23 static void scale_rect(SkRect* rect, float xScale, float yScale) { | 24 static void scale_rect(SkRect* rect, float xScale, float yScale) { |
| 24 rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale)); | 25 rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale)); |
| 25 rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale)); | 26 rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale)); |
| 26 rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale)); | 27 rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale)); |
| 27 rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale)); | 28 rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale)); |
| 28 } | 29 } |
| 29 | 30 |
| 30 static float adjust_sigma(float sigma, int *scaleFactor, int *radius) { | 31 static float adjust_sigma(float sigma, int *scaleFactor, int *radius) { |
| 31 *scaleFactor = 1; | 32 *scaleFactor = 1; |
| 32 while (sigma > MAX_BLUR_SIGMA) { | 33 while (sigma > MAX_BLUR_SIGMA) { |
| 33 *scaleFactor *= 2; | 34 *scaleFactor *= 2; |
| 34 sigma *= 0.5f; | 35 sigma *= 0.5f; |
| 35 } | 36 } |
| 36 *radius = static_cast<int>(ceilf(sigma * 3.0f)); | 37 *radius = static_cast<int>(ceilf(sigma * 3.0f)); |
| 37 GrAssert(*radius <= GrConvolutionEffect::kMaxKernelRadius); | 38 GrAssert(*radius <= GrConvolutionEffect::kMaxKernelRadius); |
| 38 return sigma; | 39 return sigma; |
| 39 } | 40 } |
| 40 | 41 |
| 41 static void convolve_gaussian(GrContext* context, | 42 static void convolve_gaussian(GrContext* context, |
| 42 GrTexture* texture, | 43 GrTexture* texture, |
| 43 const SkRect& rect, | 44 const SkRect& srcRect, |
| 45 const SkRect& dstRect, |
| 46 bool cropToSrcRect, |
| 44 float sigma, | 47 float sigma, |
| 45 int radius, | 48 int radius, |
| 46 Gr1DKernelEffect::Direction direction) { | 49 Gr1DKernelEffect::Direction direction) { |
| 47 GrPaint paint; | 50 GrPaint paint; |
| 51 paint.reset(); |
| 52 float cropRect[4] = { 0.0f, 1.0f, 0.0f, 1.0f }; |
| 53 if (cropToSrcRect) { |
| 54 if (direction == Gr1DKernelEffect::kX_Direction) { |
| 55 cropRect[0] = SkScalarToFloat(srcRect.left()) / texture->width(); |
| 56 cropRect[1] = SkScalarToFloat(srcRect.right()) / texture->width(); |
| 57 } else { |
| 58 cropRect[2] = SkScalarToFloat(srcRect.top()) / texture->height(); |
| 59 cropRect[3] = SkScalarToFloat(srcRect.bottom()) / texture->height(); |
| 60 } |
| 61 } |
| 48 | 62 |
| 49 SkAutoTUnref<GrEffectRef> conv(GrConvolutionEffect::CreateGaussian(texture, | 63 SkAutoTUnref<GrEffectRef> conv(GrConvolutionEffect::CreateGaussian(texture, |
| 50 direction
, | 64 direction
, |
| 51 radius, | 65 radius, |
| 52 sigma)); | 66 sigma, |
| 67 cropToSrc
Rect, |
| 68 cropRect)
); |
| 53 paint.addColorEffect(conv); | 69 paint.addColorEffect(conv); |
| 54 context->drawRect(paint, rect); | 70 context->drawRectToRect(paint, dstRect, srcRect); |
| 55 } | 71 } |
| 56 | 72 |
| 57 GrTexture* GaussianBlur(GrContext* context, | 73 GrTexture* GaussianBlur(GrContext* context, |
| 58 GrTexture* srcTexture, | 74 GrTexture* srcTexture, |
| 59 bool canClobberSrc, | 75 bool canClobberSrc, |
| 60 const SkRect& rect, | 76 const SkRect& rect, |
| 77 bool cropToRect, |
| 61 float sigmaX, | 78 float sigmaX, |
| 62 float sigmaY) { | 79 float sigmaY) { |
| 63 GrAssert(NULL != context); | 80 GrAssert(NULL != context); |
| 64 | 81 |
| 65 GrContext::AutoRenderTarget art(context); | 82 GrContext::AutoRenderTarget art(context); |
| 66 | 83 |
| 67 GrContext::AutoMatrix am; | 84 GrContext::AutoMatrix am; |
| 68 am.setIdentity(context); | 85 am.setIdentity(context); |
| 69 | 86 |
| 70 SkIRect clearRect; | 87 SkIRect clearRect; |
| 71 int scaleFactorX, radiusX; | 88 int scaleFactorX, radiusX; |
| 72 int scaleFactorY, radiusY; | 89 int scaleFactorY, radiusY; |
| 73 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &radiusX); | 90 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &radiusX); |
| 74 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &radiusY); | 91 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &radiusY); |
| 75 | 92 |
| 76 SkRect srcRect(rect); | 93 SkRect srcRect(rect); |
| 77 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); | 94 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); |
| 78 srcRect.roundOut(); | 95 srcRect.roundOut(); |
| 79 scale_rect(&srcRect, static_cast<float>(scaleFactorX), | 96 scale_rect(&srcRect, static_cast<float>(scaleFactorX), |
| 80 static_cast<float>(scaleFactorY)); | 97 static_cast<float>(scaleFactorY)); |
| 81 | 98 |
| 82 GrContext::AutoClip acs(context, srcRect); | 99 GrContext::AutoClip acs(context, SkRect::MakeWH(srcRect.width(), srcRect.hei
ght())); |
| 83 | 100 |
| 84 GrAssert(kBGRA_8888_GrPixelConfig == srcTexture->config() || | 101 GrAssert(kBGRA_8888_GrPixelConfig == srcTexture->config() || |
| 85 kRGBA_8888_GrPixelConfig == srcTexture->config() || | 102 kRGBA_8888_GrPixelConfig == srcTexture->config() || |
| 86 kAlpha_8_GrPixelConfig == srcTexture->config()); | 103 kAlpha_8_GrPixelConfig == srcTexture->config()); |
| 87 | 104 |
| 88 GrTextureDesc desc; | 105 GrTextureDesc desc; |
| 89 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; | 106 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; |
| 90 desc.fWidth = SkScalarFloorToInt(srcRect.width()); | 107 desc.fWidth = SkScalarFloorToInt(srcRect.width()); |
| 91 desc.fHeight = SkScalarFloorToInt(srcRect.height()); | 108 desc.fHeight = SkScalarFloorToInt(srcRect.height()); |
| 92 desc.fConfig = srcTexture->config(); | 109 desc.fConfig = srcTexture->config(); |
| 93 | 110 |
| 94 GrAutoScratchTexture temp1, temp2; | 111 GrAutoScratchTexture temp1, temp2; |
| 95 GrTexture* dstTexture = temp1.set(context, desc); | 112 GrTexture* dstTexture = temp1.set(context, desc); |
| 96 GrTexture* tempTexture = canClobberSrc ? srcTexture : temp2.set(context, des
c); | 113 GrTexture* tempTexture = canClobberSrc ? srcTexture : temp2.set(context, des
c); |
| 97 if (NULL == dstTexture || NULL == tempTexture) { | 114 if (NULL == dstTexture || NULL == tempTexture) { |
| 98 return NULL; | 115 return NULL; |
| 99 } | 116 } |
| 100 | 117 |
| 101 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { | 118 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { |
| 102 GrPaint paint; | 119 GrPaint paint; |
| 103 SkMatrix matrix; | 120 SkMatrix matrix; |
| 104 matrix.setIDiv(srcTexture->width(), srcTexture->height()); | 121 matrix.setIDiv(srcTexture->width(), srcTexture->height()); |
| 105 context->setRenderTarget(dstTexture->asRenderTarget()); | 122 context->setRenderTarget(dstTexture->asRenderTarget()); |
| 106 SkRect dstRect(srcRect); | 123 SkRect dstRect(srcRect); |
| 124 if (cropToRect && i == 1) { |
| 125 dstRect.offset(-dstRect.fLeft, -dstRect.fTop); |
| 126 SkRect domain; |
| 127 matrix.mapRect(&domain, rect); |
| 128 domain.inset(i < scaleFactorX ? SK_ScalarHalf / srcTexture->width()
: 0.0f, |
| 129 i < scaleFactorY ? SK_ScalarHalf / srcTexture->height()
: 0.0f); |
| 130 SkAutoTUnref<GrEffectRef> effect(GrTextureDomainEffect::Create( |
| 131 srcTexture, |
| 132 matrix, |
| 133 domain, |
| 134 GrTextureDomainEffect::kDecal_WrapMode, |
| 135 true)); |
| 136 paint.addColorEffect(effect); |
| 137 } else { |
| 138 GrTextureParams params(SkShader::kClamp_TileMode, true); |
| 139 paint.addColorTextureEffect(srcTexture, matrix, params); |
| 140 } |
| 107 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f, | 141 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f, |
| 108 i < scaleFactorY ? 0.5f : 1.0f); | 142 i < scaleFactorY ? 0.5f : 1.0f); |
| 109 GrTextureParams params(SkShader::kClamp_TileMode, true); | |
| 110 paint.addColorTextureEffect(srcTexture, matrix, params); | |
| 111 context->drawRectToRect(paint, dstRect, srcRect); | 143 context->drawRectToRect(paint, dstRect, srcRect); |
| 112 srcRect = dstRect; | 144 srcRect = dstRect; |
| 113 srcTexture = dstTexture; | 145 srcTexture = dstTexture; |
| 114 SkTSwap(dstTexture, tempTexture); | 146 SkTSwap(dstTexture, tempTexture); |
| 115 } | 147 } |
| 116 | 148 |
| 117 SkIRect srcIRect; | 149 SkIRect srcIRect; |
| 118 srcRect.roundOut(&srcIRect); | 150 srcRect.roundOut(&srcIRect); |
| 119 | 151 |
| 120 if (sigmaX > 0.0f) { | 152 if (sigmaX > 0.0f) { |
| 121 if (scaleFactorX > 1) { | 153 if (scaleFactorX > 1) { |
| 122 // Clear out a radius to the right of the srcRect to prevent the | 154 // Clear out a radius to the right of the srcRect to prevent the |
| 123 // X convolution from reading garbage. | 155 // X convolution from reading garbage. |
| 124 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, | 156 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, |
| 125 radiusX, srcIRect.height()); | 157 radiusX, srcIRect.height()); |
| 126 context->clear(&clearRect, 0x0); | 158 context->clear(&clearRect, 0x0); |
| 127 } | 159 } |
| 128 context->setRenderTarget(dstTexture->asRenderTarget()); | 160 context->setRenderTarget(dstTexture->asRenderTarget()); |
| 129 convolve_gaussian(context, srcTexture, srcRect, sigmaX, radiusX, | 161 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); |
| 130 Gr1DKernelEffect::kX_Direction); | 162 convolve_gaussian(context, srcTexture, srcRect, dstRect, cropToRect, |
| 163 sigmaX, radiusX, Gr1DKernelEffect::kX_Direction); |
| 131 srcTexture = dstTexture; | 164 srcTexture = dstTexture; |
| 165 srcRect = dstRect; |
| 132 SkTSwap(dstTexture, tempTexture); | 166 SkTSwap(dstTexture, tempTexture); |
| 133 } | 167 } |
| 134 | 168 |
| 135 if (sigmaY > 0.0f) { | 169 if (sigmaY > 0.0f) { |
| 136 if (scaleFactorY > 1 || sigmaX > 0.0f) { | 170 if (scaleFactorY > 1 || sigmaX > 0.0f) { |
| 137 // Clear out a radius below the srcRect to prevent the Y | 171 // Clear out a radius below the srcRect to prevent the Y |
| 138 // convolution from reading garbage. | 172 // convolution from reading garbage. |
| 139 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, | 173 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, |
| 140 srcIRect.width(), radiusY); | 174 srcIRect.width(), radiusY); |
| 141 context->clear(&clearRect, 0x0); | 175 context->clear(&clearRect, 0x0); |
| 142 } | 176 } |
| 143 | 177 |
| 144 context->setRenderTarget(dstTexture->asRenderTarget()); | 178 context->setRenderTarget(dstTexture->asRenderTarget()); |
| 145 convolve_gaussian(context, srcTexture, srcRect, sigmaY, radiusY, | 179 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); |
| 146 Gr1DKernelEffect::kY_Direction); | 180 convolve_gaussian(context, srcTexture, srcRect, dstRect, cropToRect, |
| 181 sigmaY, radiusY, Gr1DKernelEffect::kY_Direction); |
| 147 srcTexture = dstTexture; | 182 srcTexture = dstTexture; |
| 183 srcRect = dstRect; |
| 148 SkTSwap(dstTexture, tempTexture); | 184 SkTSwap(dstTexture, tempTexture); |
| 149 } | 185 } |
| 150 | 186 |
| 151 if (scaleFactorX > 1 || scaleFactorY > 1) { | 187 if (scaleFactorX > 1 || scaleFactorY > 1) { |
| 152 // Clear one pixel to the right and below, to accommodate bilinear | 188 // Clear one pixel to the right and below, to accommodate bilinear |
| 153 // upsampling. | 189 // upsampling. |
| 154 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, | 190 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, |
| 155 srcIRect.width() + 1, 1); | 191 srcIRect.width() + 1, 1); |
| 156 context->clear(&clearRect, 0x0); | 192 context->clear(&clearRect, 0x0); |
| 157 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, | 193 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 178 } else if (srcTexture == temp2.texture()) { | 214 } else if (srcTexture == temp2.texture()) { |
| 179 return temp2.detach(); | 215 return temp2.detach(); |
| 180 } else { | 216 } else { |
| 181 srcTexture->ref(); | 217 srcTexture->ref(); |
| 182 return srcTexture; | 218 return srcTexture; |
| 183 } | 219 } |
| 184 } | 220 } |
| 185 #endif | 221 #endif |
| 186 | 222 |
| 187 } | 223 } |
| OLD | NEW |