| 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" |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 sigma = MAX_BLUR_SIGMA; | 40 sigma = MAX_BLUR_SIGMA; |
| 41 } | 41 } |
| 42 } | 42 } |
| 43 *radius = static_cast<int>(ceilf(sigma * 3.0f)); | 43 *radius = static_cast<int>(ceilf(sigma * 3.0f)); |
| 44 SkASSERT(*radius <= GrConvolutionEffect::kMaxKernelRadius); | 44 SkASSERT(*radius <= GrConvolutionEffect::kMaxKernelRadius); |
| 45 return sigma; | 45 return sigma; |
| 46 } | 46 } |
| 47 | 47 |
| 48 static void convolve_gaussian_1d(GrDrawContext* drawContext, | 48 static void convolve_gaussian_1d(GrDrawContext* drawContext, |
| 49 const GrClip& clip, | 49 const GrClip& clip, |
| 50 const SkRect& srcRect, | |
| 51 const SkRect& dstRect, | 50 const SkRect& dstRect, |
| 51 const SkPoint& srcOffset, |
| 52 GrTexture* texture, | 52 GrTexture* texture, |
| 53 Gr1DKernelEffect::Direction direction, | 53 Gr1DKernelEffect::Direction direction, |
| 54 int radius, | 54 int radius, |
| 55 float sigma, | 55 float sigma, |
| 56 bool useBounds, | 56 bool useBounds, |
| 57 float bounds[2]) { | 57 float bounds[2]) { |
| 58 GrPaint paint; | 58 GrPaint paint; |
| 59 SkAutoTUnref<GrFragmentProcessor> conv(GrConvolutionEffect::CreateGaussian( | 59 SkAutoTUnref<GrFragmentProcessor> conv(GrConvolutionEffect::CreateGaussian( |
| 60 texture, direction, radius, sigma, useBounds, bounds)); | 60 texture, direction, radius, sigma, useBounds, bounds)); |
| 61 paint.addColorFragmentProcessor(conv); | 61 paint.addColorFragmentProcessor(conv); |
| 62 drawContext->drawNonAARectToRect(clip, paint, SkMatrix::I(), dstRect, srcRec
t); | 62 SkMatrix localMatrix = SkMatrix::MakeTrans(srcOffset.x(), srcOffset.y()); |
| 63 drawContext->drawNonAARectWithLocalMatrix(clip, paint, SkMatrix::I(), dstRec
t, localMatrix); |
| 63 } | 64 } |
| 64 | 65 |
| 65 static void convolve_gaussian_2d(GrDrawContext* drawContext, | 66 static void convolve_gaussian_2d(GrDrawContext* drawContext, |
| 66 const GrClip& clip, | 67 const GrClip& clip, |
| 67 const SkRect& srcRect, | 68 const SkRect& srcRect, |
| 68 const SkRect& dstRect, | |
| 69 GrTexture* texture, | 69 GrTexture* texture, |
| 70 int radiusX, | 70 int radiusX, |
| 71 int radiusY, | 71 int radiusY, |
| 72 SkScalar sigmaX, | 72 SkScalar sigmaX, |
| 73 SkScalar sigmaY, | 73 SkScalar sigmaY, |
| 74 bool useBounds, | 74 bool useBounds, |
| 75 SkIRect bounds) { | 75 SkIRect bounds) { |
| 76 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); |
| 77 SkMatrix localMatrix = SkMatrix::MakeTrans(srcRect.x(), srcRect.y()); |
| 76 SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1); | 78 SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1); |
| 77 SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY); | 79 SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY); |
| 78 GrPaint paint; | 80 GrPaint paint; |
| 79 SkAutoTUnref<GrFragmentProcessor> conv(GrMatrixConvolutionEffect::CreateGaus
sian( | 81 SkAutoTUnref<GrFragmentProcessor> conv(GrMatrixConvolutionEffect::CreateGaus
sian( |
| 80 texture, bounds, size, 1.0, 0.0, kernelOffset, | 82 texture, bounds, size, 1.0, 0.0, kernelOffset, |
| 81 useBounds ? GrTextureDomain::kClamp_Mode : GrTextureDomain::kIgnore_
Mode, | 83 useBounds ? GrTextureDomain::kClamp_Mode : GrTextureDomain::kIgnore_
Mode, |
| 82 true, sigmaX, sigmaY)); | 84 true, sigmaX, sigmaY)); |
| 83 paint.addColorFragmentProcessor(conv); | 85 paint.addColorFragmentProcessor(conv); |
| 84 drawContext->drawNonAARectToRect(clip, paint, SkMatrix::I(), dstRect, srcRec
t); | 86 drawContext->drawNonAARectWithLocalMatrix(clip, paint, SkMatrix::I(), dstRec
t, localMatrix); |
| 85 } | 87 } |
| 86 | 88 |
| 87 static void convolve_gaussian(GrDrawContext* drawContext, | 89 static void convolve_gaussian(GrDrawContext* drawContext, |
| 88 const GrClip& clip, | 90 const GrClip& clip, |
| 89 const SkRect& srcRect, | 91 const SkRect& srcRect, |
| 90 const SkRect& dstRect, | |
| 91 GrTexture* texture, | 92 GrTexture* texture, |
| 92 Gr1DKernelEffect::Direction direction, | 93 Gr1DKernelEffect::Direction direction, |
| 93 int radius, | 94 int radius, |
| 94 float sigma, | 95 float sigma, |
| 95 bool cropToSrcRect) { | 96 bool cropToSrcRect) { |
| 96 float bounds[2] = { 0.0f, 1.0f }; | 97 float bounds[2] = { 0.0f, 1.0f }; |
| 98 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); |
| 99 SkPoint srcOffset = SkPoint::Make(srcRect.x(), srcRect.y()); |
| 97 if (!cropToSrcRect) { | 100 if (!cropToSrcRect) { |
| 98 convolve_gaussian_1d(drawContext, clip, srcRect, dstRect, texture, | 101 convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture, |
| 99 direction, radius, sigma, false, bounds); | 102 direction, radius, sigma, false, bounds); |
| 100 return; | 103 return; |
| 101 } | 104 } |
| 102 SkRect lowerSrcRect = srcRect, lowerDstRect = dstRect; | 105 SkRect lowerDstRect = dstRect; |
| 103 SkRect middleSrcRect = srcRect, middleDstRect = dstRect; | 106 SkRect middleDstRect = dstRect; |
| 104 SkRect upperSrcRect = srcRect, upperDstRect = dstRect; | 107 SkRect upperDstRect = dstRect; |
| 105 SkScalar size; | 108 SkScalar size; |
| 106 SkScalar rad = SkIntToScalar(radius); | 109 SkScalar rad = SkIntToScalar(radius); |
| 107 if (direction == Gr1DKernelEffect::kX_Direction) { | 110 if (direction == Gr1DKernelEffect::kX_Direction) { |
| 108 bounds[0] = SkScalarToFloat(srcRect.left()) / texture->width(); | 111 bounds[0] = SkScalarToFloat(srcRect.left()) / texture->width(); |
| 109 bounds[1] = SkScalarToFloat(srcRect.right()) / texture->width(); | 112 bounds[1] = SkScalarToFloat(srcRect.right()) / texture->width(); |
| 110 size = srcRect.width(); | 113 size = dstRect.width(); |
| 111 lowerSrcRect.fRight = srcRect.left() + rad; | |
| 112 lowerDstRect.fRight = dstRect.left() + rad; | 114 lowerDstRect.fRight = dstRect.left() + rad; |
| 113 upperSrcRect.fLeft = srcRect.right() - rad; | |
| 114 upperDstRect.fLeft = dstRect.right() - rad; | 115 upperDstRect.fLeft = dstRect.right() - rad; |
| 115 middleSrcRect.inset(rad, 0); | |
| 116 middleDstRect.inset(rad, 0); | 116 middleDstRect.inset(rad, 0); |
| 117 } else { | 117 } else { |
| 118 bounds[0] = SkScalarToFloat(srcRect.top()) / texture->height(); | 118 bounds[0] = SkScalarToFloat(srcRect.top()) / texture->height(); |
| 119 bounds[1] = SkScalarToFloat(srcRect.bottom()) / texture->height(); | 119 bounds[1] = SkScalarToFloat(srcRect.bottom()) / texture->height(); |
| 120 size = srcRect.height(); | 120 size = dstRect.height(); |
| 121 lowerSrcRect.fBottom = srcRect.top() + rad; | |
| 122 lowerDstRect.fBottom = dstRect.top() + rad; | 121 lowerDstRect.fBottom = dstRect.top() + rad; |
| 123 upperSrcRect.fTop = srcRect.bottom() - rad; | |
| 124 upperDstRect.fTop = dstRect.bottom() - rad; | 122 upperDstRect.fTop = dstRect.bottom() - rad; |
| 125 middleSrcRect.inset(0, rad); | |
| 126 middleDstRect.inset(0, rad); | 123 middleDstRect.inset(0, rad); |
| 127 } | 124 } |
| 128 if (radius >= size * SK_ScalarHalf) { | 125 if (radius >= size * SK_ScalarHalf) { |
| 129 // Blur radius covers srcRect; use bounds over entire draw | 126 // Blur radius covers srcRect; use bounds over entire draw |
| 130 convolve_gaussian_1d(drawContext, clip, srcRect, dstRect, texture, | 127 convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture, |
| 131 direction, radius, sigma, true, bounds); | 128 direction, radius, sigma, true, bounds); |
| 132 } else { | 129 } else { |
| 133 // Draw upper and lower margins with bounds; middle without. | 130 // Draw upper and lower margins with bounds; middle without. |
| 134 convolve_gaussian_1d(drawContext, clip, lowerSrcRect, lowerDstRect, text
ure, | 131 convolve_gaussian_1d(drawContext, clip, lowerDstRect, srcOffset, texture
, |
| 135 direction, radius, sigma, true, bounds); | 132 direction, radius, sigma, true, bounds); |
| 136 convolve_gaussian_1d(drawContext, clip, upperSrcRect, upperDstRect, text
ure, | 133 convolve_gaussian_1d(drawContext, clip, upperDstRect, srcOffset, texture
, |
| 137 direction, radius, sigma, true, bounds); | 134 direction, radius, sigma, true, bounds); |
| 138 convolve_gaussian_1d(drawContext, clip, middleSrcRect, middleDstRect, te
xture, | 135 convolve_gaussian_1d(drawContext, clip, middleDstRect, srcOffset, textur
e, |
| 139 direction, radius, sigma, false, bounds); | 136 direction, radius, sigma, false, bounds); |
| 140 } | 137 } |
| 141 } | 138 } |
| 142 | 139 |
| 143 GrTexture* GaussianBlur(GrContext* context, | 140 GrTexture* GaussianBlur(GrContext* context, |
| 144 GrTexture* srcTexture, | 141 GrTexture* srcTexture, |
| 145 bool canClobberSrc, | 142 bool canClobberSrc, |
| 146 const SkRect& rect, | 143 const SkRect& rect, |
| 147 bool cropToRect, | 144 bool cropToRect, |
| 148 float sigmaX, | 145 float sigmaX, |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 234 } | 231 } |
| 235 | 232 |
| 236 const SkIRect srcIRect = srcRect.roundOut(); | 233 const SkIRect srcIRect = srcRect.roundOut(); |
| 237 | 234 |
| 238 // For really small blurs (certainly no wider than 5x5 on desktop gpus) it i
s faster to just | 235 // For really small blurs (certainly no wider than 5x5 on desktop gpus) it i
s faster to just |
| 239 // launch a single non separable kernel vs two launches | 236 // launch a single non separable kernel vs two launches |
| 240 if (sigmaX > 0.0f && sigmaY > 0.0f && | 237 if (sigmaX > 0.0f && sigmaY > 0.0f && |
| 241 (2 * radiusX + 1) * (2 * radiusY + 1) <= MAX_KERNEL_SIZE) { | 238 (2 * radiusX + 1) * (2 * radiusY + 1) <= MAX_KERNEL_SIZE) { |
| 242 // We shouldn't be scaling because this is a small size blur | 239 // We shouldn't be scaling because this is a small size blur |
| 243 SkASSERT((1 == scaleFactorX) && (1 == scaleFactorY)); | 240 SkASSERT((1 == scaleFactorX) && (1 == scaleFactorY)); |
| 244 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); | |
| 245 | 241 |
| 246 SkAutoTUnref<GrDrawContext> dstDrawContext( | 242 SkAutoTUnref<GrDrawContext> dstDrawContext( |
| 247 context->drawContext(dstTexture->as
RenderTarget())); | 243 context->drawContext(dstTexture->as
RenderTarget())); |
| 248 if (!dstDrawContext) { | 244 if (!dstDrawContext) { |
| 249 return nullptr; | 245 return nullptr; |
| 250 } | 246 } |
| 251 convolve_gaussian_2d(dstDrawContext, clip, srcRect, dstRect, | 247 convolve_gaussian_2d(dstDrawContext, clip, srcRect, |
| 252 srcTexture, radiusX, radiusY, sigmaX, sigmaY, cropT
oRect, srcIRect); | 248 srcTexture, radiusX, radiusY, sigmaX, sigmaY, cropT
oRect, srcIRect); |
| 253 | 249 |
| 254 srcDrawContext.swap(dstDrawContext); | 250 srcDrawContext.swap(dstDrawContext); |
| 255 srcRect = dstRect; | 251 srcRect.offsetTo(0, 0); |
| 256 srcTexture = dstTexture; | 252 srcTexture = dstTexture; |
| 257 SkTSwap(dstTexture, tempTexture); | 253 SkTSwap(dstTexture, tempTexture); |
| 258 | 254 |
| 259 } else { | 255 } else { |
| 260 if (sigmaX > 0.0f) { | 256 if (sigmaX > 0.0f) { |
| 261 if (scaleFactorX > 1) { | 257 if (scaleFactorX > 1) { |
| 262 // TODO: if we pass in the source draw context we don't need thi
s here | 258 // TODO: if we pass in the source draw context we don't need thi
s here |
| 263 if (!srcDrawContext) { | 259 if (!srcDrawContext) { |
| 264 srcDrawContext.reset(context->drawContext(srcTexture->asRend
erTarget())); | 260 srcDrawContext.reset(context->drawContext(srcTexture->asRend
erTarget())); |
| 265 if (!srcDrawContext) { | 261 if (!srcDrawContext) { |
| 266 return nullptr; | 262 return nullptr; |
| 267 } | 263 } |
| 268 } | 264 } |
| 269 | 265 |
| 270 // Clear out a radius to the right of the srcRect to prevent the | 266 // Clear out a radius to the right of the srcRect to prevent the |
| 271 // X convolution from reading garbage. | 267 // X convolution from reading garbage. |
| 272 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, | 268 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, |
| 273 radiusX, srcIRect.height()); | 269 radiusX, srcIRect.height()); |
| 274 srcDrawContext->clear(&clearRect, 0x0, false); | 270 srcDrawContext->clear(&clearRect, 0x0, false); |
| 275 } | 271 } |
| 276 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); | |
| 277 | 272 |
| 278 SkAutoTUnref<GrDrawContext> dstDrawContext( | 273 SkAutoTUnref<GrDrawContext> dstDrawContext( |
| 279 context->drawContext(dstTexture->as
RenderTarget())); | 274 context->drawContext(dstTexture->as
RenderTarget())); |
| 280 if (!dstDrawContext) { | 275 if (!dstDrawContext) { |
| 281 return nullptr; | 276 return nullptr; |
| 282 } | 277 } |
| 283 convolve_gaussian(dstDrawContext, clip, srcRect, dstRect, | 278 convolve_gaussian(dstDrawContext, clip, srcRect, |
| 284 srcTexture, Gr1DKernelEffect::kX_Direction, radius
X, sigmaX, | 279 srcTexture, Gr1DKernelEffect::kX_Direction, radius
X, sigmaX, |
| 285 cropToRect); | 280 cropToRect); |
| 286 | 281 |
| 287 srcDrawContext.swap(dstDrawContext); | 282 srcDrawContext.swap(dstDrawContext); |
| 288 srcTexture = dstTexture; | 283 srcTexture = dstTexture; |
| 289 srcRect = dstRect; | 284 srcRect.offsetTo(0, 0); |
| 290 SkTSwap(dstTexture, tempTexture); | 285 SkTSwap(dstTexture, tempTexture); |
| 291 } | 286 } |
| 292 | 287 |
| 293 if (sigmaY > 0.0f) { | 288 if (sigmaY > 0.0f) { |
| 294 if (scaleFactorY > 1 || sigmaX > 0.0f) { | 289 if (scaleFactorY > 1 || sigmaX > 0.0f) { |
| 295 // TODO: if we pass in the source draw context we don't need thi
s here | 290 // TODO: if we pass in the source draw context we don't need thi
s here |
| 296 if (!srcDrawContext) { | 291 if (!srcDrawContext) { |
| 297 srcDrawContext.reset(context->drawContext(srcTexture->asRend
erTarget())); | 292 srcDrawContext.reset(context->drawContext(srcTexture->asRend
erTarget())); |
| 298 if (!srcDrawContext) { | 293 if (!srcDrawContext) { |
| 299 return nullptr; | 294 return nullptr; |
| 300 } | 295 } |
| 301 } | 296 } |
| 302 | 297 |
| 303 // Clear out a radius below the srcRect to prevent the Y | 298 // Clear out a radius below the srcRect to prevent the Y |
| 304 // convolution from reading garbage. | 299 // convolution from reading garbage. |
| 305 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, | 300 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, |
| 306 srcIRect.width(), radiusY); | 301 srcIRect.width(), radiusY); |
| 307 srcDrawContext->clear(&clearRect, 0x0, false); | 302 srcDrawContext->clear(&clearRect, 0x0, false); |
| 308 } | 303 } |
| 309 | 304 |
| 310 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); | |
| 311 | |
| 312 SkAutoTUnref<GrDrawContext> dstDrawContext( | 305 SkAutoTUnref<GrDrawContext> dstDrawContext( |
| 313 context->drawContext(dstTexture->
asRenderTarget())); | 306 context->drawContext(dstTexture->
asRenderTarget())); |
| 314 if (!dstDrawContext) { | 307 if (!dstDrawContext) { |
| 315 return nullptr; | 308 return nullptr; |
| 316 } | 309 } |
| 317 convolve_gaussian(dstDrawContext, clip, srcRect, | 310 convolve_gaussian(dstDrawContext, clip, srcRect, |
| 318 dstRect, srcTexture, Gr1DKernelEffect::kY_Directio
n, radiusY, sigmaY, | 311 srcTexture, Gr1DKernelEffect::kY_Direction, radius
Y, sigmaY, |
| 319 cropToRect); | 312 cropToRect); |
| 320 | 313 |
| 321 srcDrawContext.swap(dstDrawContext); | 314 srcDrawContext.swap(dstDrawContext); |
| 322 srcTexture = dstTexture; | 315 srcTexture = dstTexture; |
| 323 srcRect = dstRect; | 316 srcRect.offsetTo(0, 0); |
| 324 SkTSwap(dstTexture, tempTexture); | 317 SkTSwap(dstTexture, tempTexture); |
| 325 } | 318 } |
| 326 } | 319 } |
| 327 | 320 |
| 328 if (scaleFactorX > 1 || scaleFactorY > 1) { | 321 if (scaleFactorX > 1 || scaleFactorY > 1) { |
| 329 SkASSERT(srcDrawContext); | 322 SkASSERT(srcDrawContext); |
| 330 | 323 |
| 331 // Clear one pixel to the right and below, to accommodate bilinear | 324 // Clear one pixel to the right and below, to accommodate bilinear |
| 332 // upsampling. | 325 // upsampling. |
| 333 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, | 326 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, |
| (...skipping 24 matching lines...) Expand all Loading... |
| 358 srcRect = dstRect; | 351 srcRect = dstRect; |
| 359 srcTexture = dstTexture; | 352 srcTexture = dstTexture; |
| 360 SkTSwap(dstTexture, tempTexture); | 353 SkTSwap(dstTexture, tempTexture); |
| 361 } | 354 } |
| 362 | 355 |
| 363 return SkRef(srcTexture); | 356 return SkRef(srcTexture); |
| 364 } | 357 } |
| 365 #endif | 358 #endif |
| 366 | 359 |
| 367 } | 360 } |
| OLD | NEW |