blob: 43f28cb61d0833c6cefd989400a253e45001d5f4 [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
bsalomon76228632015-05-29 08:02:10 -070013#include "GrCaps.h"
Brian Salomonaee504b2017-01-24 12:29:36 -050014#include "GrContext.h"
15#include "GrFixedClip.h"
Brian Osman11052242016-10-27 14:47:55 -040016#include "GrRenderTargetContext.h"
Robert Phillips784b7bf2016-12-09 13:35:02 -050017#include "GrRenderTargetContextPriv.h"
Brian Salomonaee504b2017-01-24 12:29:36 -050018#include "effects/GrGaussianConvolutionFragmentProcessor.h"
19#include "effects/GrMatrixConvolutionEffect.h"
robertphillips@google.com736dd032013-07-15 15:06:54 +000020
21#define MAX_BLUR_SIGMA 4.0f
22
robertphillipsf054b172016-05-13 05:06:19 -070023static void scale_irect_roundout(SkIRect* rect, float xScale, float yScale) {
Mike Reeda99b6ce2017-02-04 11:04:26 -050024 rect->fLeft = SkScalarFloorToInt(rect->fLeft * xScale);
25 rect->fTop = SkScalarFloorToInt(rect->fTop * yScale);
26 rect->fRight = SkScalarCeilToInt(rect->fRight * xScale);
27 rect->fBottom = SkScalarCeilToInt(rect->fBottom * yScale);
robertphillipsf054b172016-05-13 05:06:19 -070028}
29
30static void scale_irect(SkIRect* rect, int xScale, int yScale) {
31 rect->fLeft *= xScale;
32 rect->fTop *= yScale;
33 rect->fRight *= xScale;
34 rect->fBottom *= yScale;
35}
36
37#ifdef SK_DEBUG
38static inline int is_even(int x) { return !(x & 1); }
39#endif
40
41static void shrink_irect_by_2(SkIRect* rect, bool xAxis, bool yAxis) {
42 if (xAxis) {
43 SkASSERT(is_even(rect->fLeft) && is_even(rect->fRight));
44 rect->fLeft /= 2;
45 rect->fRight /= 2;
46 }
47 if (yAxis) {
48 SkASSERT(is_even(rect->fTop) && is_even(rect->fBottom));
49 rect->fTop /= 2;
50 rect->fBottom /= 2;
51 }
robertphillips@google.com736dd032013-07-15 15:06:54 +000052}
53
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +000054static float adjust_sigma(float sigma, int maxTextureSize, int *scaleFactor, int *radius) {
robertphillips@google.com736dd032013-07-15 15:06:54 +000055 *scaleFactor = 1;
56 while (sigma > MAX_BLUR_SIGMA) {
57 *scaleFactor *= 2;
58 sigma *= 0.5f;
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +000059 if (*scaleFactor > maxTextureSize) {
60 *scaleFactor = maxTextureSize;
61 sigma = MAX_BLUR_SIGMA;
62 }
robertphillips@google.com736dd032013-07-15 15:06:54 +000063 }
64 *radius = static_cast<int>(ceilf(sigma * 3.0f));
Brian Salomonaee504b2017-01-24 12:29:36 -050065 SkASSERT(*radius <= GrGaussianConvolutionFragmentProcessor::kMaxKernelRadius);
robertphillips@google.com736dd032013-07-15 15:06:54 +000066 return sigma;
67}
68
Robert Phillips08c5ec72017-01-30 12:26:47 -050069static void convolve_gaussian_1d(GrContext* context,
70 GrRenderTargetContext* renderTargetContext,
joshualitt570d2f82015-02-25 13:19:48 -080071 const GrClip& clip,
robertphillipsf054b172016-05-13 05:06:19 -070072 const SkIRect& dstRect,
73 const SkIPoint& srcOffset,
Robert Phillips08c5ec72017-01-30 12:26:47 -050074 sk_sp<GrTextureProxy> proxy,
joshualitt5acfea72014-08-11 13:55:34 -070075 Gr1DKernelEffect::Direction direction,
76 int radius,
77 float sigma,
78 bool useBounds,
Robert Phillips08c5ec72017-01-30 12:26:47 -050079 int bounds[2]) {
robertphillips@google.com736dd032013-07-15 15:06:54 +000080 GrPaint paint;
Brian Osman11052242016-10-27 14:47:55 -040081 paint.setGammaCorrect(renderTargetContext->isGammaCorrect());
Brian Salomonaee504b2017-01-24 12:29:36 -050082 sk_sp<GrFragmentProcessor> conv(GrGaussianConvolutionFragmentProcessor::Make(
Robert Phillips08c5ec72017-01-30 12:26:47 -050083 context, std::move(proxy), direction, radius, sigma, useBounds, bounds));
bungeman06ca8ec2016-06-09 08:01:03 -070084 paint.addColorFragmentProcessor(std::move(conv));
reed374772b2016-10-05 17:33:02 -070085 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
robertphillipsf054b172016-05-13 05:06:19 -070086 SkMatrix localMatrix = SkMatrix::MakeTrans(-SkIntToScalar(srcOffset.x()),
87 -SkIntToScalar(srcOffset.y()));
Brian Salomon82f44312017-01-11 13:42:54 -050088 renderTargetContext->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(),
Brian Osman11052242016-10-27 14:47:55 -040089 SkRect::Make(dstRect), localMatrix);
robertphillips@google.com736dd032013-07-15 15:06:54 +000090}
91
Robert Phillips08c5ec72017-01-30 12:26:47 -050092static void convolve_gaussian_2d(GrContext* context,
93 GrRenderTargetContext* renderTargetContext,
joshualitt570d2f82015-02-25 13:19:48 -080094 const GrClip& clip,
robertphillipsf054b172016-05-13 05:06:19 -070095 const SkIRect& dstRect,
96 const SkIPoint& srcOffset,
Robert Phillips08c5ec72017-01-30 12:26:47 -050097 sk_sp<GrTextureProxy> proxy,
joshualitt5acfea72014-08-11 13:55:34 -070098 int radiusX,
99 int radiusY,
100 SkScalar sigmaX,
101 SkScalar sigmaY,
robertphillipsf054b172016-05-13 05:06:19 -0700102 const SkIRect* srcBounds) {
103 SkMatrix localMatrix = SkMatrix::MakeTrans(-SkIntToScalar(srcOffset.x()),
104 -SkIntToScalar(srcOffset.y()));
joshualitt5acfea72014-08-11 13:55:34 -0700105 SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1);
106 SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY);
107 GrPaint paint;
Brian Osman11052242016-10-27 14:47:55 -0400108 paint.setGammaCorrect(renderTargetContext->isGammaCorrect());
robertphillipsf054b172016-05-13 05:06:19 -0700109 SkIRect bounds = srcBounds ? *srcBounds : SkIRect::EmptyIRect();
senorblanco07d56b12015-11-10 07:32:37 -0800110
bungeman06ca8ec2016-06-09 08:01:03 -0700111 sk_sp<GrFragmentProcessor> conv(GrMatrixConvolutionEffect::MakeGaussian(
Robert Phillips08c5ec72017-01-30 12:26:47 -0500112 context, std::move(proxy), bounds, size, 1.0, 0.0, kernelOffset,
senorblanco07d56b12015-11-10 07:32:37 -0800113 srcBounds ? GrTextureDomain::kDecal_Mode : GrTextureDomain::kIgnore_Mode,
joshualitt5acfea72014-08-11 13:55:34 -0700114 true, sigmaX, sigmaY));
bungeman06ca8ec2016-06-09 08:01:03 -0700115 paint.addColorFragmentProcessor(std::move(conv));
reed374772b2016-10-05 17:33:02 -0700116 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Brian Salomon82f44312017-01-11 13:42:54 -0500117 renderTargetContext->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(),
Brian Osman11052242016-10-27 14:47:55 -0400118 SkRect::Make(dstRect), localMatrix);
joshualitt5acfea72014-08-11 13:55:34 -0700119}
120
Robert Phillips08c5ec72017-01-30 12:26:47 -0500121static void convolve_gaussian(GrContext* context,
122 GrRenderTargetContext* renderTargetContext,
joshualitt570d2f82015-02-25 13:19:48 -0800123 const GrClip& clip,
robertphillipsf054b172016-05-13 05:06:19 -0700124 const SkIRect& srcRect,
Robert Phillips08c5ec72017-01-30 12:26:47 -0500125 sk_sp<GrTextureProxy> proxy,
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000126 Gr1DKernelEffect::Direction direction,
127 int radius,
128 float sigma,
robertphillipsf054b172016-05-13 05:06:19 -0700129 const SkIRect* srcBounds,
130 const SkIPoint& srcOffset) {
Robert Phillips08c5ec72017-01-30 12:26:47 -0500131 int bounds[2] = { 0, 0 };
robertphillipsf054b172016-05-13 05:06:19 -0700132 SkIRect dstRect = SkIRect::MakeWH(srcRect.width(), srcRect.height());
senorblanco07d56b12015-11-10 07:32:37 -0800133 if (!srcBounds) {
Robert Phillips08c5ec72017-01-30 12:26:47 -0500134 convolve_gaussian_1d(context, renderTargetContext, clip, dstRect, srcOffset,
135 std::move(proxy), direction, radius, sigma, false, bounds);
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000136 return;
137 }
robertphillipsf054b172016-05-13 05:06:19 -0700138 SkIRect midRect = *srcBounds, leftRect, rightRect;
senorblanco07d56b12015-11-10 07:32:37 -0800139 midRect.offset(srcOffset);
140 SkIRect topRect, bottomRect;
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000141 if (direction == Gr1DKernelEffect::kX_Direction) {
Robert Phillips08c5ec72017-01-30 12:26:47 -0500142 bounds[0] = srcBounds->left();
143 bounds[1] = srcBounds->right();
robertphillipsf054b172016-05-13 05:06:19 -0700144 topRect = SkIRect::MakeLTRB(0, 0, dstRect.right(), midRect.top());
145 bottomRect = SkIRect::MakeLTRB(0, midRect.bottom(), dstRect.right(), dstRect.bottom());
146 midRect.inset(radius, 0);
147 leftRect = SkIRect::MakeLTRB(0, midRect.top(), midRect.left(), midRect.bottom());
senorblanco07d56b12015-11-10 07:32:37 -0800148 rightRect =
robertphillipsf054b172016-05-13 05:06:19 -0700149 SkIRect::MakeLTRB(midRect.right(), midRect.top(), dstRect.width(), midRect.bottom());
senorblanco07d56b12015-11-10 07:32:37 -0800150 dstRect.fTop = midRect.top();
151 dstRect.fBottom = midRect.bottom();
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000152 } else {
Robert Phillips08c5ec72017-01-30 12:26:47 -0500153 bounds[0] = srcBounds->top();
154 bounds[1] = srcBounds->bottom();
robertphillipsf054b172016-05-13 05:06:19 -0700155 topRect = SkIRect::MakeLTRB(0, 0, midRect.left(), dstRect.bottom());
156 bottomRect = SkIRect::MakeLTRB(midRect.right(), 0, dstRect.right(), dstRect.bottom());
157 midRect.inset(0, radius);
158 leftRect = SkIRect::MakeLTRB(midRect.left(), 0, midRect.right(), midRect.top());
senorblanco07d56b12015-11-10 07:32:37 -0800159 rightRect =
robertphillipsf054b172016-05-13 05:06:19 -0700160 SkIRect::MakeLTRB(midRect.left(), midRect.bottom(), midRect.right(), dstRect.height());
senorblanco07d56b12015-11-10 07:32:37 -0800161 dstRect.fLeft = midRect.left();
162 dstRect.fRight = midRect.right();
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000163 }
senorblanco07d56b12015-11-10 07:32:37 -0800164 if (!topRect.isEmpty()) {
Brian Osman11052242016-10-27 14:47:55 -0400165 renderTargetContext->clear(&topRect, 0, false);
senorblanco07d56b12015-11-10 07:32:37 -0800166 }
167
168 if (!bottomRect.isEmpty()) {
Brian Osman11052242016-10-27 14:47:55 -0400169 renderTargetContext->clear(&bottomRect, 0, false);
senorblanco07d56b12015-11-10 07:32:37 -0800170 }
171 if (midRect.isEmpty()) {
172 // Blur radius covers srcBounds; use bounds over entire draw
Robert Phillips08c5ec72017-01-30 12:26:47 -0500173 convolve_gaussian_1d(context, renderTargetContext, clip, dstRect, srcOffset,
174 std::move(proxy), direction, radius, sigma, true, bounds);
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000175 } else {
senorblanco07d56b12015-11-10 07:32:37 -0800176 // Draw right and left margins with bounds; middle without.
Robert Phillips08c5ec72017-01-30 12:26:47 -0500177 convolve_gaussian_1d(context, renderTargetContext, clip, leftRect, srcOffset,
178 proxy, direction, radius, sigma, true, bounds);
179 convolve_gaussian_1d(context, renderTargetContext, clip, rightRect, srcOffset,
180 proxy, direction, radius, sigma, true, bounds);
181 convolve_gaussian_1d(context, renderTargetContext, clip, midRect, srcOffset,
182 std::move(proxy), direction, radius, sigma, false, bounds);
senorblanco@chromium.orgd71732a2013-07-30 21:11:05 +0000183 }
184}
185
robertphillipsf054b172016-05-13 05:06:19 -0700186namespace SkGpuBlurUtils {
187
Brian Osman11052242016-10-27 14:47:55 -0400188sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context,
Robert Phillips08c5ec72017-01-30 12:26:47 -0500189 sk_sp<GrTextureProxy> srcProxy,
Brian Osman11052242016-10-27 14:47:55 -0400190 sk_sp<SkColorSpace> colorSpace,
191 const SkIRect& dstBounds,
192 const SkIRect* srcBounds,
193 float sigmaX,
194 float sigmaY,
195 SkBackingFit fit) {
bsalomon49f085d2014-09-05 13:34:00 -0700196 SkASSERT(context);
Robert Phillips41511602017-02-02 10:06:18 -0500197
198 {
199 // Chrome is crashing with proxies when they need to be instantiated.
200 // Force an instantiation here (where, in olden days, we used to require a GrTexture)
201 // to see if the input is already un-instantiable.
Brian Osman32342f02017-03-04 08:12:46 -0500202 GrTexture* temp = srcProxy->instantiate(context->resourceProvider());
Robert Phillips41511602017-02-02 10:06:18 -0500203 if (!temp) {
204 return nullptr;
205 }
206 }
207
robertphillips@google.com736dd032013-07-15 15:06:54 +0000208 SkIRect clearRect;
209 int scaleFactorX, radiusX;
210 int scaleFactorY, radiusY;
bsalomon76228632015-05-29 08:02:10 -0700211 int maxTextureSize = context->caps()->maxTextureSize();
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +0000212 sigmaX = adjust_sigma(sigmaX, maxTextureSize, &scaleFactorX, &radiusX);
213 sigmaY = adjust_sigma(sigmaY, maxTextureSize, &scaleFactorY, &radiusY);
robertphillipsf054b172016-05-13 05:06:19 -0700214 SkASSERT(sigmaX || sigmaY);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000215
robertphillipsf054b172016-05-13 05:06:19 -0700216 SkIPoint srcOffset = SkIPoint::Make(-dstBounds.x(), -dstBounds.y());
217 SkIRect localDstBounds = SkIRect::MakeWH(dstBounds.width(), dstBounds.height());
218 SkIRect localSrcBounds;
219 SkIRect srcRect;
senorblanco07d56b12015-11-10 07:32:37 -0800220 if (srcBounds) {
221 srcRect = localSrcBounds = *srcBounds;
222 srcRect.offset(srcOffset);
223 srcBounds = &localSrcBounds;
224 } else {
225 srcRect = localDstBounds;
226 }
227
robertphillipsf054b172016-05-13 05:06:19 -0700228 scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
229 scale_irect(&srcRect, scaleFactorX, scaleFactorY);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000230
joshualitt570d2f82015-02-25 13:19:48 -0800231 // setup new clip
cdalton846c0512016-05-13 10:25:00 -0700232 GrFixedClip clip(localDstBounds);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000233
Robert Phillips08c5ec72017-01-30 12:26:47 -0500234 const GrPixelConfig config = srcProxy->config();
robertphillips04c84af2016-05-12 11:13:00 -0700235
Robert Phillips08c5ec72017-01-30 12:26:47 -0500236 SkASSERT(kBGRA_8888_GrPixelConfig == config || kRGBA_8888_GrPixelConfig == config ||
237 kSRGBA_8888_GrPixelConfig == config || kSBGRA_8888_GrPixelConfig == config ||
238 kRGBA_half_GrPixelConfig == config || kAlpha_8_GrPixelConfig == config);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000239
robertphillipsf054b172016-05-13 05:06:19 -0700240 const int width = dstBounds.width();
241 const int height = dstBounds.height();
robertphillipsa8966a82016-05-09 06:45:37 -0700242
robertphillipsd728f0c2016-11-21 11:05:03 -0800243 sk_sp<GrRenderTargetContext> dstRenderTargetContext(context->makeDeferredRenderTargetContext(
Robert Phillips40fd7c92017-01-30 08:06:27 -0500244 fit, width, height, config, colorSpace, 0, kBottomLeft_GrSurfaceOrigin));
Brian Osman11052242016-10-27 14:47:55 -0400245 if (!dstRenderTargetContext) {
robertphillips04c84af2016-05-12 11:13:00 -0700246 return nullptr;
247 }
248
robertphillipsa8966a82016-05-09 06:45:37 -0700249 // For really small blurs (certainly no wider than 5x5 on desktop gpus) it is faster to just
250 // launch a single non separable kernel vs two launches
251 if (sigmaX > 0.0f && sigmaY > 0.0f &&
252 (2 * radiusX + 1) * (2 * radiusY + 1) <= MAX_KERNEL_SIZE) {
253 // We shouldn't be scaling because this is a small size blur
254 SkASSERT((1 == scaleFactorX) && (1 == scaleFactorY));
255
Robert Phillips08c5ec72017-01-30 12:26:47 -0500256 convolve_gaussian_2d(context, dstRenderTargetContext.get(), clip, localDstBounds, srcOffset,
257 std::move(srcProxy), radiusX, radiusY, sigmaX, sigmaY, srcBounds);
robertphillipsa8966a82016-05-09 06:45:37 -0700258
Brian Osman11052242016-10-27 14:47:55 -0400259 return dstRenderTargetContext;
robertphillipsa8966a82016-05-09 06:45:37 -0700260 }
261
robertphillipsd728f0c2016-11-21 11:05:03 -0800262 sk_sp<GrRenderTargetContext> tmpRenderTargetContext(context->makeDeferredRenderTargetContext(
Robert Phillips40fd7c92017-01-30 08:06:27 -0500263 fit, width, height, config, colorSpace, 0, kBottomLeft_GrSurfaceOrigin));
Brian Osman11052242016-10-27 14:47:55 -0400264 if (!tmpRenderTargetContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700265 return nullptr;
robertphillips@google.com736dd032013-07-15 15:06:54 +0000266 }
267
Brian Osman11052242016-10-27 14:47:55 -0400268 sk_sp<GrRenderTargetContext> srcRenderTargetContext;
robertphillipsea461502015-05-26 11:38:03 -0700269
robertphillipsf054b172016-05-13 05:06:19 -0700270 SkASSERT(SkIsPow2(scaleFactorX) && SkIsPow2(scaleFactorY));
271
robertphillips@google.com736dd032013-07-15 15:06:54 +0000272 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
273 GrPaint paint;
Brian Osman11052242016-10-27 14:47:55 -0400274 paint.setGammaCorrect(dstRenderTargetContext->isGammaCorrect());
robertphillipsf054b172016-05-13 05:06:19 -0700275 SkIRect dstRect(srcRect);
senorblanco07d56b12015-11-10 07:32:37 -0800276 if (srcBounds && i == 1) {
Robert Phillipse98234f2017-01-09 14:23:59 -0500277 SkRect domain = SkRect::Make(*srcBounds);
278 domain.inset((i < scaleFactorX) ? SK_ScalarHalf : 0.0f,
279 (i < scaleFactorY) ? SK_ScalarHalf : 0.0f);
bungeman06ca8ec2016-06-09 08:01:03 -0700280 sk_sp<GrFragmentProcessor> fp(GrTextureDomainEffect::Make(
Robert Phillips08c5ec72017-01-30 12:26:47 -0500281 context,
282 std::move(srcProxy),
brianosman54f30c12016-07-18 10:53:52 -0700283 nullptr,
Robert Phillips67c18d62017-01-20 12:44:06 -0500284 SkMatrix::I(),
robertphillipsa8966a82016-05-09 06:45:37 -0700285 domain,
286 GrTextureDomain::kDecal_Mode,
Brian Salomon514baff2016-11-17 15:17:07 -0500287 GrSamplerParams::kBilerp_FilterMode));
bungeman06ca8ec2016-06-09 08:01:03 -0700288 paint.addColorFragmentProcessor(std::move(fp));
senorblanco07d56b12015-11-10 07:32:37 -0800289 srcRect.offset(-srcOffset);
290 srcOffset.set(0, 0);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000291 } else {
Brian Salomon514baff2016-11-17 15:17:07 -0500292 GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode);
Robert Phillips08c5ec72017-01-30 12:26:47 -0500293 paint.addColorTextureProcessor(context, std::move(srcProxy), nullptr,
294 SkMatrix::I(), params);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000295 }
reed374772b2016-10-05 17:33:02 -0700296 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
robertphillipsf054b172016-05-13 05:06:19 -0700297 shrink_irect_by_2(&dstRect, i < scaleFactorX, i < scaleFactorY);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700298
Brian Salomon82f44312017-01-11 13:42:54 -0500299 dstRenderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(),
Brian Osman11052242016-10-27 14:47:55 -0400300 SkRect::Make(dstRect), SkRect::Make(srcRect));
robertphillipsff0ca5e2015-07-22 11:54:44 -0700301
Brian Osman11052242016-10-27 14:47:55 -0400302 srcRenderTargetContext = dstRenderTargetContext;
robertphillips@google.com736dd032013-07-15 15:06:54 +0000303 srcRect = dstRect;
Robert Phillipsf200a902017-01-30 13:27:37 -0500304 srcProxy = srcRenderTargetContext->asTextureProxyRef();
Robert Phillips08c5ec72017-01-30 12:26:47 -0500305 if (!srcProxy) {
robertphillipsd728f0c2016-11-21 11:05:03 -0800306 return nullptr;
307 }
Brian Osman11052242016-10-27 14:47:55 -0400308 dstRenderTargetContext.swap(tmpRenderTargetContext);
senorblanco07d56b12015-11-10 07:32:37 -0800309 localSrcBounds = srcRect;
robertphillips@google.com736dd032013-07-15 15:06:54 +0000310 }
311
senorblancoc834ab12015-12-17 08:10:17 -0800312 srcRect = localDstBounds;
robertphillipsf054b172016-05-13 05:06:19 -0700313 scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
robertphillipsa8966a82016-05-09 06:45:37 -0700314 if (sigmaX > 0.0f) {
315 if (scaleFactorX > 1) {
Brian Osman11052242016-10-27 14:47:55 -0400316 SkASSERT(srcRenderTargetContext);
robertphillipsa8966a82016-05-09 06:45:37 -0700317
318 // Clear out a radius to the right of the srcRect to prevent the
319 // X convolution from reading garbage.
robertphillipsf054b172016-05-13 05:06:19 -0700320 clearRect = SkIRect::MakeXYWH(srcRect.fRight, srcRect.fTop,
321 radiusX, srcRect.height());
Robert Phillips784b7bf2016-12-09 13:35:02 -0500322 srcRenderTargetContext->priv().absClear(&clearRect, 0x0);
robertphillipsa8966a82016-05-09 06:45:37 -0700323 }
robertphillipsff0ca5e2015-07-22 11:54:44 -0700324
Robert Phillips08c5ec72017-01-30 12:26:47 -0500325 convolve_gaussian(context, dstRenderTargetContext.get(), clip, srcRect,
326 std::move(srcProxy), Gr1DKernelEffect::kX_Direction, radiusX, sigmaX,
robertphillipsa8966a82016-05-09 06:45:37 -0700327 srcBounds, srcOffset);
Brian Osman11052242016-10-27 14:47:55 -0400328 srcRenderTargetContext = dstRenderTargetContext;
Robert Phillipsf200a902017-01-30 13:27:37 -0500329 srcProxy = srcRenderTargetContext->asTextureProxyRef();
Robert Phillips08c5ec72017-01-30 12:26:47 -0500330 if (!srcProxy) {
robertphillipsd728f0c2016-11-21 11:05:03 -0800331 return nullptr;
332 }
robertphillipsa8966a82016-05-09 06:45:37 -0700333 srcRect.offsetTo(0, 0);
Brian Osman11052242016-10-27 14:47:55 -0400334 dstRenderTargetContext.swap(tmpRenderTargetContext);
robertphillipsa8966a82016-05-09 06:45:37 -0700335 localSrcBounds = srcRect;
336 srcOffset.set(0, 0);
337 }
338
339 if (sigmaY > 0.0f) {
340 if (scaleFactorY > 1 || sigmaX > 0.0f) {
Brian Osman11052242016-10-27 14:47:55 -0400341 SkASSERT(srcRenderTargetContext);
robertphillipsa8966a82016-05-09 06:45:37 -0700342
343 // Clear out a radius below the srcRect to prevent the Y
344 // convolution from reading garbage.
robertphillipsf054b172016-05-13 05:06:19 -0700345 clearRect = SkIRect::MakeXYWH(srcRect.fLeft, srcRect.fBottom,
346 srcRect.width(), radiusY);
Robert Phillips784b7bf2016-12-09 13:35:02 -0500347 srcRenderTargetContext->priv().absClear(&clearRect, 0x0);
robertphillipsa8966a82016-05-09 06:45:37 -0700348 }
349
Robert Phillips08c5ec72017-01-30 12:26:47 -0500350 convolve_gaussian(context, dstRenderTargetContext.get(), clip, srcRect,
351 std::move(srcProxy), Gr1DKernelEffect::kY_Direction, radiusY, sigmaY,
robertphillipsa8966a82016-05-09 06:45:37 -0700352 srcBounds, srcOffset);
robertphillips56a85e62016-05-06 07:17:49 -0700353
Brian Osman11052242016-10-27 14:47:55 -0400354 srcRenderTargetContext = dstRenderTargetContext;
robertphillipsa8966a82016-05-09 06:45:37 -0700355 srcRect.offsetTo(0, 0);
Brian Osman11052242016-10-27 14:47:55 -0400356 dstRenderTargetContext.swap(tmpRenderTargetContext);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000357 }
robertphillipsa8966a82016-05-09 06:45:37 -0700358
Brian Osman11052242016-10-27 14:47:55 -0400359 SkASSERT(srcRenderTargetContext);
Robert Phillips08c5ec72017-01-30 12:26:47 -0500360 srcProxy.reset(nullptr); // we don't use this from here on out
robertphillips@google.com736dd032013-07-15 15:06:54 +0000361
362 if (scaleFactorX > 1 || scaleFactorY > 1) {
robertphillips04c84af2016-05-12 11:13:00 -0700363 // Clear one pixel to the right and below, to accommodate bilinear upsampling.
Robert Phillips784b7bf2016-12-09 13:35:02 -0500364 // TODO: it seems like we should actually be clamping here rather than darkening
365 // the bottom right edges.
robertphillipsf054b172016-05-13 05:06:19 -0700366 clearRect = SkIRect::MakeXYWH(srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
Robert Phillips784b7bf2016-12-09 13:35:02 -0500367 srcRenderTargetContext->priv().absClear(&clearRect, 0x0);
robertphillipsf054b172016-05-13 05:06:19 -0700368 clearRect = SkIRect::MakeXYWH(srcRect.fRight, srcRect.fTop, 1, srcRect.height());
Robert Phillips784b7bf2016-12-09 13:35:02 -0500369 srcRenderTargetContext->priv().absClear(&clearRect, 0x0);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700370
robertphillips@google.com736dd032013-07-15 15:06:54 +0000371 GrPaint paint;
Brian Osman11052242016-10-27 14:47:55 -0400372 paint.setGammaCorrect(dstRenderTargetContext->isGammaCorrect());
robertphillips@google.com736dd032013-07-15 15:06:54 +0000373 // FIXME: this should be mitchell, not bilinear.
Brian Salomon514baff2016-11-17 15:17:07 -0500374 GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode);
Robert Phillips32f28182017-02-28 16:20:03 -0500375 sk_sp<GrTextureProxy> proxy(srcRenderTargetContext->asTextureProxyRef());
376 if (!proxy) {
robertphillipsd728f0c2016-11-21 11:05:03 -0800377 return nullptr;
378 }
379
Robert Phillips32f28182017-02-28 16:20:03 -0500380 paint.addColorTextureProcessor(context, std::move(proxy), nullptr, SkMatrix::I(), params);
reed374772b2016-10-05 17:33:02 -0700381 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000382
robertphillipsf054b172016-05-13 05:06:19 -0700383 SkIRect dstRect(srcRect);
384 scale_irect(&dstRect, scaleFactorX, scaleFactorY);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700385
Brian Salomon82f44312017-01-11 13:42:54 -0500386 dstRenderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(),
Brian Osman11052242016-10-27 14:47:55 -0400387 SkRect::Make(dstRect), SkRect::Make(srcRect));
robertphillipsff0ca5e2015-07-22 11:54:44 -0700388
Brian Osman11052242016-10-27 14:47:55 -0400389 srcRenderTargetContext = dstRenderTargetContext;
robertphillips@google.com736dd032013-07-15 15:06:54 +0000390 srcRect = dstRect;
Brian Osman11052242016-10-27 14:47:55 -0400391 dstRenderTargetContext.swap(tmpRenderTargetContext);
robertphillips@google.com736dd032013-07-15 15:06:54 +0000392 }
robertphillipsff0ca5e2015-07-22 11:54:44 -0700393
Brian Osman11052242016-10-27 14:47:55 -0400394 return srcRenderTargetContext;
robertphillips@google.com736dd032013-07-15 15:06:54 +0000395}
robertphillips@google.com736dd032013-07-15 15:06:54 +0000396
robertphillips@google.comcce41022013-07-15 15:47:10 +0000397}
robertphillipsf054b172016-05-13 05:06:19 -0700398
399#endif
400