blob: fbaf2f3172d108e1ff0d70c9b7310bfce64e84a7 [file] [log] [blame]
Jim Van Verthc5903412016-11-17 15:27:09 -05001/*
2 * Copyright 2016 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
Robert Phillipscadd5db2021-08-30 11:37:18 -04008#include "src/gpu/ops/ShadowRRectOp.h"
Robert Phillips7c525e62018-06-12 10:11:12 -04009
Robert Phillipsb7bfbc22020-07-01 12:55:01 -040010#include "include/gpu/GrRecordingContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "src/core/SkRRectPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "src/gpu/GrMemoryPool.h"
13#include "src/gpu/GrOpFlushState.h"
Robert Phillips6941f4a2020-03-12 09:41:54 -040014#include "src/gpu/GrProgramInfo.h"
Jim Van Verth7da048b2019-10-29 13:28:14 -040015#include "src/gpu/GrProxyProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/gpu/GrRecordingContextPriv.h"
Robert Phillipsd464feb2020-10-08 11:00:02 -040017#include "src/gpu/GrThreadSafeCache.h"
Brian Salomon27c42022021-04-28 12:39:21 -040018#include "src/gpu/SkGr.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/gpu/effects/GrShadowGeoProc.h"
Robert Phillips3968fcb2019-12-05 16:40:31 -050020#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
Jim Van Verthc5903412016-11-17 15:27:09 -050021
Robert Phillipscadd5db2021-08-30 11:37:18 -040022namespace {
23
Jim Van Verthc5903412016-11-17 15:27:09 -050024///////////////////////////////////////////////////////////////////////////////
Jim Van Verth57061ee2017-04-28 17:30:30 -040025// Circle Data
26//
Jim Van Verthc5903412016-11-17 15:27:09 -050027// We have two possible cases for geometry for a circle:
28
29// In the case of a normal fill, we draw geometry for the circle as an octagon.
30static const uint16_t gFillCircleIndices[] = {
Brian Salomonfc527d22016-12-14 21:07:01 -050031 // enter the octagon
32 // clang-format off
33 0, 1, 8, 1, 2, 8,
34 2, 3, 8, 3, 4, 8,
35 4, 5, 8, 5, 6, 8,
36 6, 7, 8, 7, 0, 8,
37 // clang-format on
Jim Van Verthc5903412016-11-17 15:27:09 -050038};
39
40// For stroked circles, we use two nested octagons.
41static const uint16_t gStrokeCircleIndices[] = {
Brian Salomonfc527d22016-12-14 21:07:01 -050042 // enter the octagon
43 // clang-format off
44 0, 1, 9, 0, 9, 8,
45 1, 2, 10, 1, 10, 9,
46 2, 3, 11, 2, 11, 10,
47 3, 4, 12, 3, 12, 11,
48 4, 5, 13, 4, 13, 12,
49 5, 6, 14, 5, 14, 13,
50 6, 7, 15, 6, 15, 14,
51 7, 0, 8, 7, 8, 15,
52 // clang-format on
Jim Van Verthc5903412016-11-17 15:27:09 -050053};
54
55static const int kIndicesPerFillCircle = SK_ARRAY_COUNT(gFillCircleIndices);
56static const int kIndicesPerStrokeCircle = SK_ARRAY_COUNT(gStrokeCircleIndices);
57static const int kVertsPerStrokeCircle = 16;
58static const int kVertsPerFillCircle = 9;
59
Robert Phillipscadd5db2021-08-30 11:37:18 -040060int circle_type_to_vert_count(bool stroked) {
Jim Van Verthc5903412016-11-17 15:27:09 -050061 return stroked ? kVertsPerStrokeCircle : kVertsPerFillCircle;
62}
63
Robert Phillipscadd5db2021-08-30 11:37:18 -040064int circle_type_to_index_count(bool stroked) {
Jim Van Verthc5903412016-11-17 15:27:09 -050065 return stroked ? kIndicesPerStrokeCircle : kIndicesPerFillCircle;
66}
67
Robert Phillipscadd5db2021-08-30 11:37:18 -040068const uint16_t* circle_type_to_indices(bool stroked) {
Jim Van Verthc5903412016-11-17 15:27:09 -050069 return stroked ? gStrokeCircleIndices : gFillCircleIndices;
70}
71
72///////////////////////////////////////////////////////////////////////////////
Jim Van Verth57061ee2017-04-28 17:30:30 -040073// RoundRect Data
74//
Jim Van Verthb6069df2017-04-28 11:00:35 -040075// The geometry for a shadow roundrect is similar to a 9-patch:
Jim Van Verthc5903412016-11-17 15:27:09 -050076// ____________
77// |_|________|_|
78// | | | |
79// | | | |
80// | | | |
81// |_|________|_|
82// |_|________|_|
83//
Jim Van Verthb6069df2017-04-28 11:00:35 -040084// However, each corner is rendered as a fan rather than a simple quad, as below. (The diagram
85// shows the upper part of the upper left corner. The bottom triangle would similarly be split
86// into two triangles.)
87// ________
88// |\ \ |
89// | \ \ |
90// | \\ |
91// | \|
92// --------
93//
94// The center of the fan handles the curve of the corner. For roundrects where the stroke width
95// is greater than the corner radius, the outer triangles blend from the curve to the straight
96// sides. Otherwise these triangles will be degenerate.
97//
98// In the case where the stroke width is greater than the corner radius and the
99// blur radius (overstroke), we add additional geometry to mark out the rectangle in the center.
100// This rectangle extends the coverage values of the center edges of the 9-patch.
Jim Van Verthc5903412016-11-17 15:27:09 -0500101// ____________
102// |_|________|_|
103// | |\ ____ /| |
104// | | | | | |
105// | | |____| | |
106// |_|/______\|_|
107// |_|________|_|
108//
Jim Van Verthb6069df2017-04-28 11:00:35 -0400109// For filled rrects we reuse the stroke geometry but add an additional quad to the center.
Jim Van Verthc5903412016-11-17 15:27:09 -0500110
Jim Van Verthb6069df2017-04-28 11:00:35 -0400111static const uint16_t gRRectIndices[] = {
112 // clang-format off
113 // overstroke quads
114 // we place this at the beginning so that we can skip these indices when rendering as filled
115 0, 6, 25, 0, 25, 24,
116 6, 18, 27, 6, 27, 25,
117 18, 12, 26, 18, 26, 27,
118 12, 0, 24, 12, 24, 26,
Jim Van Verthc5903412016-11-17 15:27:09 -0500119
Jim Van Verthb6069df2017-04-28 11:00:35 -0400120 // corners
121 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5,
122 6, 11, 10, 6, 10, 9, 6, 9, 8, 6, 8, 7,
123 12, 17, 16, 12, 16, 15, 12, 15, 14, 12, 14, 13,
124 18, 19, 20, 18, 20, 21, 18, 21, 22, 18, 22, 23,
Jim Van Verthc5903412016-11-17 15:27:09 -0500125
Jim Van Verthb6069df2017-04-28 11:00:35 -0400126 // edges
127 0, 5, 11, 0, 11, 6,
128 6, 7, 19, 6, 19, 18,
129 18, 23, 17, 18, 17, 12,
130 12, 13, 1, 12, 1, 0,
131
132 // fill quad
133 // we place this at the end so that we can skip these indices when rendering as stroked
134 0, 6, 18, 0, 18, 12,
135 // clang-format on
Jim Van Verthc5903412016-11-17 15:27:09 -0500136};
Jim Van Verthc5903412016-11-17 15:27:09 -0500137
138// overstroke count
Jim Van Verthb6069df2017-04-28 11:00:35 -0400139static const int kIndicesPerOverstrokeRRect = SK_ARRAY_COUNT(gRRectIndices) - 6;
Jim Van Verthc5903412016-11-17 15:27:09 -0500140// simple stroke count skips overstroke indices
Jim Van Verthb6069df2017-04-28 11:00:35 -0400141static const int kIndicesPerStrokeRRect = kIndicesPerOverstrokeRRect - 6*4;
142// fill count adds final quad to stroke count
143static const int kIndicesPerFillRRect = kIndicesPerStrokeRRect + 6;
144static const int kVertsPerStrokeRRect = 24;
145static const int kVertsPerOverstrokeRRect = 28;
146static const int kVertsPerFillRRect = 24;
Jim Van Verthc5903412016-11-17 15:27:09 -0500147
148enum RRectType {
149 kFill_RRectType,
150 kStroke_RRectType,
151 kOverstroke_RRectType,
152};
153
Robert Phillipscadd5db2021-08-30 11:37:18 -0400154int rrect_type_to_vert_count(RRectType type) {
Brian Salomonfc527d22016-12-14 21:07:01 -0500155 switch (type) {
156 case kFill_RRectType:
Jim Van Verthb6069df2017-04-28 11:00:35 -0400157 return kVertsPerFillRRect;
Brian Salomonfc527d22016-12-14 21:07:01 -0500158 case kStroke_RRectType:
159 return kVertsPerStrokeRRect;
160 case kOverstroke_RRectType:
161 return kVertsPerOverstrokeRRect;
162 }
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400163 SK_ABORT("Invalid type");
Jim Van Verthc5903412016-11-17 15:27:09 -0500164}
165
Robert Phillipscadd5db2021-08-30 11:37:18 -0400166int rrect_type_to_index_count(RRectType type) {
Brian Salomonfc527d22016-12-14 21:07:01 -0500167 switch (type) {
168 case kFill_RRectType:
Jim Van Verthb6069df2017-04-28 11:00:35 -0400169 return kIndicesPerFillRRect;
Brian Salomonfc527d22016-12-14 21:07:01 -0500170 case kStroke_RRectType:
171 return kIndicesPerStrokeRRect;
172 case kOverstroke_RRectType:
173 return kIndicesPerOverstrokeRRect;
174 }
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400175 SK_ABORT("Invalid type");
Jim Van Verthc5903412016-11-17 15:27:09 -0500176}
177
Robert Phillipscadd5db2021-08-30 11:37:18 -0400178const uint16_t* rrect_type_to_indices(RRectType type) {
Brian Salomonfc527d22016-12-14 21:07:01 -0500179 switch (type) {
180 case kFill_RRectType:
Brian Salomonfc527d22016-12-14 21:07:01 -0500181 case kStroke_RRectType:
Jim Van Verthb6069df2017-04-28 11:00:35 -0400182 return gRRectIndices + 6*4;
Brian Salomonfc527d22016-12-14 21:07:01 -0500183 case kOverstroke_RRectType:
Jim Van Verthb6069df2017-04-28 11:00:35 -0400184 return gRRectIndices;
Brian Salomonfc527d22016-12-14 21:07:01 -0500185 }
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400186 SK_ABORT("Invalid type");
Jim Van Verthc5903412016-11-17 15:27:09 -0500187}
188
Jim Van Verth57061ee2017-04-28 17:30:30 -0400189///////////////////////////////////////////////////////////////////////////////
190
Brian Salomon05969092017-07-13 11:20:51 -0400191class ShadowCircularRRectOp final : public GrMeshDrawOp {
Jim Van Verthc5903412016-11-17 15:27:09 -0500192public:
Brian Salomon25a88092016-12-01 09:36:50 -0500193 DEFINE_OP_CLASS_ID
Jim Van Verthc5903412016-11-17 15:27:09 -0500194
Jim Van Verth8d1e0ac2017-05-05 15:53:23 -0400195 // An insetWidth > 1/2 rect width or height indicates a simple fill.
Brian Salomon05969092017-07-13 11:20:51 -0400196 ShadowCircularRRectOp(GrColor color, const SkRect& devRect,
Jim Van Verth7da048b2019-10-29 13:28:14 -0400197 float devRadius, bool isCircle, float blurRadius, float insetWidth,
Greg Danielad994cd2019-12-10 09:35:16 -0500198 GrSurfaceProxyView falloffView)
Jim Van Verth7da048b2019-10-29 13:28:14 -0400199 : INHERITED(ClassID())
Greg Danielad994cd2019-12-10 09:35:16 -0500200 , fFalloffView(std::move(falloffView)) {
Jim Van Verthc5903412016-11-17 15:27:09 -0500201 SkRect bounds = devRect;
Jim Van Verth8d1e0ac2017-05-05 15:53:23 -0400202 SkASSERT(insetWidth > 0);
Jim Van Verth57061ee2017-04-28 17:30:30 -0400203 SkScalar innerRadius = 0.0f;
Jim Van Verthc5903412016-11-17 15:27:09 -0500204 SkScalar outerRadius = devRadius;
Jim Van Verth57061ee2017-04-28 17:30:30 -0400205 SkScalar umbraInset;
Jim Van Verth8d1e0ac2017-05-05 15:53:23 -0400206
207 RRectType type = kFill_RRectType;
Jim Van Verth57061ee2017-04-28 17:30:30 -0400208 if (isCircle) {
209 umbraInset = 0;
210 } else {
Brian Osman788b9162020-02-07 10:36:46 -0500211 umbraInset = std::max(outerRadius, blurRadius);
Jim Van Verth57061ee2017-04-28 17:30:30 -0400212 }
213
Jim Van Verth8d1e0ac2017-05-05 15:53:23 -0400214 // If stroke is greater than width or height, this is still a fill,
215 // otherwise we compute stroke params.
216 if (isCircle) {
217 innerRadius = devRadius - insetWidth;
218 type = innerRadius > 0 ? kStroke_RRectType : kFill_RRectType;
219 } else {
Brian Osman788b9162020-02-07 10:36:46 -0500220 if (insetWidth <= 0.5f*std::min(devRect.width(), devRect.height())) {
Jim Van Verth8d1e0ac2017-05-05 15:53:23 -0400221 // We don't worry about a real inner radius, we just need to know if we
222 // need to create overstroke vertices.
Brian Osman788b9162020-02-07 10:36:46 -0500223 innerRadius = std::max(insetWidth - umbraInset, 0.0f);
Jim Van Verth8d1e0ac2017-05-05 15:53:23 -0400224 type = innerRadius > 0 ? kOverstroke_RRectType : kStroke_RRectType;
Jim Van Verthb6069df2017-04-28 11:00:35 -0400225 }
Jim Van Verthc5903412016-11-17 15:27:09 -0500226 }
227
Greg Daniel5faf4742019-10-01 15:14:44 -0400228 this->setBounds(bounds, HasAABloat::kNo, IsHairline::kNo);
Jim Van Verthc5903412016-11-17 15:27:09 -0500229
Jim Van Verth57061ee2017-04-28 17:30:30 -0400230 fGeoData.emplace_back(Geometry{color, outerRadius, umbraInset, innerRadius,
Jim Van Verthfb186392018-09-11 11:37:46 -0400231 blurRadius, bounds, type, isCircle});
Jim Van Verth57061ee2017-04-28 17:30:30 -0400232 if (isCircle) {
233 fVertCount = circle_type_to_vert_count(kStroke_RRectType == type);
234 fIndexCount = circle_type_to_index_count(kStroke_RRectType == type);
235 } else {
236 fVertCount = rrect_type_to_vert_count(type);
237 fIndexCount = rrect_type_to_index_count(type);
238 }
Jim Van Verthc5903412016-11-17 15:27:09 -0500239 }
240
Brian Salomonfc527d22016-12-14 21:07:01 -0500241 const char* name() const override { return "ShadowCircularRRectOp"; }
Jim Van Verthc5903412016-11-17 15:27:09 -0500242
Brian Salomon05969092017-07-13 11:20:51 -0400243 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
244
Chris Dalton57ab06c2021-04-22 12:57:28 -0600245 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override {
Chris Dalton4b62aed2019-01-15 11:53:00 -0700246 return GrProcessorSet::EmptySetAnalysis();
Brian Salomon05969092017-07-13 11:20:51 -0400247 }
248
Brian Salomon92aee3d2016-12-21 09:20:25 -0500249private:
Jim Van Verth57061ee2017-04-28 17:30:30 -0400250 struct Geometry {
251 GrColor fColor;
252 SkScalar fOuterRadius;
253 SkScalar fUmbraInset;
254 SkScalar fInnerRadius;
255 SkScalar fBlurRadius;
256 SkRect fDevBounds;
257 RRectType fType;
258 bool fIsCircle;
259 };
260
Jim Van Verthc5903412016-11-17 15:27:09 -0500261 struct CircleVertex {
Brian Salomonfc527d22016-12-14 21:07:01 -0500262 SkPoint fPos;
263 GrColor fColor;
264 SkPoint fOffset;
Jim Van Verthb6069df2017-04-28 11:00:35 -0400265 SkScalar fDistanceCorrection;
Jim Van Verthc5903412016-11-17 15:27:09 -0500266 };
267
Jim Van Verth57061ee2017-04-28 17:30:30 -0400268 void fillInCircleVerts(const Geometry& args, bool isStroked, CircleVertex** verts) const {
269
270 GrColor color = args.fColor;
271 SkScalar outerRadius = args.fOuterRadius;
272 SkScalar innerRadius = args.fInnerRadius;
273 SkScalar blurRadius = args.fBlurRadius;
274 SkScalar distanceCorrection = outerRadius / blurRadius;
275
276 const SkRect& bounds = args.fDevBounds;
277
278 // The inner radius in the vertex data must be specified in normalized space.
279 innerRadius = innerRadius / outerRadius;
280
281 SkPoint center = SkPoint::Make(bounds.centerX(), bounds.centerY());
282 SkScalar halfWidth = 0.5f * bounds.width();
283 SkScalar octOffset = 0.41421356237f; // sqrt(2) - 1
284
285 (*verts)->fPos = center + SkPoint::Make(-octOffset * halfWidth, -halfWidth);
Jim Van Verthc5903412016-11-17 15:27:09 -0500286 (*verts)->fColor = color;
Jim Van Verth57061ee2017-04-28 17:30:30 -0400287 (*verts)->fOffset = SkPoint::Make(-octOffset, -1);
Jim Van Verthb6069df2017-04-28 11:00:35 -0400288 (*verts)->fDistanceCorrection = distanceCorrection;
Jim Van Verthc5903412016-11-17 15:27:09 -0500289 (*verts)++;
290
Jim Van Verth57061ee2017-04-28 17:30:30 -0400291 (*verts)->fPos = center + SkPoint::Make(octOffset * halfWidth, -halfWidth);
Jim Van Verthc5903412016-11-17 15:27:09 -0500292 (*verts)->fColor = color;
Jim Van Verth57061ee2017-04-28 17:30:30 -0400293 (*verts)->fOffset = SkPoint::Make(octOffset, -1);
Jim Van Verthb6069df2017-04-28 11:00:35 -0400294 (*verts)->fDistanceCorrection = distanceCorrection;
Jim Van Verthc5903412016-11-17 15:27:09 -0500295 (*verts)++;
296
Jim Van Verth57061ee2017-04-28 17:30:30 -0400297 (*verts)->fPos = center + SkPoint::Make(halfWidth, -octOffset * halfWidth);
Jim Van Verthc5903412016-11-17 15:27:09 -0500298 (*verts)->fColor = color;
Jim Van Verth57061ee2017-04-28 17:30:30 -0400299 (*verts)->fOffset = SkPoint::Make(1, -octOffset);
Jim Van Verthb6069df2017-04-28 11:00:35 -0400300 (*verts)->fDistanceCorrection = distanceCorrection;
Jim Van Verthc5903412016-11-17 15:27:09 -0500301 (*verts)++;
302
Jim Van Verth57061ee2017-04-28 17:30:30 -0400303 (*verts)->fPos = center + SkPoint::Make(halfWidth, octOffset * halfWidth);
Jim Van Verthc5903412016-11-17 15:27:09 -0500304 (*verts)->fColor = color;
Jim Van Verth57061ee2017-04-28 17:30:30 -0400305 (*verts)->fOffset = SkPoint::Make(1, octOffset);
Jim Van Verthb6069df2017-04-28 11:00:35 -0400306 (*verts)->fDistanceCorrection = distanceCorrection;
Jim Van Verthc5903412016-11-17 15:27:09 -0500307 (*verts)++;
Jim Van Verth57061ee2017-04-28 17:30:30 -0400308
309 (*verts)->fPos = center + SkPoint::Make(octOffset * halfWidth, halfWidth);
310 (*verts)->fColor = color;
311 (*verts)->fOffset = SkPoint::Make(octOffset, 1);
312 (*verts)->fDistanceCorrection = distanceCorrection;
313 (*verts)++;
314
315 (*verts)->fPos = center + SkPoint::Make(-octOffset * halfWidth, halfWidth);
316 (*verts)->fColor = color;
317 (*verts)->fOffset = SkPoint::Make(-octOffset, 1);
318 (*verts)->fDistanceCorrection = distanceCorrection;
319 (*verts)++;
320
321 (*verts)->fPos = center + SkPoint::Make(-halfWidth, octOffset * halfWidth);
322 (*verts)->fColor = color;
323 (*verts)->fOffset = SkPoint::Make(-1, octOffset);
324 (*verts)->fDistanceCorrection = distanceCorrection;
325 (*verts)++;
326
327 (*verts)->fPos = center + SkPoint::Make(-halfWidth, -octOffset * halfWidth);
328 (*verts)->fColor = color;
329 (*verts)->fOffset = SkPoint::Make(-1, -octOffset);
330 (*verts)->fDistanceCorrection = distanceCorrection;
331 (*verts)++;
332
333 if (isStroked) {
334 // compute the inner ring
335
336 // cosine and sine of pi/8
337 SkScalar c = 0.923579533f;
338 SkScalar s = 0.382683432f;
339 SkScalar r = args.fInnerRadius;
340
341 (*verts)->fPos = center + SkPoint::Make(-s * r, -c * r);
342 (*verts)->fColor = color;
343 (*verts)->fOffset = SkPoint::Make(-s * innerRadius, -c * innerRadius);
344 (*verts)->fDistanceCorrection = distanceCorrection;
345 (*verts)++;
346
347 (*verts)->fPos = center + SkPoint::Make(s * r, -c * r);
348 (*verts)->fColor = color;
349 (*verts)->fOffset = SkPoint::Make(s * innerRadius, -c * innerRadius);
350 (*verts)->fDistanceCorrection = distanceCorrection;
351 (*verts)++;
352
353 (*verts)->fPos = center + SkPoint::Make(c * r, -s * r);
354 (*verts)->fColor = color;
355 (*verts)->fOffset = SkPoint::Make(c * innerRadius, -s * innerRadius);
356 (*verts)->fDistanceCorrection = distanceCorrection;
357 (*verts)++;
358
359 (*verts)->fPos = center + SkPoint::Make(c * r, s * r);
360 (*verts)->fColor = color;
361 (*verts)->fOffset = SkPoint::Make(c * innerRadius, s * innerRadius);
362 (*verts)->fDistanceCorrection = distanceCorrection;
363 (*verts)++;
364
365 (*verts)->fPos = center + SkPoint::Make(s * r, c * r);
366 (*verts)->fColor = color;
367 (*verts)->fOffset = SkPoint::Make(s * innerRadius, c * innerRadius);
368 (*verts)->fDistanceCorrection = distanceCorrection;
369 (*verts)++;
370
371 (*verts)->fPos = center + SkPoint::Make(-s * r, c * r);
372 (*verts)->fColor = color;
373 (*verts)->fOffset = SkPoint::Make(-s * innerRadius, c * innerRadius);
374 (*verts)->fDistanceCorrection = distanceCorrection;
375 (*verts)++;
376
377 (*verts)->fPos = center + SkPoint::Make(-c * r, s * r);
378 (*verts)->fColor = color;
379 (*verts)->fOffset = SkPoint::Make(-c * innerRadius, s * innerRadius);
380 (*verts)->fDistanceCorrection = distanceCorrection;
381 (*verts)++;
382
383 (*verts)->fPos = center + SkPoint::Make(-c * r, -s * r);
384 (*verts)->fColor = color;
385 (*verts)->fOffset = SkPoint::Make(-c * innerRadius, -s * innerRadius);
386 (*verts)->fDistanceCorrection = distanceCorrection;
387 (*verts)++;
388 } else {
389 // filled
390 (*verts)->fPos = center;
391 (*verts)->fColor = color;
392 (*verts)->fOffset = SkPoint::Make(0, 0);
393 (*verts)->fDistanceCorrection = distanceCorrection;
394 (*verts)++;
395 }
396 }
397
398 void fillInRRectVerts(const Geometry& args, CircleVertex** verts) const {
399 GrColor color = args.fColor;
400 SkScalar outerRadius = args.fOuterRadius;
401
402 const SkRect& bounds = args.fDevBounds;
403
404 SkScalar umbraInset = args.fUmbraInset;
Brian Osman788b9162020-02-07 10:36:46 -0500405 SkScalar minDim = 0.5f*std::min(bounds.width(), bounds.height());
Jim Van Verth57061ee2017-04-28 17:30:30 -0400406 if (umbraInset > minDim) {
407 umbraInset = minDim;
408 }
409
410 SkScalar xInner[4] = { bounds.fLeft + umbraInset, bounds.fRight - umbraInset,
411 bounds.fLeft + umbraInset, bounds.fRight - umbraInset };
412 SkScalar xMid[4] = { bounds.fLeft + outerRadius, bounds.fRight - outerRadius,
413 bounds.fLeft + outerRadius, bounds.fRight - outerRadius };
414 SkScalar xOuter[4] = { bounds.fLeft, bounds.fRight,
415 bounds.fLeft, bounds.fRight };
416 SkScalar yInner[4] = { bounds.fTop + umbraInset, bounds.fTop + umbraInset,
417 bounds.fBottom - umbraInset, bounds.fBottom - umbraInset };
418 SkScalar yMid[4] = { bounds.fTop + outerRadius, bounds.fTop + outerRadius,
419 bounds.fBottom - outerRadius, bounds.fBottom - outerRadius };
420 SkScalar yOuter[4] = { bounds.fTop, bounds.fTop,
421 bounds.fBottom, bounds.fBottom };
422
423 SkScalar blurRadius = args.fBlurRadius;
424
425 // In the case where we have to inset more for the umbra, our two triangles in the
426 // corner get skewed to a diamond rather than a square. To correct for that,
427 // we also skew the vectors we send to the shader that help define the circle.
428 // By doing so, we end up with a quarter circle in the corner rather than the
429 // elliptical curve.
Jim Van Verth4c8c1e82018-04-23 17:14:48 -0400430
431 // This is a bit magical, but it gives us the correct results at extrema:
432 // a) umbraInset == outerRadius produces an orthogonal vector
433 // b) outerRadius == 0 produces a diagonal vector
434 // And visually the corner looks correct.
435 SkVector outerVec = SkVector::Make(outerRadius - umbraInset, -outerRadius - umbraInset);
Jim Van Verth57061ee2017-04-28 17:30:30 -0400436 outerVec.normalize();
Jim Van Verth4c8c1e82018-04-23 17:14:48 -0400437 // We want the circle edge to fall fractionally along the diagonal at
438 // (sqrt(2)*(umbraInset - outerRadius) + outerRadius)/sqrt(2)*umbraInset
439 //
440 // Setting the components of the diagonal offset to the following value will give us that.
441 SkScalar diagVal = umbraInset / (SK_ScalarSqrt2*(outerRadius - umbraInset) - outerRadius);
442 SkVector diagVec = SkVector::Make(diagVal, diagVal);
Jim Van Verth57061ee2017-04-28 17:30:30 -0400443 SkScalar distanceCorrection = umbraInset / blurRadius;
444
445 // build corner by corner
446 for (int i = 0; i < 4; ++i) {
447 // inner point
448 (*verts)->fPos = SkPoint::Make(xInner[i], yInner[i]);
449 (*verts)->fColor = color;
450 (*verts)->fOffset = SkVector::Make(0, 0);
451 (*verts)->fDistanceCorrection = distanceCorrection;
452 (*verts)++;
453
454 // outer points
455 (*verts)->fPos = SkPoint::Make(xOuter[i], yInner[i]);
456 (*verts)->fColor = color;
457 (*verts)->fOffset = SkVector::Make(0, -1);
458 (*verts)->fDistanceCorrection = distanceCorrection;
459 (*verts)++;
460
461 (*verts)->fPos = SkPoint::Make(xOuter[i], yMid[i]);
462 (*verts)->fColor = color;
463 (*verts)->fOffset = outerVec;
464 (*verts)->fDistanceCorrection = distanceCorrection;
465 (*verts)++;
466
467 (*verts)->fPos = SkPoint::Make(xOuter[i], yOuter[i]);
468 (*verts)->fColor = color;
469 (*verts)->fOffset = diagVec;
470 (*verts)->fDistanceCorrection = distanceCorrection;
471 (*verts)++;
472
473 (*verts)->fPos = SkPoint::Make(xMid[i], yOuter[i]);
474 (*verts)->fColor = color;
475 (*verts)->fOffset = outerVec;
476 (*verts)->fDistanceCorrection = distanceCorrection;
477 (*verts)++;
478
479 (*verts)->fPos = SkPoint::Make(xInner[i], yOuter[i]);
480 (*verts)->fColor = color;
481 (*verts)->fOffset = SkVector::Make(0, -1);
482 (*verts)->fDistanceCorrection = distanceCorrection;
483 (*verts)++;
484 }
485
486 // Add the additional vertices for overstroked rrects.
487 // Effectively this is an additional stroked rrect, with its
488 // parameters equal to those in the center of the 9-patch. This will
489 // give constant values across this inner ring.
490 if (kOverstroke_RRectType == args.fType) {
491 SkASSERT(args.fInnerRadius > 0.0f);
492
493 SkScalar inset = umbraInset + args.fInnerRadius;
494
495 // TL
496 (*verts)->fPos = SkPoint::Make(bounds.fLeft + inset, bounds.fTop + inset);
497 (*verts)->fColor = color;
498 (*verts)->fOffset = SkPoint::Make(0, 0);
499 (*verts)->fDistanceCorrection = distanceCorrection;
500 (*verts)++;
501
502 // TR
503 (*verts)->fPos = SkPoint::Make(bounds.fRight - inset, bounds.fTop + inset);
504 (*verts)->fColor = color;
505 (*verts)->fOffset = SkPoint::Make(0, 0);
506 (*verts)->fDistanceCorrection = distanceCorrection;
507 (*verts)++;
508
509 // BL
510 (*verts)->fPos = SkPoint::Make(bounds.fLeft + inset, bounds.fBottom - inset);
511 (*verts)->fColor = color;
512 (*verts)->fOffset = SkPoint::Make(0, 0);
513 (*verts)->fDistanceCorrection = distanceCorrection;
514 (*verts)++;
515
516 // BR
517 (*verts)->fPos = SkPoint::Make(bounds.fRight - inset, bounds.fBottom - inset);
518 (*verts)->fColor = color;
519 (*verts)->fOffset = SkPoint::Make(0, 0);
520 (*verts)->fDistanceCorrection = distanceCorrection;
521 (*verts)++;
522 }
523
Jim Van Verthc5903412016-11-17 15:27:09 -0500524 }
525
Robert Phillips2669a7b2020-03-12 12:07:19 -0400526 GrProgramInfo* programInfo() override { return fProgramInfo; }
527
Robert Phillips6941f4a2020-03-12 09:41:54 -0400528 void onCreateProgramInfo(const GrCaps* caps,
529 SkArenaAlloc* arena,
Adlai Hollere2296f72020-11-19 13:41:26 -0500530 const GrSurfaceProxyView& writeView,
Chris Dalton6aaf00f2021-07-13 13:26:39 -0600531 bool usesMSAASurface,
Robert Phillips6941f4a2020-03-12 09:41:54 -0400532 GrAppliedClip&& appliedClip,
John Stiles52cb1d02021-06-02 11:58:05 -0400533 const GrDstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500534 GrXferBarrierFlags renderPassXferBarriers,
535 GrLoadOp colorLoadOp) override {
Robert Phillips6941f4a2020-03-12 09:41:54 -0400536 GrGeometryProcessor* gp = GrRRectShadowGeoProc::Make(arena, fFalloffView);
537 SkASSERT(sizeof(CircleVertex) == gp->vertexStride());
538
Brian Salomon8afde5f2020-04-01 16:22:00 -0400539 fProgramInfo = GrSimpleMeshDrawOpHelper::CreateProgramInfo(caps, arena, writeView,
Chris Dalton2a26c502021-08-26 10:05:11 -0600540 usesMSAASurface,
Robert Phillips6941f4a2020-03-12 09:41:54 -0400541 std::move(appliedClip),
542 dstProxyView, gp,
543 GrProcessorSet::MakeEmptySet(),
544 GrPrimitiveType::kTriangles,
Greg Danield358cbe2020-09-11 09:33:54 -0400545 renderPassXferBarriers,
Greg Daniel42dbca52020-11-20 10:22:43 -0500546 colorLoadOp,
Robert Phillips6941f4a2020-03-12 09:41:54 -0400547 GrPipeline::InputFlags::kNone,
Chris Dalton765ed362020-03-16 17:34:44 -0600548 &GrUserStencilSettings::kUnused);
Robert Phillips6941f4a2020-03-12 09:41:54 -0400549 }
550
Robert Phillips71143952021-06-17 14:55:07 -0400551 void onPrepareDraws(GrMeshDrawTarget* target) override {
Jim Van Verthc5903412016-11-17 15:27:09 -0500552 int instanceCount = fGeoData.count();
Jim Van Verthc5903412016-11-17 15:27:09 -0500553
Brian Salomon12d22642019-01-29 14:38:50 -0500554 sk_sp<const GrBuffer> vertexBuffer;
Jim Van Verthc5903412016-11-17 15:27:09 -0500555 int firstVertex;
Brian Salomon92be2f72018-06-19 14:33:47 -0400556 CircleVertex* verts = (CircleVertex*)target->makeVertexSpace(
557 sizeof(CircleVertex), fVertCount, &vertexBuffer, &firstVertex);
Jim Van Verthc5903412016-11-17 15:27:09 -0500558 if (!verts) {
559 SkDebugf("Could not allocate vertices\n");
560 return;
561 }
562
Brian Salomon12d22642019-01-29 14:38:50 -0500563 sk_sp<const GrBuffer> indexBuffer;
Jim Van Verthc5903412016-11-17 15:27:09 -0500564 int firstIndex = 0;
565 uint16_t* indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
566 if (!indices) {
567 SkDebugf("Could not allocate indices\n");
568 return;
569 }
570
571 int currStartVertex = 0;
572 for (int i = 0; i < instanceCount; i++) {
573 const Geometry& args = fGeoData[i];
574
Jim Van Verth57061ee2017-04-28 17:30:30 -0400575 if (args.fIsCircle) {
576 bool isStroked = SkToBool(kStroke_RRectType == args.fType);
577 this->fillInCircleVerts(args, isStroked, &verts);
Jim Van Verthc5903412016-11-17 15:27:09 -0500578
Jim Van Verth57061ee2017-04-28 17:30:30 -0400579 const uint16_t* primIndices = circle_type_to_indices(isStroked);
580 const int primIndexCount = circle_type_to_index_count(isStroked);
John Stiles7c3fa4e2021-08-10 17:00:56 -0400581 for (int j = 0; j < primIndexCount; ++j) {
582 *indices++ = primIndices[j] + currStartVertex;
Jim Van Verth57061ee2017-04-28 17:30:30 -0400583 }
Jim Van Verthc5903412016-11-17 15:27:09 -0500584
Jim Van Verth57061ee2017-04-28 17:30:30 -0400585 currStartVertex += circle_type_to_vert_count(isStroked);
Jim Van Verthc5903412016-11-17 15:27:09 -0500586
Jim Van Verth57061ee2017-04-28 17:30:30 -0400587 } else {
588 this->fillInRRectVerts(args, &verts);
589
590 const uint16_t* primIndices = rrect_type_to_indices(args.fType);
591 const int primIndexCount = rrect_type_to_index_count(args.fType);
John Stiles7c3fa4e2021-08-10 17:00:56 -0400592 for (int j = 0; j < primIndexCount; ++j) {
593 *indices++ = primIndices[j] + currStartVertex;
Jim Van Verth57061ee2017-04-28 17:30:30 -0400594 }
595
596 currStartVertex += rrect_type_to_vert_count(args.fType);
Jim Van Verthb6069df2017-04-28 11:00:35 -0400597 }
Jim Van Verthc5903412016-11-17 15:27:09 -0500598 }
599
Robert Phillips6941f4a2020-03-12 09:41:54 -0400600 fMesh = target->allocMesh();
601 fMesh->setIndexed(std::move(indexBuffer), fIndexCount, firstIndex, 0, fVertCount - 1,
Chris Dalton37c7bdd2020-03-13 09:21:12 -0600602 GrPrimitiveRestart::kNo, std::move(vertexBuffer), firstVertex);
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700603 }
604
605 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
Robert Phillips6941f4a2020-03-12 09:41:54 -0400606 if (!fProgramInfo) {
607 this->createProgramInfo(flushState);
608 }
Robert Phillips3968fcb2019-12-05 16:40:31 -0500609
Robert Phillips6941f4a2020-03-12 09:41:54 -0400610 if (!fProgramInfo || !fMesh) {
611 return;
612 }
613
Chris Dalton765ed362020-03-16 17:34:44 -0600614 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
Robert Phillips787fd9d2021-03-22 14:48:09 -0400615 flushState->bindTextures(fProgramInfo->geomProc(), *fFalloffView.proxy(),
Chris Dalton765ed362020-03-16 17:34:44 -0600616 fProgramInfo->pipeline());
617 flushState->drawMesh(*fMesh);
Jim Van Verthc5903412016-11-17 15:27:09 -0500618 }
619
Herb Derbye25c3002020-10-27 15:57:27 -0400620 CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override {
Brian Salomonfc527d22016-12-14 21:07:01 -0500621 ShadowCircularRRectOp* that = t->cast<ShadowCircularRRectOp>();
Jim Van Verthc5903412016-11-17 15:27:09 -0500622 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
Jim Van Verthc5903412016-11-17 15:27:09 -0500623 fVertCount += that->fVertCount;
624 fIndexCount += that->fIndexCount;
Brian Salomon7eae3e02018-08-07 14:02:38 +0000625 return CombineResult::kMerged;
Jim Van Verthc5903412016-11-17 15:27:09 -0500626 }
627
John Stilesaf366522020-08-13 09:57:34 -0400628#if GR_TEST_UTILS
629 SkString onDumpInfo() const override {
630 SkString string;
631 for (int i = 0; i < fGeoData.count(); ++i) {
632 string.appendf(
633 "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f],"
634 "OuterRad: %.2f, Umbra: %.2f, InnerRad: %.2f, BlurRad: %.2f\n",
635 fGeoData[i].fColor, fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.fTop,
636 fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds.fBottom,
637 fGeoData[i].fOuterRadius, fGeoData[i].fUmbraInset,
638 fGeoData[i].fInnerRadius, fGeoData[i].fBlurRadius);
639 }
640 return string;
641 }
642#endif
643
Robert Phillips294723d2021-06-17 09:23:58 -0400644 void visitProxies(const GrVisitProxyFunc& func) const override {
Brian Salomon7e67dca2020-07-21 09:27:25 -0400645 func(fFalloffView.proxy(), GrMipmapped(false));
Robert Phillips6941f4a2020-03-12 09:41:54 -0400646 if (fProgramInfo) {
Chris Daltonbe457422020-03-16 18:05:03 -0600647 fProgramInfo->visitFPProxies(func);
Robert Phillips6941f4a2020-03-12 09:41:54 -0400648 }
Jim Van Verth7da048b2019-10-29 13:28:14 -0400649 }
650
Jim Van Verthc5903412016-11-17 15:27:09 -0500651 SkSTArray<1, Geometry, true> fGeoData;
Brian Salomonfc527d22016-12-14 21:07:01 -0500652 int fVertCount;
653 int fIndexCount;
Greg Danielad994cd2019-12-10 09:35:16 -0500654 GrSurfaceProxyView fFalloffView;
Jim Van Verthc5903412016-11-17 15:27:09 -0500655
Chris Daltoneb694b72020-03-16 09:25:50 -0600656 GrSimpleMesh* fMesh = nullptr;
Robert Phillips6941f4a2020-03-12 09:41:54 -0400657 GrProgramInfo* fProgramInfo = nullptr;
658
John Stiles7571f9e2020-09-02 22:42:33 -0400659 using INHERITED = GrMeshDrawOp;
Jim Van Verthc5903412016-11-17 15:27:09 -0500660};
661
Brian Salomon05969092017-07-13 11:20:51 -0400662} // anonymous namespace
663
Jim Van Verthc5903412016-11-17 15:27:09 -0500664///////////////////////////////////////////////////////////////////////////////
665
Robert Phillipscadd5db2021-08-30 11:37:18 -0400666namespace skgpu::v1::ShadowRRectOp {
Jim Van Verth7da048b2019-10-29 13:28:14 -0400667
Robert Phillips692915e2020-09-30 13:56:51 -0400668static GrSurfaceProxyView create_falloff_texture(GrRecordingContext* rContext) {
Jim Van Verth7da048b2019-10-29 13:28:14 -0400669 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
670 GrUniqueKey key;
671 GrUniqueKey::Builder builder(&key, kDomain, 0, "Shadow Gaussian Falloff");
672 builder.finish();
673
Robert Phillipsd464feb2020-10-08 11:00:02 -0400674 auto threadSafeCache = rContext->priv().threadSafeCache();
Greg Daniel6f5441a2020-01-28 17:02:49 -0500675
Robert Phillipsd464feb2020-10-08 11:00:02 -0400676 GrSurfaceProxyView view = threadSafeCache->find(key);
Robert Phillips692915e2020-09-30 13:56:51 -0400677 if (view) {
678 SkASSERT(view.origin() == kTopLeft_GrSurfaceOrigin);
679 return view;
Jim Van Verth7da048b2019-10-29 13:28:14 -0400680 }
681
Greg Daniel9f0dfbd2020-02-10 11:47:11 -0500682 static const int kWidth = 128;
683 static const size_t kRowBytes = kWidth * GrColorTypeBytesPerPixel(GrColorType::kAlpha_8);
684 SkImageInfo ii = SkImageInfo::MakeA8(kWidth, 1);
685
686 SkBitmap bitmap;
687 bitmap.allocPixels(ii, kRowBytes);
688
689 unsigned char* values = (unsigned char*)bitmap.getPixels();
690 for (int i = 0; i < 128; ++i) {
691 SkScalar d = SK_Scalar1 - i / SkIntToScalar(127);
692 values[i] = SkScalarRoundToInt((SkScalarExp(-4 * d * d) - 0.018f) * 255);
693 }
694 bitmap.setImmutable();
695
Brian Salomon27c42022021-04-28 12:39:21 -0400696 view = std::get<0>(GrMakeUncachedBitmapProxyView(rContext, bitmap));
Robert Phillips692915e2020-09-30 13:56:51 -0400697 if (!view) {
698 return {};
Greg Daniel9f0dfbd2020-02-10 11:47:11 -0500699 }
Robert Phillips692915e2020-09-30 13:56:51 -0400700
Robert Phillipsd464feb2020-10-08 11:00:02 -0400701 view = threadSafeCache->add(key, view);
Robert Phillips692915e2020-09-30 13:56:51 -0400702 SkASSERT(view.origin() == kTopLeft_GrSurfaceOrigin);
Greg Daniel9f0dfbd2020-02-10 11:47:11 -0500703 return view;
Jim Van Verth7da048b2019-10-29 13:28:14 -0400704}
705
Herb Derbyc76d4092020-10-07 16:46:15 -0400706GrOp::Owner Make(GrRecordingContext* context,
707 GrColor color,
708 const SkMatrix& viewMatrix,
709 const SkRRect& rrect,
710 SkScalar blurWidth,
711 SkScalar insetWidth) {
Brian Salomon53e4c3c2016-12-21 11:38:53 -0500712 // Shadow rrect ops only handle simple circular rrects.
Mike Reed242135a2018-02-22 13:41:39 -0500713 SkASSERT(viewMatrix.isSimilarity() && SkRRectPriv::EqualRadii(rrect));
Jim Van Verth57061ee2017-04-28 17:30:30 -0400714
Greg Daniel9f0dfbd2020-02-10 11:47:11 -0500715 GrSurfaceProxyView falloffView = create_falloff_texture(context);
716 if (!falloffView) {
Jim Van Verth7da048b2019-10-29 13:28:14 -0400717 return nullptr;
718 }
719
Brian Salomon53e4c3c2016-12-21 11:38:53 -0500720 // Do any matrix crunching before we reset the draw state for device coords.
Jim Van Verthc5903412016-11-17 15:27:09 -0500721 const SkRect& rrectBounds = rrect.getBounds();
722 SkRect bounds;
723 viewMatrix.mapRect(&bounds, rrectBounds);
724
Jim Van Verth8d1e0ac2017-05-05 15:53:23 -0400725 // Map radius and inset. As the matrix is a similarity matrix, this should be isotropic.
Mike Reed242135a2018-02-22 13:41:39 -0500726 SkScalar radius = SkRRectPriv::GetSimpleRadii(rrect).fX;
Jim Van Verth8d1e0ac2017-05-05 15:53:23 -0400727 SkScalar matrixFactor = viewMatrix[SkMatrix::kMScaleX] + viewMatrix[SkMatrix::kMSkewX];
728 SkScalar scaledRadius = SkScalarAbs(radius*matrixFactor);
729 SkScalar scaledInsetWidth = SkScalarAbs(insetWidth*matrixFactor);
Jim Van Verthc5903412016-11-17 15:27:09 -0500730
Robert Phillipse5763782019-04-17 14:38:24 -0400731 if (scaledInsetWidth <= 0) {
732 return nullptr;
733 }
734
Herb Derbyc76d4092020-10-07 16:46:15 -0400735 return GrOp::Make<ShadowCircularRRectOp>(context,
736 color,
737 bounds,
738 scaledRadius,
739 rrect.isOval(),
740 blurWidth,
741 scaledInsetWidth,
742 std::move(falloffView));
Jim Van Verthc5903412016-11-17 15:27:09 -0500743}
Robert Phillipscadd5db2021-08-30 11:37:18 -0400744
745} // namespace skgpu::v1::ShadowRRectOp
Jim Van Verth57061ee2017-04-28 17:30:30 -0400746
Jim Van Verthc5903412016-11-17 15:27:09 -0500747///////////////////////////////////////////////////////////////////////////////
748
Hal Canary6f6961e2017-01-31 13:50:44 -0500749#if GR_TEST_UTILS
Jim Van Verthc5903412016-11-17 15:27:09 -0500750
Robert Phillipscadd5db2021-08-30 11:37:18 -0400751#include "src/gpu/GrDrawOpTest.h"
752
Brian Salomon05969092017-07-13 11:20:51 -0400753GR_DRAW_OP_TEST_DEFINE(ShadowRRectOp) {
Brian Salomonfc118442019-11-22 19:09:27 -0500754 // We may choose matrix and inset values that cause the factory to fail. We loop until we find
755 // an acceptable combination.
Brian Osman4462c042018-06-08 16:35:44 -0400756 do {
Brian Salomonfc118442019-11-22 19:09:27 -0500757 // create a similarity matrix
758 SkScalar rotate = random->nextSScalar1() * 360.f;
759 SkScalar translateX = random->nextSScalar1() * 1000.f;
760 SkScalar translateY = random->nextSScalar1() * 1000.f;
761 SkScalar scale = random->nextSScalar1() * 100.f;
762 SkMatrix viewMatrix;
763 viewMatrix.setRotate(rotate);
764 viewMatrix.postTranslate(translateX, translateY);
765 viewMatrix.postScale(scale, scale);
766 SkScalar insetWidth = random->nextSScalar1() * 72.f;
767 SkScalar blurWidth = random->nextSScalar1() * 72.f;
768 bool isCircle = random->nextBool();
769 // This op doesn't use a full GrPaint, just a color.
770 GrColor color = paint.getColor4f().toBytes_RGBA();
771 if (isCircle) {
772 SkRect circle = GrTest::TestSquare(random);
773 SkRRect rrect = SkRRect::MakeOval(circle);
Robert Phillipscadd5db2021-08-30 11:37:18 -0400774 if (auto op = skgpu::v1::ShadowRRectOp::Make(
Brian Salomonfc118442019-11-22 19:09:27 -0500775 context, color, viewMatrix, rrect, blurWidth, insetWidth)) {
776 return op;
777 }
778 } else {
779 SkRRect rrect;
780 do {
781 // This may return a rrect with elliptical corners, which will cause an assert.
782 rrect = GrTest::TestRRectSimple(random);
783 } while (!SkRRectPriv::IsSimpleCircular(rrect));
Robert Phillipscadd5db2021-08-30 11:37:18 -0400784 if (auto op = skgpu::v1::ShadowRRectOp::Make(
Brian Salomonfc118442019-11-22 19:09:27 -0500785 context, color, viewMatrix, rrect, blurWidth, insetWidth)) {
786 return op;
787 }
788 }
789 } while (true);
Jim Van Verthc5903412016-11-17 15:27:09 -0500790}
791
Robert Phillipscadd5db2021-08-30 11:37:18 -0400792#endif // GR_TEST_UTILS