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

Side by Side Diff: src/core/SkGpuBlurUtils.cpp

Issue 2274603003: Revert of Moving SkBlurImageFilter into core (Closed) Base URL: https://skia.googlesource.com/skia@master
Patch Set: Created 4 years, 4 months 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 unified diff | Download patch
« no previous file with comments | « src/core/SkGpuBlurUtils.h ('k') | src/effects/SkBlurImageFilter.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkGpuBlurUtils.h"
9
10 #include "SkRect.h"
11
12 #if SK_SUPPORT_GPU
13 #include "effects/GrConvolutionEffect.h"
14 #include "effects/GrMatrixConvolutionEffect.h"
15 #include "GrContext.h"
16 #include "GrCaps.h"
17 #include "GrDrawContext.h"
18 #include "GrFixedClip.h"
19
20 #define MAX_BLUR_SIGMA 4.0f
21
22 static void scale_irect_roundout(SkIRect* rect, float xScale, float yScale) {
23 rect->fLeft = SkScalarFloorToInt(SkScalarMul(rect->fLeft, xScale));
24 rect->fTop = SkScalarFloorToInt(SkScalarMul(rect->fTop, yScale));
25 rect->fRight = SkScalarCeilToInt(SkScalarMul(rect->fRight, xScale));
26 rect->fBottom = SkScalarCeilToInt(SkScalarMul(rect->fBottom, yScale));
27 }
28
29 static void scale_irect(SkIRect* rect, int xScale, int yScale) {
30 rect->fLeft *= xScale;
31 rect->fTop *= yScale;
32 rect->fRight *= xScale;
33 rect->fBottom *= yScale;
34 }
35
36 #ifdef SK_DEBUG
37 static inline int is_even(int x) { return !(x & 1); }
38 #endif
39
40 static void shrink_irect_by_2(SkIRect* rect, bool xAxis, bool yAxis) {
41 if (xAxis) {
42 SkASSERT(is_even(rect->fLeft) && is_even(rect->fRight));
43 rect->fLeft /= 2;
44 rect->fRight /= 2;
45 }
46 if (yAxis) {
47 SkASSERT(is_even(rect->fTop) && is_even(rect->fBottom));
48 rect->fTop /= 2;
49 rect->fBottom /= 2;
50 }
51 }
52
53 static float adjust_sigma(float sigma, int maxTextureSize, int *scaleFactor, int *radius) {
54 *scaleFactor = 1;
55 while (sigma > MAX_BLUR_SIGMA) {
56 *scaleFactor *= 2;
57 sigma *= 0.5f;
58 if (*scaleFactor > maxTextureSize) {
59 *scaleFactor = maxTextureSize;
60 sigma = MAX_BLUR_SIGMA;
61 }
62 }
63 *radius = static_cast<int>(ceilf(sigma * 3.0f));
64 SkASSERT(*radius <= GrConvolutionEffect::kMaxKernelRadius);
65 return sigma;
66 }
67
68 static void convolve_gaussian_1d(GrDrawContext* drawContext,
69 const GrClip& clip,
70 const SkIRect& dstRect,
71 const SkIPoint& srcOffset,
72 GrTexture* texture,
73 Gr1DKernelEffect::Direction direction,
74 int radius,
75 float sigma,
76 bool useBounds,
77 float bounds[2]) {
78 GrPaint paint;
79 paint.setGammaCorrect(drawContext->isGammaCorrect());
80 sk_sp<GrFragmentProcessor> conv(GrConvolutionEffect::MakeGaussian(
81 texture, direction, radius, sigma, useBounds, bounds));
82 paint.addColorFragmentProcessor(std::move(conv));
83 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
84 SkMatrix localMatrix = SkMatrix::MakeTrans(-SkIntToScalar(srcOffset.x()),
85 -SkIntToScalar(srcOffset.y()));
86 drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(),
87 SkRect::Make(dstRect), localMatrix);
88 }
89
90 static void convolve_gaussian_2d(GrDrawContext* drawContext,
91 const GrClip& clip,
92 const SkIRect& dstRect,
93 const SkIPoint& srcOffset,
94 GrTexture* texture,
95 int radiusX,
96 int radiusY,
97 SkScalar sigmaX,
98 SkScalar sigmaY,
99 const SkIRect* srcBounds) {
100 SkMatrix localMatrix = SkMatrix::MakeTrans(-SkIntToScalar(srcOffset.x()),
101 -SkIntToScalar(srcOffset.y()));
102 SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1);
103 SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY);
104 GrPaint paint;
105 paint.setGammaCorrect(drawContext->isGammaCorrect());
106 SkIRect bounds = srcBounds ? *srcBounds : SkIRect::EmptyIRect();
107
108 sk_sp<GrFragmentProcessor> conv(GrMatrixConvolutionEffect::MakeGaussian(
109 texture, bounds, size, 1.0, 0.0, kernelOffset,
110 srcBounds ? GrTextureDomain::kDecal_Mode : GrTextureDomain::kIgnore_ Mode,
111 true, sigmaX, sigmaY));
112 paint.addColorFragmentProcessor(std::move(conv));
113 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
114 drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(),
115 SkRect::Make(dstRect), localMatrix);
116 }
117
118 static void convolve_gaussian(GrDrawContext* drawContext,
119 const GrClip& clip,
120 const SkIRect& srcRect,
121 GrTexture* texture,
122 Gr1DKernelEffect::Direction direction,
123 int radius,
124 float sigma,
125 const SkIRect* srcBounds,
126 const SkIPoint& srcOffset) {
127 float bounds[2] = { 0.0f, 1.0f };
128 SkIRect dstRect = SkIRect::MakeWH(srcRect.width(), srcRect.height());
129 if (!srcBounds) {
130 convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture,
131 direction, radius, sigma, false, bounds);
132 return;
133 }
134 SkIRect midRect = *srcBounds, leftRect, rightRect;
135 midRect.offset(srcOffset);
136 SkIRect topRect, bottomRect;
137 if (direction == Gr1DKernelEffect::kX_Direction) {
138 bounds[0] = SkIntToFloat(srcBounds->left()) / texture->width();
139 bounds[1] = SkIntToFloat(srcBounds->right()) / texture->width();
140 topRect = SkIRect::MakeLTRB(0, 0, dstRect.right(), midRect.top());
141 bottomRect = SkIRect::MakeLTRB(0, midRect.bottom(), dstRect.right(), dst Rect.bottom());
142 midRect.inset(radius, 0);
143 leftRect = SkIRect::MakeLTRB(0, midRect.top(), midRect.left(), midRect.b ottom());
144 rightRect =
145 SkIRect::MakeLTRB(midRect.right(), midRect.top(), dstRect.width(), m idRect.bottom());
146 dstRect.fTop = midRect.top();
147 dstRect.fBottom = midRect.bottom();
148 } else {
149 bounds[0] = SkIntToFloat(srcBounds->top()) / texture->height();
150 bounds[1] = SkIntToFloat(srcBounds->bottom()) / texture->height();
151 topRect = SkIRect::MakeLTRB(0, 0, midRect.left(), dstRect.bottom());
152 bottomRect = SkIRect::MakeLTRB(midRect.right(), 0, dstRect.right(), dstR ect.bottom());
153 midRect.inset(0, radius);
154 leftRect = SkIRect::MakeLTRB(midRect.left(), 0, midRect.right(), midRect .top());
155 rightRect =
156 SkIRect::MakeLTRB(midRect.left(), midRect.bottom(), midRect.right(), dstRect.height());
157 dstRect.fLeft = midRect.left();
158 dstRect.fRight = midRect.right();
159 }
160 if (!topRect.isEmpty()) {
161 drawContext->clear(&topRect, 0, false);
162 }
163
164 if (!bottomRect.isEmpty()) {
165 drawContext->clear(&bottomRect, 0, false);
166 }
167 if (midRect.isEmpty()) {
168 // Blur radius covers srcBounds; use bounds over entire draw
169 convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture,
170 direction, radius, sigma, true, bounds);
171 } else {
172 // Draw right and left margins with bounds; middle without.
173 convolve_gaussian_1d(drawContext, clip, leftRect, srcOffset, texture,
174 direction, radius, sigma, true, bounds);
175 convolve_gaussian_1d(drawContext, clip, rightRect, srcOffset, texture,
176 direction, radius, sigma, true, bounds);
177 convolve_gaussian_1d(drawContext, clip, midRect, srcOffset, texture,
178 direction, radius, sigma, false, bounds);
179 }
180 }
181
182 namespace SkGpuBlurUtils {
183
184 sk_sp<GrDrawContext> GaussianBlur(GrContext* context,
185 GrTexture* origSrc,
186 sk_sp<SkColorSpace> colorSpace,
187 const SkIRect& dstBounds,
188 const SkIRect* srcBounds,
189 float sigmaX,
190 float sigmaY,
191 SkBackingFit fit) {
192 SkASSERT(context);
193 SkIRect clearRect;
194 int scaleFactorX, radiusX;
195 int scaleFactorY, radiusY;
196 int maxTextureSize = context->caps()->maxTextureSize();
197 sigmaX = adjust_sigma(sigmaX, maxTextureSize, &scaleFactorX, &radiusX);
198 sigmaY = adjust_sigma(sigmaY, maxTextureSize, &scaleFactorY, &radiusY);
199 SkASSERT(sigmaX || sigmaY);
200
201 SkIPoint srcOffset = SkIPoint::Make(-dstBounds.x(), -dstBounds.y());
202 SkIRect localDstBounds = SkIRect::MakeWH(dstBounds.width(), dstBounds.height ());
203 SkIRect localSrcBounds;
204 SkIRect srcRect;
205 if (srcBounds) {
206 srcRect = localSrcBounds = *srcBounds;
207 srcRect.offset(srcOffset);
208 srcBounds = &localSrcBounds;
209 } else {
210 srcRect = localDstBounds;
211 }
212
213 scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
214 scale_irect(&srcRect, scaleFactorX, scaleFactorY);
215
216 // setup new clip
217 GrFixedClip clip(localDstBounds);
218
219 sk_sp<GrTexture> srcTexture(sk_ref_sp(origSrc));
220
221 SkASSERT(kBGRA_8888_GrPixelConfig == srcTexture->config() ||
222 kRGBA_8888_GrPixelConfig == srcTexture->config() ||
223 kSRGBA_8888_GrPixelConfig == srcTexture->config() ||
224 kSBGRA_8888_GrPixelConfig == srcTexture->config() ||
225 kAlpha_8_GrPixelConfig == srcTexture->config());
226
227 const int width = dstBounds.width();
228 const int height = dstBounds.height();
229 const GrPixelConfig config = srcTexture->config();
230
231 sk_sp<GrDrawContext> dstDrawContext(context->makeDrawContext(fit,
232 width, height, config, colorSpace,
233 0, kDefault_GrS urfaceOrigin));
234 if (!dstDrawContext) {
235 return nullptr;
236 }
237
238 // 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
240 if (sigmaX > 0.0f && sigmaY > 0.0f &&
241 (2 * radiusX + 1) * (2 * radiusY + 1) <= MAX_KERNEL_SIZE) {
242 // We shouldn't be scaling because this is a small size blur
243 SkASSERT((1 == scaleFactorX) && (1 == scaleFactorY));
244
245 convolve_gaussian_2d(dstDrawContext.get(), clip, localDstBounds, srcOffs et,
246 srcTexture.get(), radiusX, radiusY, sigmaX, sigmaY, srcBounds);
247
248 return dstDrawContext;
249 }
250
251 sk_sp<GrDrawContext> tmpDrawContext(context->makeDrawContext(fit,
252 width, height, config, colorSpace,
253 0, kDefault_GrS urfaceOrigin));
254 if (!tmpDrawContext) {
255 return nullptr;
256 }
257
258 sk_sp<GrDrawContext> srcDrawContext;
259
260 SkASSERT(SkIsPow2(scaleFactorX) && SkIsPow2(scaleFactorY));
261
262 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
263 GrPaint paint;
264 paint.setGammaCorrect(dstDrawContext->isGammaCorrect());
265 SkMatrix matrix;
266 matrix.setIDiv(srcTexture->width(), srcTexture->height());
267 SkIRect dstRect(srcRect);
268 if (srcBounds && i == 1) {
269 SkRect domain;
270 matrix.mapRect(&domain, SkRect::Make(*srcBounds));
271 domain.inset((i < scaleFactorX) ? SK_ScalarHalf / srcTexture->width( ) : 0.0f,
272 (i < scaleFactorY) ? SK_ScalarHalf / srcTexture->height () : 0.0f);
273 sk_sp<GrFragmentProcessor> fp(GrTextureDomainEffect::Make(
274 srcTexture.get(),
275 nullptr,
276 matrix,
277 domain,
278 GrTextureDomain::kDecal_ Mode,
279 GrTextureParams::kBilerp _FilterMode));
280 paint.addColorFragmentProcessor(std::move(fp));
281 srcRect.offset(-srcOffset);
282 srcOffset.set(0, 0);
283 } else {
284 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::k Bilerp_FilterMode);
285 paint.addColorTextureProcessor(srcTexture.get(), nullptr, matrix, pa rams);
286 }
287 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
288 shrink_irect_by_2(&dstRect, i < scaleFactorX, i < scaleFactorY);
289
290 dstDrawContext->fillRectToRect(clip, paint, SkMatrix::I(),
291 SkRect::Make(dstRect), SkRect::Make(srcRe ct));
292
293 srcDrawContext = dstDrawContext;
294 srcRect = dstRect;
295 srcTexture = srcDrawContext->asTexture();
296 dstDrawContext.swap(tmpDrawContext);
297 localSrcBounds = srcRect;
298 }
299
300 srcRect = localDstBounds;
301 scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
302 if (sigmaX > 0.0f) {
303 if (scaleFactorX > 1) {
304 SkASSERT(srcDrawContext);
305
306 // Clear out a radius to the right of the srcRect to prevent the
307 // X convolution from reading garbage.
308 clearRect = SkIRect::MakeXYWH(srcRect.fRight, srcRect.fTop,
309 radiusX, srcRect.height());
310 srcDrawContext->clear(&clearRect, 0x0, false);
311 }
312
313 convolve_gaussian(dstDrawContext.get(), clip, srcRect,
314 srcTexture.get(), Gr1DKernelEffect::kX_Direction, radi usX, sigmaX,
315 srcBounds, srcOffset);
316 srcDrawContext = dstDrawContext;
317 srcTexture = srcDrawContext->asTexture();
318 srcRect.offsetTo(0, 0);
319 dstDrawContext.swap(tmpDrawContext);
320 localSrcBounds = srcRect;
321 srcOffset.set(0, 0);
322 }
323
324 if (sigmaY > 0.0f) {
325 if (scaleFactorY > 1 || sigmaX > 0.0f) {
326 SkASSERT(srcDrawContext);
327
328 // Clear out a radius below the srcRect to prevent the Y
329 // convolution from reading garbage.
330 clearRect = SkIRect::MakeXYWH(srcRect.fLeft, srcRect.fBottom,
331 srcRect.width(), radiusY);
332 srcDrawContext->clear(&clearRect, 0x0, false);
333 }
334
335 convolve_gaussian(dstDrawContext.get(), clip, srcRect,
336 srcTexture.get(), Gr1DKernelEffect::kY_Direction, radi usY, sigmaY,
337 srcBounds, srcOffset);
338
339 srcDrawContext = dstDrawContext;
340 srcRect.offsetTo(0, 0);
341 dstDrawContext.swap(tmpDrawContext);
342 }
343
344 SkASSERT(srcDrawContext);
345 srcTexture = nullptr; // we don't use this from here on out
346
347 if (scaleFactorX > 1 || scaleFactorY > 1) {
348 // Clear one pixel to the right and below, to accommodate bilinear upsam pling.
349 clearRect = SkIRect::MakeXYWH(srcRect.fLeft, srcRect.fBottom, srcRect.wi dth() + 1, 1);
350 srcDrawContext->clear(&clearRect, 0x0, false);
351 clearRect = SkIRect::MakeXYWH(srcRect.fRight, srcRect.fTop, 1, srcRect.h eight());
352 srcDrawContext->clear(&clearRect, 0x0, false);
353
354 SkMatrix matrix;
355 matrix.setIDiv(srcDrawContext->width(), srcDrawContext->height());
356
357 GrPaint paint;
358 paint.setGammaCorrect(dstDrawContext->isGammaCorrect());
359 // FIXME: this should be mitchell, not bilinear.
360 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBile rp_FilterMode);
361 sk_sp<GrTexture> tex(srcDrawContext->asTexture());
362 paint.addColorTextureProcessor(tex.get(), nullptr, matrix, params);
363 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
364
365 SkIRect dstRect(srcRect);
366 scale_irect(&dstRect, scaleFactorX, scaleFactorY);
367
368 dstDrawContext->fillRectToRect(clip, paint, SkMatrix::I(),
369 SkRect::Make(dstRect), SkRect::Make(srcRe ct));
370
371 srcDrawContext = dstDrawContext;
372 srcRect = dstRect;
373 dstDrawContext.swap(tmpDrawContext);
374 }
375
376 return srcDrawContext;
377 }
378
379 }
380
381 #endif
382
OLDNEW
« no previous file with comments | « src/core/SkGpuBlurUtils.h ('k') | src/effects/SkBlurImageFilter.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698