blob: 1cb2d1dd125692b5e348491aa6eb81254b119761 [file] [log] [blame]
robertphillips@google.com736dd032013-07-15 15:06:54 +00001/*
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"
joshualitt5acfea72014-08-11 13:55:34 -070014#include "effects/GrMatrixConvolutionEffect.h"
robertphillips@google.com736dd032013-07-15 15:06:54 +000015#include "GrContext.h"
bsalomon76228632015-05-29 08:02:10 -070016#include "GrCaps.h"
robertphillipsea461502015-05-26 11:38:03 -070017#include "GrDrawContext.h"
robertphillips@google.com736dd032013-07-15 15:06:54 +000018#endif
19
20namespace SkGpuBlurUtils {
21
22#if SK_SUPPORT_GPU
23
24#define MAX_BLUR_SIGMA 4.0f
25
26static void scale_rect(SkRect* rect, float xScale, float yScale) {
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000027 rect->fLeft = SkScalarMul(rect->fLeft, xScale);
28 rect->fTop = SkScalarMul(rect->fTop, yScale);
29 rect->fRight = SkScalarMul(rect->fRight, xScale);
30 rect->fBottom = SkScalarMul(rect->fBottom, yScale);
robertphillips@google.com736dd032013-07-15 15:06:54 +000031}
32
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +000033static float adjust_sigma(float sigma, int maxTextureSize, int *scaleFactor, int *radius) {
robertphillips@google.com736dd032013-07-15 15:06:54 +000034 *scaleFactor = 1;
35 while (sigma > MAX_BLUR_SIGMA) {
36 *scaleFactor *= 2;
37 sigma *= 0.5f;
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +000038 if (*scaleFactor > maxTextureSize) {
39 *scaleFactor = maxTextureSize;
40 sigma = MAX_BLUR_SIGMA;
41 }
robertphillips@google.com736dd032013-07-15 15:06:54 +000042 }
43 *radius = static_cast<int>(ceilf(sigma * 3.0f));
commit-bot@chromium.org96ae6882013-08-14 12:09:00 +000044 SkASSERT(*radius <= GrConvolutionEffect::kMaxKernelRadius);
robertphillips@google.com736dd032013-07-15 15:06:54 +000045 return sigma;
46}
47
robertphillipsea461502015-05-26 11:38:03 -070048static void convolve_gaussian_1d(GrDrawContext* drawContext,
joshualitt570d2f82015-02-25 13:19:48 -080049 const GrClip& clip,
joshualitt5acfea72014-08-11 13:55:34 -070050 const SkRect& dstRect,
senorblanco48343ee2015-11-03 05:07:43 -080051 const SkPoint& srcOffset,
joshualitt5acfea72014-08-11 13:55:34 -070052 GrTexture* texture,
53 Gr1DKernelEffect::Direction direction,
54 int radius,
55 float sigma,
56 bool useBounds,
57 float bounds[2]) {
robertphillips@google.com736dd032013-07-15 15:06:54 +000058 GrPaint paint;
brianosmanb461d342016-04-13 13:10:14 -070059 paint.setGammaCorrect(drawContext->isGammaCorrect());
joshualittb0a8a372014-09-23 09:50:21 -070060 SkAutoTUnref<GrFragmentProcessor> conv(GrConvolutionEffect::CreateGaussian(
bsalomon4a339522015-10-06 08:40:50 -070061 texture, direction, radius, sigma, useBounds, bounds));
bsalomonac856c92015-08-27 06:30:17 -070062 paint.addColorFragmentProcessor(conv);
egdanielc4b72722015-11-23 13:20:41 -080063 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
senorblancoc834ab12015-12-17 08:10:17 -080064 SkMatrix localMatrix = SkMatrix::MakeTrans(-srcOffset.x(), -srcOffset.y());
bsalomona2e69fc2015-11-05 10:41:43 -080065 drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), dstRect, localMatrix);
robertphillips@google.com736dd032013-07-15 15:06:54 +000066}
67
robertphillipsea461502015-05-26 11:38:03 -070068static void convolve_gaussian_2d(GrDrawContext* drawContext,
joshualitt570d2f82015-02-25 13:19:48 -080069 const GrClip& clip,
senorblancoc834ab12015-12-17 08:10:17 -080070 const SkRect& dstRect,
71 const SkPoint& srcOffset,
joshualitt5acfea72014-08-11 13:55:34 -070072 GrTexture* texture,
73 int radiusX,
74 int radiusY,
75 SkScalar sigmaX,
76 SkScalar sigmaY,
senorblanco07d56b12015-11-10 07:32:37 -080077 const SkRect* srcBounds) {
senorblancoc834ab12015-12-17 08:10:17 -080078 SkMatrix localMatrix = SkMatrix::MakeTrans(-srcOffset.x(), -srcOffset.y());
joshualitt5acfea72014-08-11 13:55:34 -070079 SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1);
80 SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY);
81 GrPaint paint;
brianosmanb461d342016-04-13 13:10:14 -070082 paint.setGammaCorrect(drawContext->isGammaCorrect());
senorblanco07d56b12015-11-10 07:32:37 -080083 SkIRect bounds;
84 if (srcBounds) {
85 srcBounds->roundOut(&bounds);
86 } else {
87 bounds.setEmpty();
88 }
89
joshualittb0a8a372014-09-23 09:50:21 -070090 SkAutoTUnref<GrFragmentProcessor> conv(GrMatrixConvolutionEffect::CreateGaussian(
joshualitt5acfea72014-08-11 13:55:34 -070091 texture, bounds, size, 1.0, 0.0, kernelOffset,
senorblanco07d56b12015-11-10 07:32:37 -080092 srcBounds ? GrTextureDomain::kDecal_Mode : GrTextureDomain::kIgnore_Mode,
joshualitt5acfea72014-08-11 13:55:34 -070093 true, sigmaX, sigmaY));
bsalomonac856c92015-08-27 06:30:17 -070094 paint.addColorFragmentProcessor(conv);
egdanielc4b72722015-11-23 13:20:41 -080095 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
bsalomona2e69fc2015-11-05 10:41:43 -080096 drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), dstRect, localMatrix);
joshualitt5acfea72014-08-11 13:55:34 -070097}
98
robertphillipsea461502015-05-26 11:38:03 -070099static void convolve_gaussian(GrDrawContext* drawContext,
joshualitt570d2f82015-02-25 13:19:48 -0800100 const GrClip& clip,
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000101 const SkRect& srcRect,
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000102 GrTexture* texture,
103 Gr1DKernelEffect::Direction direction,
104 int radius,
105 float sigma,
senorblanco07d56b12015-11-10 07:32:37 -0800106 const SkRect* srcBounds,
107 const SkPoint& srcOffset) {
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000108 float bounds[2] = { 0.0f, 1.0f };
senorblanco48343ee2015-11-03 05:07:43 -0800109 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
senorblanco07d56b12015-11-10 07:32:37 -0800110 if (!srcBounds) {
senorblanco48343ee2015-11-03 05:07:43 -0800111 convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture,
joshualitt5acfea72014-08-11 13:55:34 -0700112 direction, radius, sigma, false, bounds);
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000113 return;
114 }
senorblanco07d56b12015-11-10 07:32:37 -0800115 SkRect midRect = *srcBounds, leftRect, rightRect;
116 midRect.offset(srcOffset);
117 SkIRect topRect, bottomRect;
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000118 SkScalar rad = SkIntToScalar(radius);
119 if (direction == Gr1DKernelEffect::kX_Direction) {
senorblanco07d56b12015-11-10 07:32:37 -0800120 bounds[0] = SkScalarToFloat(srcBounds->left()) / texture->width();
121 bounds[1] = SkScalarToFloat(srcBounds->right()) / texture->width();
122 SkRect::MakeLTRB(0, 0, dstRect.right(), midRect.top()).roundOut(&topRect);
123 SkRect::MakeLTRB(0, midRect.bottom(), dstRect.right(), dstRect.bottom())
124 .roundOut(&bottomRect);
125 midRect.inset(rad, 0);
126 leftRect = SkRect::MakeLTRB(0, midRect.top(), midRect.left(), midRect.bottom());
127 rightRect =
128 SkRect::MakeLTRB(midRect.right(), midRect.top(), dstRect.width(), midRect.bottom());
129 dstRect.fTop = midRect.top();
130 dstRect.fBottom = midRect.bottom();
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000131 } else {
senorblanco07d56b12015-11-10 07:32:37 -0800132 bounds[0] = SkScalarToFloat(srcBounds->top()) / texture->height();
133 bounds[1] = SkScalarToFloat(srcBounds->bottom()) / texture->height();
134 SkRect::MakeLTRB(0, 0, midRect.left(), dstRect.bottom()).roundOut(&topRect);
135 SkRect::MakeLTRB(midRect.right(), 0, dstRect.right(), dstRect.bottom())
136 .roundOut(&bottomRect);;
137 midRect.inset(0, rad);
138 leftRect = SkRect::MakeLTRB(midRect.left(), 0, midRect.right(), midRect.top());
139 rightRect =
140 SkRect::MakeLTRB(midRect.left(), midRect.bottom(), midRect.right(), dstRect.height());
141 dstRect.fLeft = midRect.left();
142 dstRect.fRight = midRect.right();
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000143 }
senorblanco07d56b12015-11-10 07:32:37 -0800144 if (!topRect.isEmpty()) {
145 drawContext->clear(&topRect, 0, false);
146 }
147
148 if (!bottomRect.isEmpty()) {
149 drawContext->clear(&bottomRect, 0, false);
150 }
151 if (midRect.isEmpty()) {
152 // Blur radius covers srcBounds; use bounds over entire draw
senorblancoc834ab12015-12-17 08:10:17 -0800153 convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture,
joshualitt5acfea72014-08-11 13:55:34 -0700154 direction, radius, sigma, true, bounds);
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000155 } else {
senorblanco07d56b12015-11-10 07:32:37 -0800156 // Draw right and left margins with bounds; middle without.
senorblancoc834ab12015-12-17 08:10:17 -0800157 convolve_gaussian_1d(drawContext, clip, leftRect, srcOffset, texture,
joshualitt5acfea72014-08-11 13:55:34 -0700158 direction, radius, sigma, true, bounds);
senorblancoc834ab12015-12-17 08:10:17 -0800159 convolve_gaussian_1d(drawContext, clip, rightRect, srcOffset, texture,
joshualitt5acfea72014-08-11 13:55:34 -0700160 direction, radius, sigma, true, bounds);
senorblancoc834ab12015-12-17 08:10:17 -0800161 convolve_gaussian_1d(drawContext, clip, midRect, srcOffset, texture,
joshualitt5acfea72014-08-11 13:55:34 -0700162 direction, radius, sigma, false, bounds);
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000163 }
164}
165
robertphillips@google.com736dd032013-07-15 15:06:54 +0000166GrTexture* GaussianBlur(GrContext* context,
167 GrTexture* srcTexture,
brianosmanb461d342016-04-13 13:10:14 -0700168 bool gammaCorrect,
senorblanco07d56b12015-11-10 07:32:37 -0800169 const SkRect& dstBounds,
170 const SkRect* srcBounds,
skia.committer@gmail.com977409a2013-07-16 07:00:56 +0000171 float sigmaX,
reed4e23cda2016-01-11 10:56:59 -0800172 float sigmaY) {
bsalomon49f085d2014-09-05 13:34:00 -0700173 SkASSERT(context);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000174 SkIRect clearRect;
175 int scaleFactorX, radiusX;
176 int scaleFactorY, radiusY;
bsalomon76228632015-05-29 08:02:10 -0700177 int maxTextureSize = context->caps()->maxTextureSize();
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +0000178 sigmaX = adjust_sigma(sigmaX, maxTextureSize, &scaleFactorX, &radiusX);
179 sigmaY = adjust_sigma(sigmaY, maxTextureSize, &scaleFactorY, &radiusY);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000180
senorblanco07d56b12015-11-10 07:32:37 -0800181 SkPoint srcOffset = SkPoint::Make(-dstBounds.x(), -dstBounds.y());
182 SkRect localDstBounds = SkRect::MakeWH(dstBounds.width(), dstBounds.height());
183 SkRect localSrcBounds;
184 SkRect srcRect;
185 if (srcBounds) {
186 srcRect = localSrcBounds = *srcBounds;
187 srcRect.offset(srcOffset);
188 srcBounds = &localSrcBounds;
189 } else {
190 srcRect = localDstBounds;
191 }
192
robertphillips@google.com736dd032013-07-15 15:06:54 +0000193 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
reedd02cf262014-11-18 18:06:45 -0800194 srcRect.roundOut(&srcRect);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000195 scale_rect(&srcRect, static_cast<float>(scaleFactorX),
196 static_cast<float>(scaleFactorY));
197
joshualitt570d2f82015-02-25 13:19:48 -0800198 // setup new clip
senorblanco07d56b12015-11-10 07:32:37 -0800199 GrClip clip(localDstBounds);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000200
commit-bot@chromium.org96ae6882013-08-14 12:09:00 +0000201 SkASSERT(kBGRA_8888_GrPixelConfig == srcTexture->config() ||
robertphillips@google.com736dd032013-07-15 15:06:54 +0000202 kRGBA_8888_GrPixelConfig == srcTexture->config() ||
brianosmana6359362016-03-21 06:55:37 -0700203 kSRGBA_8888_GrPixelConfig == srcTexture->config() ||
204 kSBGRA_8888_GrPixelConfig == srcTexture->config() ||
robertphillips@google.com736dd032013-07-15 15:06:54 +0000205 kAlpha_8_GrPixelConfig == srcTexture->config());
206
robertphillipsa8966a82016-05-09 06:45:37 -0700207 const int width = SkScalarFloorToInt(dstBounds.width());
208 const int height = SkScalarFloorToInt(dstBounds.height());
209 const GrPixelConfig config = srcTexture->config();
210
211 const SkSurfaceProps props(gammaCorrect ? SkSurfaceProps::kGammaCorrect_Flag : 0,
212 SkSurfaceProps::kLegacyFontHost_InitType);
213
214 // For really small blurs (certainly no wider than 5x5 on desktop gpus) it is faster to just
215 // launch a single non separable kernel vs two launches
216 if (sigmaX > 0.0f && sigmaY > 0.0f &&
217 (2 * radiusX + 1) * (2 * radiusY + 1) <= MAX_KERNEL_SIZE) {
218 // We shouldn't be scaling because this is a small size blur
219 SkASSERT((1 == scaleFactorX) && (1 == scaleFactorY));
220
221 sk_sp<GrDrawContext> dstDrawContext(context->newDrawContext(SkBackingFit::kApprox,
222 width, height, config,
223 0, kDefault_GrSurfaceOrigin,
224 &props));
225 if (!dstDrawContext) {
226 return nullptr;
227 }
228 convolve_gaussian_2d(dstDrawContext.get(), clip, localDstBounds, srcOffset,
229 srcTexture, radiusX, radiusY, sigmaX, sigmaY, srcBounds);
230
231 return dstDrawContext->asTexture().release();
232 }
233
bsalomonf2703d82014-10-28 14:33:06 -0700234 GrSurfaceDesc desc;
bsalomon6bc1b5f2015-02-23 09:06:38 -0800235 desc.fFlags = kRenderTarget_GrSurfaceFlag;
robertphillipsa8966a82016-05-09 06:45:37 -0700236 desc.fWidth = width;
237 desc.fHeight = height;
238 desc.fConfig = config;
robertphillips@google.com736dd032013-07-15 15:06:54 +0000239
bsalomone3059732014-10-14 11:47:22 -0700240 GrTexture* dstTexture;
241 GrTexture* tempTexture;
242 SkAutoTUnref<GrTexture> temp1, temp2;
243
reed4e23cda2016-01-11 10:56:59 -0800244 temp1.reset(context->textureProvider()->createApproxTexture(desc));
bsalomone3059732014-10-14 11:47:22 -0700245 dstTexture = temp1.get();
robertphillipsa8966a82016-05-09 06:45:37 -0700246 temp2.reset(context->textureProvider()->createApproxTexture(desc));
247 tempTexture = temp2.get();
bsalomone3059732014-10-14 11:47:22 -0700248
robertphillipsa8966a82016-05-09 06:45:37 -0700249 if (!dstTexture || !tempTexture) {
halcanary96fcdcc2015-08-27 07:41:13 -0700250 return nullptr;
robertphillips@google.com736dd032013-07-15 15:06:54 +0000251 }
252
robertphillips6c7e3252016-04-27 10:47:51 -0700253 sk_sp<GrDrawContext> srcDrawContext;
robertphillipsea461502015-05-26 11:38:03 -0700254
robertphillips@google.com736dd032013-07-15 15:06:54 +0000255 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
256 GrPaint paint;
brianosmanb461d342016-04-13 13:10:14 -0700257 paint.setGammaCorrect(gammaCorrect);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000258 SkMatrix matrix;
259 matrix.setIDiv(srcTexture->width(), srcTexture->height());
robertphillips@google.com736dd032013-07-15 15:06:54 +0000260 SkRect dstRect(srcRect);
senorblanco07d56b12015-11-10 07:32:37 -0800261 if (srcBounds && i == 1) {
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000262 SkRect domain;
senorblanco07d56b12015-11-10 07:32:37 -0800263 matrix.mapRect(&domain, *srcBounds);
264 domain.inset((i < scaleFactorX) ? SK_ScalarHalf / srcTexture->width() : 0.0f,
265 (i < scaleFactorY) ? SK_ScalarHalf / srcTexture->height() : 0.0f);
robertphillipsa8966a82016-05-09 06:45:37 -0700266 sk_sp<const GrFragmentProcessor> fp(GrTextureDomainEffect::Create(
267 srcTexture,
268 matrix,
269 domain,
270 GrTextureDomain::kDecal_Mode,
271 GrTextureParams::kBilerp_FilterMode));
272 paint.addColorFragmentProcessor(fp.get());
senorblanco07d56b12015-11-10 07:32:37 -0800273 srcRect.offset(-srcOffset);
274 srcOffset.set(0, 0);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000275 } else {
humper@google.comb86add12013-07-25 18:49:07 +0000276 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode);
joshualittb0a8a372014-09-23 09:50:21 -0700277 paint.addColorTextureProcessor(srcTexture, matrix, params);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000278 }
egdanielc4b72722015-11-23 13:20:41 -0800279 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000280 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
281 i < scaleFactorY ? 0.5f : 1.0f);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700282
robertphillips6c7e3252016-04-27 10:47:51 -0700283 sk_sp<GrDrawContext> dstDrawContext(
284 context->drawContext(sk_ref_sp(dstTexture->asRenderTarget())));
robertphillipsff0ca5e2015-07-22 11:54:44 -0700285 if (!dstDrawContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700286 return nullptr;
robertphillipsff0ca5e2015-07-22 11:54:44 -0700287 }
bsalomona2e69fc2015-11-05 10:41:43 -0800288 dstDrawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700289
bungeman77a53de2015-10-01 12:28:49 -0700290 srcDrawContext.swap(dstDrawContext);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000291 srcRect = dstRect;
292 srcTexture = dstTexture;
293 SkTSwap(dstTexture, tempTexture);
senorblanco07d56b12015-11-10 07:32:37 -0800294 localSrcBounds = srcRect;
robertphillips@google.com736dd032013-07-15 15:06:54 +0000295 }
296
senorblancoc834ab12015-12-17 08:10:17 -0800297 srcRect = localDstBounds;
robertphillipsa8966a82016-05-09 06:45:37 -0700298
299 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
300 srcRect.roundOut(&srcRect);
301 SkIRect srcIRect = srcRect.roundOut();
302 if (sigmaX > 0.0f) {
303 if (scaleFactorX > 1) {
304 // TODO: if we pass in the source draw context we don't need this here
305 if (!srcDrawContext) {
306 srcDrawContext = context->drawContext(sk_ref_sp(srcTexture->asRenderTarget()));
307 if (!srcDrawContext) {
308 return nullptr;
309 }
310 }
311
312 // Clear out a radius to the right of the srcRect to prevent the
313 // X convolution from reading garbage.
314 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
315 radiusX, srcIRect.height());
316 srcDrawContext->clear(&clearRect, 0x0, false);
317 }
robertphillipsff0ca5e2015-07-22 11:54:44 -0700318
robertphillips6c7e3252016-04-27 10:47:51 -0700319 sk_sp<GrDrawContext> dstDrawContext(
320 context->drawContext(sk_ref_sp(dstTexture->asRenderTarget()), &props));
robertphillipsff0ca5e2015-07-22 11:54:44 -0700321 if (!dstDrawContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700322 return nullptr;
robertphillipsff0ca5e2015-07-22 11:54:44 -0700323 }
robertphillipsa8966a82016-05-09 06:45:37 -0700324 convolve_gaussian(dstDrawContext.get(), clip, srcRect,
325 srcTexture, Gr1DKernelEffect::kX_Direction, radiusX, sigmaX,
326 srcBounds, srcOffset);
327 srcDrawContext.swap(dstDrawContext);
328 srcTexture = dstTexture;
329 srcRect.offsetTo(0, 0);
330 SkTSwap(dstTexture, tempTexture);
331 localSrcBounds = srcRect;
332 srcOffset.set(0, 0);
333 }
334
335 if (sigmaY > 0.0f) {
336 if (scaleFactorY > 1 || sigmaX > 0.0f) {
337 // TODO: if we pass in the source draw context we don't need this here
338 if (!srcDrawContext) {
339 srcDrawContext = context->drawContext(sk_ref_sp(srcTexture->asRenderTarget()));
340 if (!srcDrawContext) {
341 return nullptr;
342 }
343 }
344
345 // Clear out a radius below the srcRect to prevent the Y
346 // convolution from reading garbage.
347 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
348 srcIRect.width(), radiusY);
349 srcDrawContext->clear(&clearRect, 0x0, false);
350 }
351
352 sk_sp<GrDrawContext> dstDrawContext(
353 context->drawContext(sk_ref_sp(dstTexture->asRenderTarget()), &props));
354 if (!dstDrawContext) {
355 return nullptr;
356 }
357 convolve_gaussian(dstDrawContext.get(), clip, srcRect,
358 srcTexture, Gr1DKernelEffect::kY_Direction, radiusY, sigmaY,
359 srcBounds, srcOffset);
robertphillips56a85e62016-05-06 07:17:49 -0700360
jvanverth67a58dc2016-05-06 13:05:09 -0700361 srcDrawContext.swap(dstDrawContext);
jvanverth67a58dc2016-05-06 13:05:09 -0700362 srcTexture = dstTexture;
robertphillipsa8966a82016-05-09 06:45:37 -0700363 srcRect.offsetTo(0, 0);
jvanverth67a58dc2016-05-06 13:05:09 -0700364 SkTSwap(dstTexture, tempTexture);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000365 }
robertphillipsa8966a82016-05-09 06:45:37 -0700366
367 srcIRect = srcRect.roundOut();
robertphillips@google.com736dd032013-07-15 15:06:54 +0000368
369 if (scaleFactorX > 1 || scaleFactorY > 1) {
robertphillipsff0ca5e2015-07-22 11:54:44 -0700370 SkASSERT(srcDrawContext);
371
robertphillips@google.com736dd032013-07-15 15:06:54 +0000372 // Clear one pixel to the right and below, to accommodate bilinear
373 // upsampling.
374 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
375 srcIRect.width() + 1, 1);
robertphillips2e1e51f2015-10-15 08:01:48 -0700376 srcDrawContext->clear(&clearRect, 0x0, false);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000377 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
378 1, srcIRect.height());
robertphillips2e1e51f2015-10-15 08:01:48 -0700379 srcDrawContext->clear(&clearRect, 0x0, false);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000380 SkMatrix matrix;
381 matrix.setIDiv(srcTexture->width(), srcTexture->height());
robertphillips@google.com736dd032013-07-15 15:06:54 +0000382
383 GrPaint paint;
brianosmanb461d342016-04-13 13:10:14 -0700384 paint.setGammaCorrect(gammaCorrect);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000385 // FIXME: this should be mitchell, not bilinear.
humper@google.comb86add12013-07-25 18:49:07 +0000386 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode);
joshualittb0a8a372014-09-23 09:50:21 -0700387 paint.addColorTextureProcessor(srcTexture, matrix, params);
egdanielc4b72722015-11-23 13:20:41 -0800388 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000389
390 SkRect dstRect(srcRect);
391 scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700392
robertphillips6c7e3252016-04-27 10:47:51 -0700393 sk_sp<GrDrawContext> dstDrawContext(
394 context->drawContext(sk_ref_sp(dstTexture->asRenderTarget())));
robertphillipsff0ca5e2015-07-22 11:54:44 -0700395 if (!dstDrawContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700396 return nullptr;
robertphillipsff0ca5e2015-07-22 11:54:44 -0700397 }
bsalomona2e69fc2015-11-05 10:41:43 -0800398 dstDrawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700399
bungeman77a53de2015-10-01 12:28:49 -0700400 srcDrawContext.swap(dstDrawContext);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000401 srcRect = dstRect;
402 srcTexture = dstTexture;
403 SkTSwap(dstTexture, tempTexture);
404 }
robertphillipsff0ca5e2015-07-22 11:54:44 -0700405
bsalomone3059732014-10-14 11:47:22 -0700406 return SkRef(srcTexture);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000407}
408#endif
409
robertphillips@google.comcce41022013-07-15 15:47:10 +0000410}