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 |