blob: 2e6a7d6bde96f9b43d9b8032ec813c5c90b8af7d [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;
joshualittb0a8a372014-09-23 09:50:21 -070059 SkAutoTUnref<GrFragmentProcessor> conv(GrConvolutionEffect::CreateGaussian(
bsalomon4a339522015-10-06 08:40:50 -070060 texture, direction, radius, sigma, useBounds, bounds));
bsalomonac856c92015-08-27 06:30:17 -070061 paint.addColorFragmentProcessor(conv);
senorblanco48343ee2015-11-03 05:07:43 -080062 SkMatrix localMatrix = SkMatrix::MakeTrans(srcOffset.x(), srcOffset.y());
bsalomona2e69fc2015-11-05 10:41:43 -080063 drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), dstRect, localMatrix);
robertphillips@google.com736dd032013-07-15 15:06:54 +000064}
65
robertphillipsea461502015-05-26 11:38:03 -070066static void convolve_gaussian_2d(GrDrawContext* drawContext,
joshualitt570d2f82015-02-25 13:19:48 -080067 const GrClip& clip,
joshualitt5acfea72014-08-11 13:55:34 -070068 const SkRect& srcRect,
joshualitt5acfea72014-08-11 13:55:34 -070069 GrTexture* texture,
70 int radiusX,
71 int radiusY,
72 SkScalar sigmaX,
73 SkScalar sigmaY,
senorblanco07d56b12015-11-10 07:32:37 -080074 const SkRect* srcBounds) {
senorblanco48343ee2015-11-03 05:07:43 -080075 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
76 SkMatrix localMatrix = SkMatrix::MakeTrans(srcRect.x(), srcRect.y());
joshualitt5acfea72014-08-11 13:55:34 -070077 SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1);
78 SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY);
79 GrPaint paint;
senorblanco07d56b12015-11-10 07:32:37 -080080 SkIRect bounds;
81 if (srcBounds) {
82 srcBounds->roundOut(&bounds);
83 } else {
84 bounds.setEmpty();
85 }
86
joshualittb0a8a372014-09-23 09:50:21 -070087 SkAutoTUnref<GrFragmentProcessor> conv(GrMatrixConvolutionEffect::CreateGaussian(
joshualitt5acfea72014-08-11 13:55:34 -070088 texture, bounds, size, 1.0, 0.0, kernelOffset,
senorblanco07d56b12015-11-10 07:32:37 -080089 srcBounds ? GrTextureDomain::kDecal_Mode : GrTextureDomain::kIgnore_Mode,
joshualitt5acfea72014-08-11 13:55:34 -070090 true, sigmaX, sigmaY));
bsalomonac856c92015-08-27 06:30:17 -070091 paint.addColorFragmentProcessor(conv);
bsalomona2e69fc2015-11-05 10:41:43 -080092 drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), dstRect, localMatrix);
joshualitt5acfea72014-08-11 13:55:34 -070093}
94
robertphillipsea461502015-05-26 11:38:03 -070095static void convolve_gaussian(GrDrawContext* drawContext,
joshualitt570d2f82015-02-25 13:19:48 -080096 const GrClip& clip,
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +000097 const SkRect& srcRect,
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +000098 GrTexture* texture,
99 Gr1DKernelEffect::Direction direction,
100 int radius,
101 float sigma,
senorblanco07d56b12015-11-10 07:32:37 -0800102 const SkRect* srcBounds,
103 const SkPoint& srcOffset) {
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000104 float bounds[2] = { 0.0f, 1.0f };
senorblanco48343ee2015-11-03 05:07:43 -0800105 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
senorblanco07d56b12015-11-10 07:32:37 -0800106 if (!srcBounds) {
senorblanco48343ee2015-11-03 05:07:43 -0800107 convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture,
joshualitt5acfea72014-08-11 13:55:34 -0700108 direction, radius, sigma, false, bounds);
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000109 return;
110 }
senorblanco07d56b12015-11-10 07:32:37 -0800111 SkRect midRect = *srcBounds, leftRect, rightRect;
112 midRect.offset(srcOffset);
113 SkIRect topRect, bottomRect;
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000114 SkScalar rad = SkIntToScalar(radius);
115 if (direction == Gr1DKernelEffect::kX_Direction) {
senorblanco07d56b12015-11-10 07:32:37 -0800116 bounds[0] = SkScalarToFloat(srcBounds->left()) / texture->width();
117 bounds[1] = SkScalarToFloat(srcBounds->right()) / texture->width();
118 SkRect::MakeLTRB(0, 0, dstRect.right(), midRect.top()).roundOut(&topRect);
119 SkRect::MakeLTRB(0, midRect.bottom(), dstRect.right(), dstRect.bottom())
120 .roundOut(&bottomRect);
121 midRect.inset(rad, 0);
122 leftRect = SkRect::MakeLTRB(0, midRect.top(), midRect.left(), midRect.bottom());
123 rightRect =
124 SkRect::MakeLTRB(midRect.right(), midRect.top(), dstRect.width(), midRect.bottom());
125 dstRect.fTop = midRect.top();
126 dstRect.fBottom = midRect.bottom();
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000127 } else {
senorblanco07d56b12015-11-10 07:32:37 -0800128 bounds[0] = SkScalarToFloat(srcBounds->top()) / texture->height();
129 bounds[1] = SkScalarToFloat(srcBounds->bottom()) / texture->height();
130 SkRect::MakeLTRB(0, 0, midRect.left(), dstRect.bottom()).roundOut(&topRect);
131 SkRect::MakeLTRB(midRect.right(), 0, dstRect.right(), dstRect.bottom())
132 .roundOut(&bottomRect);;
133 midRect.inset(0, rad);
134 leftRect = SkRect::MakeLTRB(midRect.left(), 0, midRect.right(), midRect.top());
135 rightRect =
136 SkRect::MakeLTRB(midRect.left(), midRect.bottom(), midRect.right(), dstRect.height());
137 dstRect.fLeft = midRect.left();
138 dstRect.fRight = midRect.right();
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000139 }
senorblanco07d56b12015-11-10 07:32:37 -0800140 if (!topRect.isEmpty()) {
141 drawContext->clear(&topRect, 0, false);
142 }
143
144 if (!bottomRect.isEmpty()) {
145 drawContext->clear(&bottomRect, 0, false);
146 }
147 if (midRect.isEmpty()) {
148 // Blur radius covers srcBounds; use bounds over entire draw
149 convolve_gaussian_1d(drawContext, clip, dstRect, -srcOffset, texture,
joshualitt5acfea72014-08-11 13:55:34 -0700150 direction, radius, sigma, true, bounds);
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000151 } else {
senorblanco07d56b12015-11-10 07:32:37 -0800152 // Draw right and left margins with bounds; middle without.
153 convolve_gaussian_1d(drawContext, clip, leftRect, -srcOffset, texture,
joshualitt5acfea72014-08-11 13:55:34 -0700154 direction, radius, sigma, true, bounds);
senorblanco07d56b12015-11-10 07:32:37 -0800155 convolve_gaussian_1d(drawContext, clip, rightRect, -srcOffset, texture,
joshualitt5acfea72014-08-11 13:55:34 -0700156 direction, radius, sigma, true, bounds);
senorblanco07d56b12015-11-10 07:32:37 -0800157 convolve_gaussian_1d(drawContext, clip, midRect, -srcOffset, texture,
joshualitt5acfea72014-08-11 13:55:34 -0700158 direction, radius, sigma, false, bounds);
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000159 }
160}
161
robertphillips@google.com736dd032013-07-15 15:06:54 +0000162GrTexture* GaussianBlur(GrContext* context,
163 GrTexture* srcTexture,
164 bool canClobberSrc,
senorblanco07d56b12015-11-10 07:32:37 -0800165 const SkRect& dstBounds,
166 const SkRect* srcBounds,
skia.committer@gmail.com977409a2013-07-16 07:00:56 +0000167 float sigmaX,
reedc9b5f8b2015-10-22 13:20:20 -0700168 float sigmaY,
169 GrTextureProvider::SizeConstraint constraint) {
bsalomon49f085d2014-09-05 13:34:00 -0700170 SkASSERT(context);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000171 SkIRect clearRect;
172 int scaleFactorX, radiusX;
173 int scaleFactorY, radiusY;
bsalomon76228632015-05-29 08:02:10 -0700174 int maxTextureSize = context->caps()->maxTextureSize();
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +0000175 sigmaX = adjust_sigma(sigmaX, maxTextureSize, &scaleFactorX, &radiusX);
176 sigmaY = adjust_sigma(sigmaY, maxTextureSize, &scaleFactorY, &radiusY);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000177
senorblanco07d56b12015-11-10 07:32:37 -0800178 SkPoint srcOffset = SkPoint::Make(-dstBounds.x(), -dstBounds.y());
179 SkRect localDstBounds = SkRect::MakeWH(dstBounds.width(), dstBounds.height());
180 SkRect localSrcBounds;
181 SkRect srcRect;
182 if (srcBounds) {
183 srcRect = localSrcBounds = *srcBounds;
184 srcRect.offset(srcOffset);
185 srcBounds = &localSrcBounds;
186 } else {
187 srcRect = localDstBounds;
188 }
189
robertphillips@google.com736dd032013-07-15 15:06:54 +0000190 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
reedd02cf262014-11-18 18:06:45 -0800191 srcRect.roundOut(&srcRect);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000192 scale_rect(&srcRect, static_cast<float>(scaleFactorX),
193 static_cast<float>(scaleFactorY));
194
joshualitt570d2f82015-02-25 13:19:48 -0800195 // setup new clip
senorblanco07d56b12015-11-10 07:32:37 -0800196 GrClip clip(localDstBounds);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000197
commit-bot@chromium.org96ae6882013-08-14 12:09:00 +0000198 SkASSERT(kBGRA_8888_GrPixelConfig == srcTexture->config() ||
robertphillips@google.com736dd032013-07-15 15:06:54 +0000199 kRGBA_8888_GrPixelConfig == srcTexture->config() ||
200 kAlpha_8_GrPixelConfig == srcTexture->config());
201
bsalomonf2703d82014-10-28 14:33:06 -0700202 GrSurfaceDesc desc;
bsalomon6bc1b5f2015-02-23 09:06:38 -0800203 desc.fFlags = kRenderTarget_GrSurfaceFlag;
senorblanco07d56b12015-11-10 07:32:37 -0800204 desc.fWidth = SkScalarFloorToInt(dstBounds.width());
205 desc.fHeight = SkScalarFloorToInt(dstBounds.height());
robertphillips@google.com736dd032013-07-15 15:06:54 +0000206 desc.fConfig = srcTexture->config();
207
bsalomone3059732014-10-14 11:47:22 -0700208 GrTexture* dstTexture;
209 GrTexture* tempTexture;
210 SkAutoTUnref<GrTexture> temp1, temp2;
211
reedc9b5f8b2015-10-22 13:20:20 -0700212 temp1.reset(context->textureProvider()->createTexture(desc, constraint));
bsalomone3059732014-10-14 11:47:22 -0700213 dstTexture = temp1.get();
214 if (canClobberSrc) {
215 tempTexture = srcTexture;
216 } else {
reedc9b5f8b2015-10-22 13:20:20 -0700217 temp2.reset(context->textureProvider()->createTexture(desc, constraint));
bsalomone3059732014-10-14 11:47:22 -0700218 tempTexture = temp2.get();
219 }
220
halcanary96fcdcc2015-08-27 07:41:13 -0700221 if (nullptr == dstTexture || nullptr == tempTexture) {
222 return nullptr;
robertphillips@google.com736dd032013-07-15 15:06:54 +0000223 }
224
robertphillipsc9a37062015-09-01 08:34:28 -0700225 SkAutoTUnref<GrDrawContext> srcDrawContext;
robertphillipsea461502015-05-26 11:38:03 -0700226
robertphillips@google.com736dd032013-07-15 15:06:54 +0000227 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
228 GrPaint paint;
229 SkMatrix matrix;
230 matrix.setIDiv(srcTexture->width(), srcTexture->height());
robertphillips@google.com736dd032013-07-15 15:06:54 +0000231 SkRect dstRect(srcRect);
senorblanco07d56b12015-11-10 07:32:37 -0800232 if (srcBounds && i == 1) {
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000233 SkRect domain;
senorblanco07d56b12015-11-10 07:32:37 -0800234 matrix.mapRect(&domain, *srcBounds);
235 domain.inset((i < scaleFactorX) ? SK_ScalarHalf / srcTexture->width() : 0.0f,
236 (i < scaleFactorY) ? SK_ScalarHalf / srcTexture->height() : 0.0f);
bsalomon0ba8c242015-10-07 09:20:28 -0700237 SkAutoTUnref<const GrFragmentProcessor> fp(GrTextureDomainEffect::Create(
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000238 srcTexture,
239 matrix,
240 domain,
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000241 GrTextureDomain::kDecal_Mode,
humper@google.comb86add12013-07-25 18:49:07 +0000242 GrTextureParams::kBilerp_FilterMode));
bsalomonac856c92015-08-27 06:30:17 -0700243 paint.addColorFragmentProcessor(fp);
senorblanco07d56b12015-11-10 07:32:37 -0800244 srcRect.offset(-srcOffset);
245 srcOffset.set(0, 0);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000246 } else {
humper@google.comb86add12013-07-25 18:49:07 +0000247 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode);
joshualittb0a8a372014-09-23 09:50:21 -0700248 paint.addColorTextureProcessor(srcTexture, matrix, params);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000249 }
robertphillips@google.com736dd032013-07-15 15:06:54 +0000250 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
251 i < scaleFactorY ? 0.5f : 1.0f);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700252
robertphillips2e1e51f2015-10-15 08:01:48 -0700253 SkAutoTUnref<GrDrawContext> dstDrawContext(
254 context->drawContext(dstTexture->asRenderTarget()));
robertphillipsff0ca5e2015-07-22 11:54:44 -0700255 if (!dstDrawContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700256 return nullptr;
robertphillipsff0ca5e2015-07-22 11:54:44 -0700257 }
bsalomona2e69fc2015-11-05 10:41:43 -0800258 dstDrawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700259
bungeman77a53de2015-10-01 12:28:49 -0700260 srcDrawContext.swap(dstDrawContext);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000261 srcRect = dstRect;
262 srcTexture = dstTexture;
263 SkTSwap(dstTexture, tempTexture);
senorblanco07d56b12015-11-10 07:32:37 -0800264 localSrcBounds = srcRect;
robertphillips@google.com736dd032013-07-15 15:06:54 +0000265 }
266
robertphillipsff0ca5e2015-07-22 11:54:44 -0700267 // For really small blurs (certainly no wider than 5x5 on desktop gpus) it is faster to just
joshualitt5acfea72014-08-11 13:55:34 -0700268 // launch a single non separable kernel vs two launches
robertphillipsff0ca5e2015-07-22 11:54:44 -0700269 if (sigmaX > 0.0f && sigmaY > 0.0f &&
joshualitt5acfea72014-08-11 13:55:34 -0700270 (2 * radiusX + 1) * (2 * radiusY + 1) <= MAX_KERNEL_SIZE) {
271 // We shouldn't be scaling because this is a small size blur
robertphillipsff0ca5e2015-07-22 11:54:44 -0700272 SkASSERT((1 == scaleFactorX) && (1 == scaleFactorY));
robertphillipsff0ca5e2015-07-22 11:54:44 -0700273
robertphillips2e1e51f2015-10-15 08:01:48 -0700274 SkAutoTUnref<GrDrawContext> dstDrawContext(
275 context->drawContext(dstTexture->asRenderTarget()));
robertphillipsff0ca5e2015-07-22 11:54:44 -0700276 if (!dstDrawContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700277 return nullptr;
robertphillipsff0ca5e2015-07-22 11:54:44 -0700278 }
senorblanco48343ee2015-11-03 05:07:43 -0800279 convolve_gaussian_2d(dstDrawContext, clip, srcRect,
senorblanco07d56b12015-11-10 07:32:37 -0800280 srcTexture, radiusX, radiusY, sigmaX, sigmaY, srcBounds);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700281
bungeman77a53de2015-10-01 12:28:49 -0700282 srcDrawContext.swap(dstDrawContext);
senorblanco48343ee2015-11-03 05:07:43 -0800283 srcRect.offsetTo(0, 0);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700284 srcTexture = dstTexture;
robertphillips@google.com736dd032013-07-15 15:06:54 +0000285 SkTSwap(dstTexture, tempTexture);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000286
joshualitt5acfea72014-08-11 13:55:34 -0700287 } else {
senorblanco07d56b12015-11-10 07:32:37 -0800288 srcRect = localDstBounds;
289 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
290 srcRect.roundOut(&srcRect);
291 const SkIRect srcIRect = srcRect.roundOut();
joshualitt5acfea72014-08-11 13:55:34 -0700292 if (sigmaX > 0.0f) {
293 if (scaleFactorX > 1) {
robertphillipsff0ca5e2015-07-22 11:54:44 -0700294 // TODO: if we pass in the source draw context we don't need this here
295 if (!srcDrawContext) {
robertphillips2e1e51f2015-10-15 08:01:48 -0700296 srcDrawContext.reset(context->drawContext(srcTexture->asRenderTarget()));
robertphillipsff0ca5e2015-07-22 11:54:44 -0700297 if (!srcDrawContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700298 return nullptr;
robertphillipsff0ca5e2015-07-22 11:54:44 -0700299 }
300 }
301
joshualitt5acfea72014-08-11 13:55:34 -0700302 // Clear out a radius to the right of the srcRect to prevent the
303 // X convolution from reading garbage.
304 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
305 radiusX, srcIRect.height());
robertphillips2e1e51f2015-10-15 08:01:48 -0700306 srcDrawContext->clear(&clearRect, 0x0, false);
joshualitt5acfea72014-08-11 13:55:34 -0700307 }
robertphillipsff0ca5e2015-07-22 11:54:44 -0700308
robertphillips2e1e51f2015-10-15 08:01:48 -0700309 SkAutoTUnref<GrDrawContext> dstDrawContext(
robertphillips77a2e522015-10-17 07:43:27 -0700310 context->drawContext(dstTexture->asRenderTarget()));
robertphillipsff0ca5e2015-07-22 11:54:44 -0700311 if (!dstDrawContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700312 return nullptr;
robertphillipsff0ca5e2015-07-22 11:54:44 -0700313 }
senorblanco48343ee2015-11-03 05:07:43 -0800314 convolve_gaussian(dstDrawContext, clip, srcRect,
joshualitt570d2f82015-02-25 13:19:48 -0800315 srcTexture, Gr1DKernelEffect::kX_Direction, radiusX, sigmaX,
senorblanco07d56b12015-11-10 07:32:37 -0800316 srcBounds, srcOffset);
bungeman77a53de2015-10-01 12:28:49 -0700317 srcDrawContext.swap(dstDrawContext);
joshualitt5acfea72014-08-11 13:55:34 -0700318 srcTexture = dstTexture;
senorblanco48343ee2015-11-03 05:07:43 -0800319 srcRect.offsetTo(0, 0);
joshualitt5acfea72014-08-11 13:55:34 -0700320 SkTSwap(dstTexture, tempTexture);
senorblanco07d56b12015-11-10 07:32:37 -0800321 localSrcBounds = srcRect;
322 srcOffset.set(0, 0);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000323 }
324
joshualitt5acfea72014-08-11 13:55:34 -0700325 if (sigmaY > 0.0f) {
326 if (scaleFactorY > 1 || sigmaX > 0.0f) {
robertphillipsff0ca5e2015-07-22 11:54:44 -0700327 // TODO: if we pass in the source draw context we don't need this here
328 if (!srcDrawContext) {
robertphillips2e1e51f2015-10-15 08:01:48 -0700329 srcDrawContext.reset(context->drawContext(srcTexture->asRenderTarget()));
robertphillipsff0ca5e2015-07-22 11:54:44 -0700330 if (!srcDrawContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700331 return nullptr;
robertphillipsff0ca5e2015-07-22 11:54:44 -0700332 }
333 }
334
joshualitt5acfea72014-08-11 13:55:34 -0700335 // Clear out a radius below the srcRect to prevent the Y
336 // convolution from reading garbage.
337 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
338 srcIRect.width(), radiusY);
robertphillips2e1e51f2015-10-15 08:01:48 -0700339 srcDrawContext->clear(&clearRect, 0x0, false);
joshualitt5acfea72014-08-11 13:55:34 -0700340 }
341
robertphillips2e1e51f2015-10-15 08:01:48 -0700342 SkAutoTUnref<GrDrawContext> dstDrawContext(
robertphillips77a2e522015-10-17 07:43:27 -0700343 context->drawContext(dstTexture->asRenderTarget()));
robertphillipsff0ca5e2015-07-22 11:54:44 -0700344 if (!dstDrawContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700345 return nullptr;
robertphillipsff0ca5e2015-07-22 11:54:44 -0700346 }
robertphillips2e1e51f2015-10-15 08:01:48 -0700347 convolve_gaussian(dstDrawContext, clip, srcRect,
senorblanco48343ee2015-11-03 05:07:43 -0800348 srcTexture, Gr1DKernelEffect::kY_Direction, radiusY, sigmaY,
senorblanco07d56b12015-11-10 07:32:37 -0800349 srcBounds, srcOffset);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700350
bungeman77a53de2015-10-01 12:28:49 -0700351 srcDrawContext.swap(dstDrawContext);
joshualitt5acfea72014-08-11 13:55:34 -0700352 srcTexture = dstTexture;
senorblanco48343ee2015-11-03 05:07:43 -0800353 srcRect.offsetTo(0, 0);
joshualitt5acfea72014-08-11 13:55:34 -0700354 SkTSwap(dstTexture, tempTexture);
355 }
robertphillips@google.com736dd032013-07-15 15:06:54 +0000356 }
senorblanco07d56b12015-11-10 07:32:37 -0800357 const SkIRect srcIRect = srcRect.roundOut();
robertphillips@google.com736dd032013-07-15 15:06:54 +0000358
359 if (scaleFactorX > 1 || scaleFactorY > 1) {
robertphillipsff0ca5e2015-07-22 11:54:44 -0700360 SkASSERT(srcDrawContext);
361
robertphillips@google.com736dd032013-07-15 15:06:54 +0000362 // Clear one pixel to the right and below, to accommodate bilinear
363 // upsampling.
364 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
365 srcIRect.width() + 1, 1);
robertphillips2e1e51f2015-10-15 08:01:48 -0700366 srcDrawContext->clear(&clearRect, 0x0, false);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000367 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
368 1, srcIRect.height());
robertphillips2e1e51f2015-10-15 08:01:48 -0700369 srcDrawContext->clear(&clearRect, 0x0, false);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000370 SkMatrix matrix;
371 matrix.setIDiv(srcTexture->width(), srcTexture->height());
robertphillips@google.com736dd032013-07-15 15:06:54 +0000372
373 GrPaint paint;
374 // FIXME: this should be mitchell, not bilinear.
humper@google.comb86add12013-07-25 18:49:07 +0000375 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode);
joshualittb0a8a372014-09-23 09:50:21 -0700376 paint.addColorTextureProcessor(srcTexture, matrix, params);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000377
378 SkRect dstRect(srcRect);
379 scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700380
robertphillips2e1e51f2015-10-15 08:01:48 -0700381 SkAutoTUnref<GrDrawContext> dstDrawContext(
robertphillips77a2e522015-10-17 07:43:27 -0700382 context->drawContext(dstTexture->asRenderTarget()));
robertphillipsff0ca5e2015-07-22 11:54:44 -0700383 if (!dstDrawContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700384 return nullptr;
robertphillipsff0ca5e2015-07-22 11:54:44 -0700385 }
bsalomona2e69fc2015-11-05 10:41:43 -0800386 dstDrawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700387
bungeman77a53de2015-10-01 12:28:49 -0700388 srcDrawContext.swap(dstDrawContext);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000389 srcRect = dstRect;
390 srcTexture = dstTexture;
391 SkTSwap(dstTexture, tempTexture);
392 }
robertphillipsff0ca5e2015-07-22 11:54:44 -0700393
bsalomone3059732014-10-14 11:47:22 -0700394 return SkRef(srcTexture);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000395}
396#endif
397
robertphillips@google.comcce41022013-07-15 15:47:10 +0000398}