blob: 5b6632fa26a7cf75466521848225bfc79a204c22 [file] [log] [blame]
Ethan Nicholas297d6ef2017-12-20 12:00:11 -05001/*
Ethan Nicholas130fb3f2018-02-01 12:14:34 -05002 * Copyright 2018 Google Inc.
Ethan Nicholas297d6ef2017-12-20 12:00:11 -05003 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Ethan Nicholas130fb3f2018-02-01 12:14:34 -05008/**************************************************************************************************
9 *** This file was autogenerated from GrRRectBlurEffect.fp; do not modify.
10 **************************************************************************************************/
Ethan Nicholas297d6ef2017-12-20 12:00:11 -050011#include "GrRRectBlurEffect.h"
Ethan Nicholas297d6ef2017-12-20 12:00:11 -050012
Robert Phillipsaac57282020-09-30 10:23:38 -040013#include "include/gpu/GrDirectContext.h"
Robert Phillipsa1c4f1a2020-08-24 14:42:39 -040014#include "include/gpu/GrRecordingContext.h"
Robert Phillips1ee21cd2020-09-03 13:40:52 -040015#include "src/core/SkAutoMalloc.h"
Robert Phillipsa1c4f1a2020-08-24 14:42:39 -040016#include "src/core/SkGpuBlurUtils.h"
17#include "src/core/SkRRectPriv.h"
Robert Phillipsaac57282020-09-30 10:23:38 -040018#include "src/gpu/GrBitmapTextureMaker.h"
Robert Phillipsa1c4f1a2020-08-24 14:42:39 -040019#include "src/gpu/GrCaps.h"
Adlai Hollera0693042020-10-14 11:23:11 -040020#include "src/gpu/GrDirectContextPriv.h"
Robert Phillipsa1c4f1a2020-08-24 14:42:39 -040021#include "src/gpu/GrPaint.h"
22#include "src/gpu/GrProxyProvider.h"
23#include "src/gpu/GrRecordingContextPriv.h"
24#include "src/gpu/GrRenderTargetContext.h"
25#include "src/gpu/GrStyle.h"
Robert Phillipsd464feb2020-10-08 11:00:02 -040026#include "src/gpu/GrThreadSafeCache.h"
Robert Phillipsa1c4f1a2020-08-24 14:42:39 -040027#include "src/gpu/effects/GrTextureEffect.h"
28
Robert Phillipsaac57282020-09-30 10:23:38 -040029static constexpr auto kBlurredRRectMaskOrigin = kTopLeft_GrSurfaceOrigin;
Robert Phillips5bc0b652020-09-02 09:49:38 -040030
31static void make_blurred_rrect_key(GrUniqueKey* key,
32 const SkRRect& rrectToDraw,
33 float xformedSigma) {
Michael Ludwige2674642020-10-21 13:01:34 -040034 SkASSERT(!SkGpuBlurUtils::IsEffectivelyZeroSigma(xformedSigma));
Robert Phillipsa1c4f1a2020-08-24 14:42:39 -040035 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
Robert Phillips5bc0b652020-09-02 09:49:38 -040036
37 GrUniqueKey::Builder builder(key, kDomain, 9, "RoundRect Blur Mask");
Robert Phillipsa1c4f1a2020-08-24 14:42:39 -040038 builder[0] = SkScalarCeilToInt(xformedSigma - 1 / 6.0f);
39
40 int index = 1;
Robert Phillips5bc0b652020-09-02 09:49:38 -040041 // TODO: this is overkill for _simple_ circular rrects
Robert Phillipsa1c4f1a2020-08-24 14:42:39 -040042 for (auto c : {SkRRect::kUpperLeft_Corner, SkRRect::kUpperRight_Corner,
43 SkRRect::kLowerRight_Corner, SkRRect::kLowerLeft_Corner}) {
44 SkASSERT(SkScalarIsInt(rrectToDraw.radii(c).fX) && SkScalarIsInt(rrectToDraw.radii(c).fY));
45 builder[index++] = SkScalarCeilToInt(rrectToDraw.radii(c).fX);
46 builder[index++] = SkScalarCeilToInt(rrectToDraw.radii(c).fY);
47 }
48 builder.finish();
Robert Phillips5bc0b652020-09-02 09:49:38 -040049}
Robert Phillipsa1c4f1a2020-08-24 14:42:39 -040050
Robert Phillipsd464feb2020-10-08 11:00:02 -040051static bool fillin_view_on_gpu(GrDirectContext* dContext,
52 const GrSurfaceProxyView& lazyView,
53 sk_sp<GrThreadSafeCache::Trampoline> trampoline,
54 const SkRRect& rrectToDraw,
55 const SkISize& dimensions,
56 float xformedSigma) {
Michael Ludwige2674642020-10-21 13:01:34 -040057 SkASSERT(!SkGpuBlurUtils::IsEffectivelyZeroSigma(xformedSigma));
Robert Phillipsaac57282020-09-30 10:23:38 -040058 std::unique_ptr<GrRenderTargetContext> rtc = GrRenderTargetContext::MakeWithFallback(
59 dContext, GrColorType::kAlpha_8, nullptr, SkBackingFit::kExact, dimensions, 1,
Robert Phillips5bc0b652020-09-02 09:49:38 -040060 GrMipmapped::kNo, GrProtected::kNo, kBlurredRRectMaskOrigin);
Robert Phillipsa1c4f1a2020-08-24 14:42:39 -040061 if (!rtc) {
Robert Phillipsaac57282020-09-30 10:23:38 -040062 return false;
Robert Phillipsa1c4f1a2020-08-24 14:42:39 -040063 }
64
65 GrPaint paint;
66
67 rtc->clear(SK_PMColor4fTRANSPARENT);
68 rtc->drawRRect(nullptr, std::move(paint), GrAA::kYes, SkMatrix::I(), rrectToDraw,
69 GrStyle::SimpleFill());
70
71 GrSurfaceProxyView srcView = rtc->readSurfaceView();
72 if (!srcView) {
Robert Phillipsaac57282020-09-30 10:23:38 -040073 return false;
Robert Phillipsa1c4f1a2020-08-24 14:42:39 -040074 }
75 SkASSERT(srcView.asTextureProxy());
Robert Phillipsaac57282020-09-30 10:23:38 -040076 auto rtc2 = SkGpuBlurUtils::GaussianBlur(dContext,
Robert Phillipsa1c4f1a2020-08-24 14:42:39 -040077 std::move(srcView),
78 rtc->colorInfo().colorType(),
79 rtc->colorInfo().alphaType(),
80 nullptr,
81 SkIRect::MakeSize(dimensions),
82 SkIRect::MakeSize(dimensions),
83 xformedSigma,
84 xformedSigma,
85 SkTileMode::kClamp,
86 SkBackingFit::kExact);
Robert Phillipsaac57282020-09-30 10:23:38 -040087 if (!rtc2 || !rtc2->readSurfaceView()) {
88 return false;
Robert Phillipsa1c4f1a2020-08-24 14:42:39 -040089 }
90
Robert Phillipsaac57282020-09-30 10:23:38 -040091 auto view = rtc2->readSurfaceView();
92 SkASSERT(view.swizzle() == lazyView.swizzle());
93 SkASSERT(view.origin() == lazyView.origin());
94 trampoline->fProxy = view.asTextureProxyRef();
95
96 return true;
Robert Phillips5bc0b652020-09-02 09:49:38 -040097}
98
Robert Phillips1ee21cd2020-09-03 13:40:52 -040099// Evaluate the vertical blur at the specified 'y' value given the location of the top of the
100// rrect.
101static uint8_t eval_V(float top, int y, const uint8_t* integral, int integralSize, float sixSigma) {
102 if (top < 0) {
103 return 0; // an empty column
104 }
105
106 float fT = (top - y - 0.5f) * (integralSize / sixSigma);
107 if (fT < 0) {
108 return 255;
109 } else if (fT >= integralSize - 1) {
110 return 0;
111 }
112
113 int lower = (int)fT;
114 float frac = fT - lower;
115
116 SkASSERT(lower + 1 < integralSize);
117
118 return integral[lower] * (1.0f - frac) + integral[lower + 1] * frac;
119}
120
121// Apply a gaussian 'kernel' horizontally at the specified 'x', 'y' location.
122static uint8_t eval_H(int x,
123 int y,
124 const std::vector<float>& topVec,
125 const float* kernel,
126 int kernelSize,
127 const uint8_t* integral,
128 int integralSize,
129 float sixSigma) {
130 SkASSERT(0 <= x && x < (int)topVec.size());
131 SkASSERT(kernelSize % 2);
132
133 float accum = 0.0f;
134
135 int xSampleLoc = x - (kernelSize / 2);
136 for (int i = 0; i < kernelSize; ++i, ++xSampleLoc) {
137 if (xSampleLoc < 0 || xSampleLoc >= (int)topVec.size()) {
138 continue;
139 }
140
141 accum += kernel[i] * eval_V(topVec[xSampleLoc], y, integral, integralSize, sixSigma);
142 }
143
144 return accum + 0.5f;
145}
146
147// Create a cpu-side blurred-rrect mask that is close to the version the gpu would've produced.
148// The match needs to be close bc the cpu- and gpu-generated version must be interchangeable.
Robert Phillipsaac57282020-09-30 10:23:38 -0400149static GrSurfaceProxyView create_mask_on_cpu(GrRecordingContext* rContext,
Robert Phillips1ee21cd2020-09-03 13:40:52 -0400150 const SkRRect& rrectToDraw,
151 const SkISize& dimensions,
152 float xformedSigma) {
Michael Ludwige2674642020-10-21 13:01:34 -0400153 SkASSERT(!SkGpuBlurUtils::IsEffectivelyZeroSigma(xformedSigma));
154 int radius = SkGpuBlurUtils::SigmaRadius(xformedSigma);
Robert Phillips1ee21cd2020-09-03 13:40:52 -0400155 int kernelSize = 2 * radius + 1;
156
157 SkASSERT(kernelSize % 2);
158 SkASSERT(dimensions.width() % 2);
159 SkASSERT(dimensions.height() % 2);
160
161 SkVector radii = rrectToDraw.getSimpleRadii();
162 SkASSERT(SkScalarNearlyEqual(radii.fX, radii.fY));
163
164 const int halfWidthPlus1 = (dimensions.width() / 2) + 1;
165 const int halfHeightPlus1 = (dimensions.height() / 2) + 1;
166
167 std::unique_ptr<float[]> kernel(new float[kernelSize]);
168
Michael Ludwige2674642020-10-21 13:01:34 -0400169 SkGpuBlurUtils::Compute1DGaussianKernel(kernel.get(), xformedSigma, radius);
Robert Phillips1ee21cd2020-09-03 13:40:52 -0400170
171 SkBitmap integral;
Michael Ludwige2674642020-10-21 13:01:34 -0400172 if (!SkGpuBlurUtils::CreateIntegralTable(6 * xformedSigma, &integral)) {
Robert Phillips1ee21cd2020-09-03 13:40:52 -0400173 return {};
174 }
175
176 SkBitmap result;
177 if (!result.tryAllocPixels(SkImageInfo::MakeA8(dimensions.width(), dimensions.height()))) {
178 return {};
179 }
180
181 std::vector<float> topVec;
182 topVec.reserve(dimensions.width());
183 for (int x = 0; x < dimensions.width(); ++x) {
184 if (x < rrectToDraw.rect().fLeft || x > rrectToDraw.rect().fRight) {
185 topVec.push_back(-1);
186 } else {
187 if (x + 0.5f < rrectToDraw.rect().fLeft + radii.fX) { // in the circular section
188 float xDist = rrectToDraw.rect().fLeft + radii.fX - x - 0.5f;
189 float h = sqrtf(radii.fX * radii.fX - xDist * xDist);
190 SkASSERT(0 <= h && h < radii.fY);
191 topVec.push_back(rrectToDraw.rect().fTop + radii.fX - h + 3 * xformedSigma);
192 } else {
193 topVec.push_back(rrectToDraw.rect().fTop + 3 * xformedSigma);
194 }
195 }
196 }
197
198 for (int y = 0; y < halfHeightPlus1; ++y) {
199 uint8_t* scanline = result.getAddr8(0, y);
200
201 for (int x = 0; x < halfWidthPlus1; ++x) {
202 scanline[x] = eval_H(x, y, topVec, kernel.get(), kernelSize, integral.getAddr8(0, 0),
203 integral.width(), 6 * xformedSigma);
204 scanline[dimensions.width() - x - 1] = scanline[x];
205 }
206
207 memcpy(result.getAddr8(0, dimensions.height() - y - 1), scanline, result.rowBytes());
208 }
209
210 result.setImmutable();
211
Robert Phillipsaac57282020-09-30 10:23:38 -0400212 GrBitmapTextureMaker maker(rContext, result, GrImageTexGenPolicy::kNew_Uncached_Budgeted);
213 auto view = maker.view(GrMipmapped::kNo);
214 if (!view) {
Robert Phillips1ee21cd2020-09-03 13:40:52 -0400215 return {};
216 }
217
Robert Phillipsaac57282020-09-30 10:23:38 -0400218 SkASSERT(view.origin() == kBlurredRRectMaskOrigin);
219 return view;
220}
221
Robert Phillips5bc0b652020-09-02 09:49:38 -0400222static std::unique_ptr<GrFragmentProcessor> find_or_create_rrect_blur_mask_fp(
Robert Phillipsaac57282020-09-30 10:23:38 -0400223 GrRecordingContext* rContext,
Robert Phillips5bc0b652020-09-02 09:49:38 -0400224 const SkRRect& rrectToDraw,
225 const SkISize& dimensions,
226 float xformedSigma) {
Michael Ludwige2674642020-10-21 13:01:34 -0400227 SkASSERT(!SkGpuBlurUtils::IsEffectivelyZeroSigma(xformedSigma));
Robert Phillips5bc0b652020-09-02 09:49:38 -0400228 GrUniqueKey key;
Brian Osman55b69f52020-09-30 01:41:15 +0000229 make_blurred_rrect_key(&key, rrectToDraw, xformedSigma);
Robert Phillips4cf00a82020-09-29 15:43:10 -0400230
Robert Phillipsd464feb2020-10-08 11:00:02 -0400231 auto threadSafeCache = rContext->priv().threadSafeCache();
Robert Phillipsaac57282020-09-30 10:23:38 -0400232
Robert Phillips5bc0b652020-09-02 09:49:38 -0400233 // It seems like we could omit this matrix and modify the shader code to not normalize
234 // the coords used to sample the texture effect. However, the "proxyDims" value in the
235 // shader is not always the actual the proxy dimensions. This is because 'dimensions' here
236 // was computed using integer corner radii as determined in
237 // SkComputeBlurredRRectParams whereas the shader code uses the float radius to compute
238 // 'proxyDims'. Why it draws correctly with these unequal values is a mystery for the ages.
239 auto m = SkMatrix::Scale(dimensions.width(), dimensions.height());
Robert Phillips5bc0b652020-09-02 09:49:38 -0400240
Robert Phillipsaac57282020-09-30 10:23:38 -0400241 GrSurfaceProxyView view;
Robert Phillips5bc0b652020-09-02 09:49:38 -0400242
Robert Phillipsaac57282020-09-30 10:23:38 -0400243 if (GrDirectContext* dContext = rContext->asDirectContext()) {
244 // The gpu thread gets priority over the recording threads. If the gpu thread is first,
245 // it crams a lazy proxy into the cache and then fills it in later.
Robert Phillipsd464feb2020-10-08 11:00:02 -0400246 auto[lazyView, trampoline] =
247 GrThreadSafeCache::CreateLazyView(dContext, GrColorType::kAlpha_8, dimensions,
248 kBlurredRRectMaskOrigin, SkBackingFit::kExact);
Robert Phillipsaac57282020-09-30 10:23:38 -0400249 if (!lazyView) {
250 return nullptr;
251 }
252
Robert Phillipsd464feb2020-10-08 11:00:02 -0400253 view = threadSafeCache->findOrAdd(key, lazyView);
Robert Phillipsaac57282020-09-30 10:23:38 -0400254 if (view != lazyView) {
255 SkASSERT(view.asTextureProxy());
256 SkASSERT(view.origin() == kBlurredRRectMaskOrigin);
257 return GrTextureEffect::Make(std::move(view), kPremul_SkAlphaType, m);
258 }
259
260 if (!fillin_view_on_gpu(dContext, lazyView, std::move(trampoline), rrectToDraw, dimensions,
261 xformedSigma)) {
262 // In this case something has gone disastrously wrong so set up to drop the draw
263 // that needed this resource and reduce future pollution of the cache.
Robert Phillipsd464feb2020-10-08 11:00:02 -0400264 threadSafeCache->remove(key);
Robert Phillipsaac57282020-09-30 10:23:38 -0400265 return nullptr;
266 }
Brian Osman55b69f52020-09-30 01:41:15 +0000267 } else {
Robert Phillipsd464feb2020-10-08 11:00:02 -0400268 view = threadSafeCache->find(key);
Robert Phillipsaac57282020-09-30 10:23:38 -0400269 if (view) {
270 SkASSERT(view.asTextureProxy());
271 SkASSERT(view.origin() == kBlurredRRectMaskOrigin);
272 return GrTextureEffect::Make(std::move(view), kPremul_SkAlphaType, m);
273 }
274
275 view = create_mask_on_cpu(rContext, rrectToDraw, dimensions, xformedSigma);
276 if (!view) {
277 return nullptr;
278 }
279
Robert Phillipsd464feb2020-10-08 11:00:02 -0400280 view = threadSafeCache->add(key, view);
Brian Osman55b69f52020-09-30 01:41:15 +0000281 }
282
Robert Phillipsaac57282020-09-30 10:23:38 -0400283 SkASSERT(view.asTextureProxy());
284 SkASSERT(view.origin() == kBlurredRRectMaskOrigin);
285 return GrTextureEffect::Make(std::move(view), kPremul_SkAlphaType, m);
Robert Phillipsa1c4f1a2020-08-24 14:42:39 -0400286}
287
John Stiles4ca88842020-06-08 17:20:01 -0400288std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::Make(
289 std::unique_ptr<GrFragmentProcessor> inputFP,
290 GrRecordingContext* context,
291 float sigma,
292 float xformedSigma,
293 const SkRRect& srcRRect,
294 const SkRRect& devRRect) {
Brian Salomon8ff24492020-09-28 11:39:09 -0400295// Should've been caught up-stream
296#ifdef SK_DEBUG
297 SkASSERTF(!SkRRectPriv::IsCircle(devRRect), "Unexpected circle. %d\n\t%s\n\t%s",
298 SkRRectPriv::IsCircle(srcRRect), srcRRect.dumpToString(true).c_str(),
299 devRRect.dumpToString(true).c_str());
300 SkASSERTF(!devRRect.isRect(), "Unexpected rect. %d\n\t%s\n\t%s", srcRRect.isRect(),
301 srcRRect.dumpToString(true).c_str(), devRRect.dumpToString(true).c_str());
302#endif
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500303 // TODO: loosen this up
Mike Reed242135a2018-02-22 13:41:39 -0500304 if (!SkRRectPriv::IsSimpleCircular(devRRect)) {
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500305 return nullptr;
306 }
307
Michael Ludwige2674642020-10-21 13:01:34 -0400308 if (SkGpuBlurUtils::IsEffectivelyZeroSigma(xformedSigma)) {
309 return inputFP;
310 }
311
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500312 // Make sure we can successfully ninepatch this rrect -- the blur sigma has to be
313 // sufficiently small relative to both the size of the corner radius and the
314 // width (and height) of the rrect.
Mike Kleind6ab77a2019-03-21 08:18:24 -0500315 SkRRect rrectToDraw;
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400316 SkISize dimensions;
Michael Ludwige2674642020-10-21 13:01:34 -0400317 SkScalar ignored[SkGpuBlurUtils::kBlurRRectMaxDivisions];
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500318
Michael Ludwige2674642020-10-21 13:01:34 -0400319 bool ninePatchable = SkGpuBlurUtils::ComputeBlurredRRectParams(
320 srcRRect, devRRect, sigma, xformedSigma, &rrectToDraw, &dimensions, ignored, ignored,
321 ignored, ignored);
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500322 if (!ninePatchable) {
323 return nullptr;
324 }
325
Brian Salomon71f6cfd2020-06-17 17:14:12 -0400326 std::unique_ptr<GrFragmentProcessor> maskFP =
327 find_or_create_rrect_blur_mask_fp(context, rrectToDraw, dimensions, xformedSigma);
328 if (!maskFP) {
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500329 return nullptr;
330 }
331
Mike Reed242135a2018-02-22 13:41:39 -0500332 return std::unique_ptr<GrFragmentProcessor>(
John Stiles4ca88842020-06-08 17:20:01 -0400333 new GrRRectBlurEffect(std::move(inputFP), xformedSigma, devRRect.getBounds(),
Brian Salomon71f6cfd2020-06-17 17:14:12 -0400334 SkRRectPriv::GetSimpleRadii(devRRect).fX, std::move(maskFP)));
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500335}
John Stiles45f5b032020-07-27 17:31:29 -0400336#include "src/core/SkUtils.h"
Greg Daniel456f9b52020-03-05 19:14:18 +0000337#include "src/gpu/GrTexture.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500338#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
339#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
340#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
341#include "src/sksl/SkSLCPP.h"
342#include "src/sksl/SkSLUtil.h"
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500343class GrGLSLRRectBlurEffect : public GrGLSLFragmentProcessor {
344public:
345 GrGLSLRRectBlurEffect() {}
346 void emitCode(EmitArgs& args) override {
347 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
Mike Kleind6ab77a2019-03-21 08:18:24 -0500348 const GrRRectBlurEffect& _outer = args.fFp.cast<GrRRectBlurEffect>();
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500349 (void)_outer;
Ethan Nicholasbcd51e82019-04-09 10:40:41 -0400350 auto sigma = _outer.sigma;
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500351 (void)sigma;
Ethan Nicholasbcd51e82019-04-09 10:40:41 -0400352 auto rect = _outer.rect;
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500353 (void)rect;
Ethan Nicholasbcd51e82019-04-09 10:40:41 -0400354 auto cornerRadius = _outer.cornerRadius;
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500355 (void)cornerRadius;
Ethan Nicholas16464c32020-04-06 13:53:05 -0400356 cornerRadiusVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag,
357 kHalf_GrSLType, "cornerRadius");
358 proxyRectVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag,
359 kFloat4_GrSLType, "proxyRect");
360 blurRadiusVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag,
361 kHalf_GrSLType, "blurRadius");
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500362 fragBuilder->codeAppendf(
Brian Salomon5e961b02020-10-21 14:28:47 -0400363 R"SkSL(float2 translatedFragPosFloat = sk_FragCoord.xy - %s.xy;
364float2 proxyCenter = (%s.zw - %s.xy) * 0.5;
John Stiles50819422020-06-18 13:00:38 -0400365half edgeSize = (2.0 * %s + %s) + 0.5;
Brian Salomon5e961b02020-10-21 14:28:47 -0400366translatedFragPosFloat -= proxyCenter;
367half2 fragDirection = half2(sign(translatedFragPosFloat));
368translatedFragPosFloat = abs(translatedFragPosFloat);
369half2 translatedFragPosHalf = half2(translatedFragPosFloat - (proxyCenter - float(edgeSize)));
370translatedFragPosHalf = max(translatedFragPosHalf, 0.0);
371translatedFragPosHalf *= fragDirection;
372translatedFragPosHalf += half2(edgeSize);
John Stiles50819422020-06-18 13:00:38 -0400373half2 proxyDims = half2(2.0 * edgeSize);
Brian Salomon5e961b02020-10-21 14:28:47 -0400374half2 texCoord = translatedFragPosHalf / proxyDims;)SkSL",
Ethan Nicholasbcd51e82019-04-09 10:40:41 -0400375 args.fUniformHandler->getUniformCStr(proxyRectVar),
John Stilesa2d46a12020-06-11 14:12:44 -0400376 args.fUniformHandler->getUniformCStr(proxyRectVar),
377 args.fUniformHandler->getUniformCStr(proxyRectVar),
Ethan Nicholasbcd51e82019-04-09 10:40:41 -0400378 args.fUniformHandler->getUniformCStr(blurRadiusVar),
John Stilesa2d46a12020-06-11 14:12:44 -0400379 args.fUniformHandler->getUniformCStr(cornerRadiusVar));
Brian Salomon5e961b02020-10-21 14:28:47 -0400380 SkString _sample17574 = this->invokeChild(0, args);
John Stiles50819422020-06-18 13:00:38 -0400381 fragBuilder->codeAppendf(
382 R"SkSL(
383half4 inputColor = %s;)SkSL",
Brian Salomon5e961b02020-10-21 14:28:47 -0400384 _sample17574.c_str());
385 SkString _coords17622("float2(texCoord)");
386 SkString _sample17622 = this->invokeChild(1, args, _coords17622.c_str());
John Stiles50819422020-06-18 13:00:38 -0400387 fragBuilder->codeAppendf(
388 R"SkSL(
389%s = inputColor * %s;
390)SkSL",
Brian Salomon5e961b02020-10-21 14:28:47 -0400391 args.fOutputColor, _sample17622.c_str());
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500392 }
393
394private:
395 void onSetData(const GrGLSLProgramDataManager& pdman,
Mike Kleind6ab77a2019-03-21 08:18:24 -0500396 const GrFragmentProcessor& _proc) override {
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500397 const GrRRectBlurEffect& _outer = _proc.cast<GrRRectBlurEffect>();
Ethan Nicholasbcd51e82019-04-09 10:40:41 -0400398 { pdman.set1f(cornerRadiusVar, (_outer.cornerRadius)); }
399 auto sigma = _outer.sigma;
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500400 (void)sigma;
Ethan Nicholasbcd51e82019-04-09 10:40:41 -0400401 auto rect = _outer.rect;
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500402 (void)rect;
Ethan Nicholasbcd51e82019-04-09 10:40:41 -0400403 UniformHandle& cornerRadius = cornerRadiusVar;
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500404 (void)cornerRadius;
Ethan Nicholasbcd51e82019-04-09 10:40:41 -0400405 UniformHandle& proxyRect = proxyRectVar;
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500406 (void)proxyRect;
Ethan Nicholasbcd51e82019-04-09 10:40:41 -0400407 UniformHandle& blurRadius = blurRadiusVar;
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500408 (void)blurRadius;
409
410 float blurRadiusValue = 3.f * SkScalarCeilToScalar(sigma - 1 / 6.0f);
411 pdman.set1f(blurRadius, blurRadiusValue);
412
413 SkRect outset = rect;
414 outset.outset(blurRadiusValue, blurRadiusValue);
415 pdman.set4f(proxyRect, outset.fLeft, outset.fTop, outset.fRight, outset.fBottom);
416 }
Ethan Nicholasbcd51e82019-04-09 10:40:41 -0400417 UniformHandle proxyRectVar;
418 UniformHandle blurRadiusVar;
419 UniformHandle cornerRadiusVar;
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500420};
421GrGLSLFragmentProcessor* GrRRectBlurEffect::onCreateGLSLInstance() const {
422 return new GrGLSLRRectBlurEffect();
423}
Mike Kleind6ab77a2019-03-21 08:18:24 -0500424void GrRRectBlurEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500425 GrProcessorKeyBuilder* b) const {}
426bool GrRRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const {
427 const GrRRectBlurEffect& that = other.cast<GrRRectBlurEffect>();
428 (void)that;
Ethan Nicholasbcd51e82019-04-09 10:40:41 -0400429 if (sigma != that.sigma) return false;
430 if (rect != that.rect) return false;
431 if (cornerRadius != that.cornerRadius) return false;
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500432 return true;
433}
John Stiles735a5a72020-08-26 10:21:10 -0400434bool GrRRectBlurEffect::usesExplicitReturn() const { return false; }
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500435GrRRectBlurEffect::GrRRectBlurEffect(const GrRRectBlurEffect& src)
436 : INHERITED(kGrRRectBlurEffect_ClassID, src.optimizationFlags())
Ethan Nicholasbcd51e82019-04-09 10:40:41 -0400437 , sigma(src.sigma)
438 , rect(src.rect)
Brian Salomon71f6cfd2020-06-17 17:14:12 -0400439 , cornerRadius(src.cornerRadius) {
Brian Osman12c5d292020-07-13 16:11:35 -0400440 this->cloneAndRegisterAllChildProcessors(src);
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500441}
442std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::clone() const {
John Stilesfbd050b2020-08-03 13:21:46 -0400443 return std::make_unique<GrRRectBlurEffect>(*this);
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500444}
John Stiles8d9bf642020-08-12 15:07:45 -0400445#if GR_TEST_UTILS
John Stilescab58862020-08-12 15:47:06 -0400446SkString GrRRectBlurEffect::onDumpInfo() const {
447 return SkStringPrintf("(sigma=%f, rect=float4(%f, %f, %f, %f), cornerRadius=%f)", sigma,
448 rect.left(), rect.top(), rect.right(), rect.bottom(), cornerRadius);
John Stiles47b4e222020-08-12 09:56:50 -0400449}
450#endif
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500451GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRRectBlurEffect);
452#if GR_TEST_UTILS
453std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::TestCreate(GrProcessorTestData* d) {
Mike Kleind6ab77a2019-03-21 08:18:24 -0500454 SkScalar w = d->fRandom->nextRangeScalar(100.f, 1000.f);
455 SkScalar h = d->fRandom->nextRangeScalar(100.f, 1000.f);
456 SkScalar r = d->fRandom->nextRangeF(1.f, 9.f);
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500457 SkScalar sigma = d->fRandom->nextRangeF(1.f, 10.f);
Mike Kleind6ab77a2019-03-21 08:18:24 -0500458 SkRRect rrect;
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500459 rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
John Stiles6609cb62020-07-17 14:52:12 -0400460 return GrRRectBlurEffect::Make(d->inputFP(), d->context(), sigma, sigma, rrect, rrect);
Ethan Nicholas297d6ef2017-12-20 12:00:11 -0500461}
462#endif