xref: /aosp_15_r20/external/skia/src/gpu/ganesh/ops/ShadowRRectOp.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2016 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/ShadowRRectOp.h"
8*c8dee2aaSAndroid Build Coastguard Worker 
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRRect.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrRecordingContext.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrTypes.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkColorData.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkPoint_impl.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkRRectPriv.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ResourceKey.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrAppliedClip.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrBuffer.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGeometryProcessor.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrMeshDrawTarget.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrOpFlushState.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrPaint.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrPipeline.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorSet.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProgramInfo.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRecordingContextPriv.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSimpleMesh.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSurfaceProxyView.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrThreadSafeCache.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrUserStencilSettings.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/SkGr.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrShadowGeoProc.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrMeshDrawOp.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrSimpleMeshDrawOpHelper.h"
45*c8dee2aaSAndroid Build Coastguard Worker 
46*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
47*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
48*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDrawOpTest.h"
49*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrTestUtils.h"
50*c8dee2aaSAndroid Build Coastguard Worker #endif
51*c8dee2aaSAndroid Build Coastguard Worker 
52*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
53*c8dee2aaSAndroid Build Coastguard Worker #include <array>
54*c8dee2aaSAndroid Build Coastguard Worker #include <climits>
55*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
56*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
57*c8dee2aaSAndroid Build Coastguard Worker #include <tuple>
58*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
59*c8dee2aaSAndroid Build Coastguard Worker 
60*c8dee2aaSAndroid Build Coastguard Worker class GrCaps;
61*c8dee2aaSAndroid Build Coastguard Worker class GrDstProxyView;
62*c8dee2aaSAndroid Build Coastguard Worker class SkArenaAlloc;
63*c8dee2aaSAndroid Build Coastguard Worker enum class GrXferBarrierFlags;
64*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu {
65*c8dee2aaSAndroid Build Coastguard Worker enum class Mipmapped : bool;
66*c8dee2aaSAndroid Build Coastguard Worker }
67*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::ganesh {
68*c8dee2aaSAndroid Build Coastguard Worker class SurfaceDrawContext;
69*c8dee2aaSAndroid Build Coastguard Worker }
70*c8dee2aaSAndroid Build Coastguard Worker 
71*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
72*c8dee2aaSAndroid Build Coastguard Worker 
73*c8dee2aaSAndroid Build Coastguard Worker namespace {
74*c8dee2aaSAndroid Build Coastguard Worker 
75*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
76*c8dee2aaSAndroid Build Coastguard Worker // Circle Data
77*c8dee2aaSAndroid Build Coastguard Worker //
78*c8dee2aaSAndroid Build Coastguard Worker // We have two possible cases for geometry for a circle:
79*c8dee2aaSAndroid Build Coastguard Worker 
80*c8dee2aaSAndroid Build Coastguard Worker // In the case of a normal fill, we draw geometry for the circle as an octagon.
81*c8dee2aaSAndroid Build Coastguard Worker static const uint16_t gFillCircleIndices[] = {
82*c8dee2aaSAndroid Build Coastguard Worker         // enter the octagon
83*c8dee2aaSAndroid Build Coastguard Worker         // clang-format off
84*c8dee2aaSAndroid Build Coastguard Worker         0, 1, 8, 1, 2, 8,
85*c8dee2aaSAndroid Build Coastguard Worker         2, 3, 8, 3, 4, 8,
86*c8dee2aaSAndroid Build Coastguard Worker         4, 5, 8, 5, 6, 8,
87*c8dee2aaSAndroid Build Coastguard Worker         6, 7, 8, 7, 0, 8,
88*c8dee2aaSAndroid Build Coastguard Worker         // clang-format on
89*c8dee2aaSAndroid Build Coastguard Worker };
90*c8dee2aaSAndroid Build Coastguard Worker 
91*c8dee2aaSAndroid Build Coastguard Worker // For stroked circles, we use two nested octagons.
92*c8dee2aaSAndroid Build Coastguard Worker static const uint16_t gStrokeCircleIndices[] = {
93*c8dee2aaSAndroid Build Coastguard Worker         // enter the octagon
94*c8dee2aaSAndroid Build Coastguard Worker         // clang-format off
95*c8dee2aaSAndroid Build Coastguard Worker         0, 1,  9, 0,  9,  8,
96*c8dee2aaSAndroid Build Coastguard Worker         1, 2, 10, 1, 10,  9,
97*c8dee2aaSAndroid Build Coastguard Worker         2, 3, 11, 2, 11, 10,
98*c8dee2aaSAndroid Build Coastguard Worker         3, 4, 12, 3, 12, 11,
99*c8dee2aaSAndroid Build Coastguard Worker         4, 5, 13, 4, 13, 12,
100*c8dee2aaSAndroid Build Coastguard Worker         5, 6, 14, 5, 14, 13,
101*c8dee2aaSAndroid Build Coastguard Worker         6, 7, 15, 6, 15, 14,
102*c8dee2aaSAndroid Build Coastguard Worker         7, 0,  8, 7,  8, 15,
103*c8dee2aaSAndroid Build Coastguard Worker         // clang-format on
104*c8dee2aaSAndroid Build Coastguard Worker };
105*c8dee2aaSAndroid Build Coastguard Worker 
106*c8dee2aaSAndroid Build Coastguard Worker static const int kIndicesPerFillCircle = std::size(gFillCircleIndices);
107*c8dee2aaSAndroid Build Coastguard Worker static const int kIndicesPerStrokeCircle = std::size(gStrokeCircleIndices);
108*c8dee2aaSAndroid Build Coastguard Worker static const int kVertsPerStrokeCircle = 16;
109*c8dee2aaSAndroid Build Coastguard Worker static const int kVertsPerFillCircle = 9;
110*c8dee2aaSAndroid Build Coastguard Worker 
circle_type_to_vert_count(bool stroked)111*c8dee2aaSAndroid Build Coastguard Worker int circle_type_to_vert_count(bool stroked) {
112*c8dee2aaSAndroid Build Coastguard Worker     return stroked ? kVertsPerStrokeCircle : kVertsPerFillCircle;
113*c8dee2aaSAndroid Build Coastguard Worker }
114*c8dee2aaSAndroid Build Coastguard Worker 
circle_type_to_index_count(bool stroked)115*c8dee2aaSAndroid Build Coastguard Worker int circle_type_to_index_count(bool stroked) {
116*c8dee2aaSAndroid Build Coastguard Worker     return stroked ? kIndicesPerStrokeCircle : kIndicesPerFillCircle;
117*c8dee2aaSAndroid Build Coastguard Worker }
118*c8dee2aaSAndroid Build Coastguard Worker 
circle_type_to_indices(bool stroked)119*c8dee2aaSAndroid Build Coastguard Worker const uint16_t* circle_type_to_indices(bool stroked) {
120*c8dee2aaSAndroid Build Coastguard Worker     return stroked ? gStrokeCircleIndices : gFillCircleIndices;
121*c8dee2aaSAndroid Build Coastguard Worker }
122*c8dee2aaSAndroid Build Coastguard Worker 
123*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
124*c8dee2aaSAndroid Build Coastguard Worker // RoundRect Data
125*c8dee2aaSAndroid Build Coastguard Worker //
126*c8dee2aaSAndroid Build Coastguard Worker // The geometry for a shadow roundrect is similar to a 9-patch:
127*c8dee2aaSAndroid Build Coastguard Worker //    ____________
128*c8dee2aaSAndroid Build Coastguard Worker //   |_|________|_|
129*c8dee2aaSAndroid Build Coastguard Worker //   | |        | |
130*c8dee2aaSAndroid Build Coastguard Worker //   | |        | |
131*c8dee2aaSAndroid Build Coastguard Worker //   | |        | |
132*c8dee2aaSAndroid Build Coastguard Worker //   |_|________|_|
133*c8dee2aaSAndroid Build Coastguard Worker //   |_|________|_|
134*c8dee2aaSAndroid Build Coastguard Worker //
135*c8dee2aaSAndroid Build Coastguard Worker // However, each corner is rendered as a fan rather than a simple quad, as below. (The diagram
136*c8dee2aaSAndroid Build Coastguard Worker // shows the upper part of the upper left corner. The bottom triangle would similarly be split
137*c8dee2aaSAndroid Build Coastguard Worker // into two triangles.)
138*c8dee2aaSAndroid Build Coastguard Worker //    ________
139*c8dee2aaSAndroid Build Coastguard Worker //   |\  \   |
140*c8dee2aaSAndroid Build Coastguard Worker //   |  \ \  |
141*c8dee2aaSAndroid Build Coastguard Worker //   |    \\ |
142*c8dee2aaSAndroid Build Coastguard Worker //   |      \|
143*c8dee2aaSAndroid Build Coastguard Worker //   --------
144*c8dee2aaSAndroid Build Coastguard Worker //
145*c8dee2aaSAndroid Build Coastguard Worker // The center of the fan handles the curve of the corner. For roundrects where the stroke width
146*c8dee2aaSAndroid Build Coastguard Worker // is greater than the corner radius, the outer triangles blend from the curve to the straight
147*c8dee2aaSAndroid Build Coastguard Worker // sides. Otherwise these triangles will be degenerate.
148*c8dee2aaSAndroid Build Coastguard Worker //
149*c8dee2aaSAndroid Build Coastguard Worker // In the case where the stroke width is greater than the corner radius and the
150*c8dee2aaSAndroid Build Coastguard Worker // blur radius (overstroke), we add additional geometry to mark out the rectangle in the center.
151*c8dee2aaSAndroid Build Coastguard Worker // This rectangle extends the coverage values of the center edges of the 9-patch.
152*c8dee2aaSAndroid Build Coastguard Worker //    ____________
153*c8dee2aaSAndroid Build Coastguard Worker //   |_|________|_|
154*c8dee2aaSAndroid Build Coastguard Worker //   | |\ ____ /| |
155*c8dee2aaSAndroid Build Coastguard Worker //   | | |    | | |
156*c8dee2aaSAndroid Build Coastguard Worker //   | | |____| | |
157*c8dee2aaSAndroid Build Coastguard Worker //   |_|/______\|_|
158*c8dee2aaSAndroid Build Coastguard Worker //   |_|________|_|
159*c8dee2aaSAndroid Build Coastguard Worker //
160*c8dee2aaSAndroid Build Coastguard Worker // For filled rrects we reuse the stroke geometry but add an additional quad to the center.
161*c8dee2aaSAndroid Build Coastguard Worker 
162*c8dee2aaSAndroid Build Coastguard Worker static const uint16_t gRRectIndices[] = {
163*c8dee2aaSAndroid Build Coastguard Worker     // clang-format off
164*c8dee2aaSAndroid Build Coastguard Worker     // overstroke quads
165*c8dee2aaSAndroid Build Coastguard Worker     // we place this at the beginning so that we can skip these indices when rendering as filled
166*c8dee2aaSAndroid Build Coastguard Worker     0, 6, 25, 0, 25, 24,
167*c8dee2aaSAndroid Build Coastguard Worker     6, 18, 27, 6, 27, 25,
168*c8dee2aaSAndroid Build Coastguard Worker     18, 12, 26, 18, 26, 27,
169*c8dee2aaSAndroid Build Coastguard Worker     12, 0, 24, 12, 24, 26,
170*c8dee2aaSAndroid Build Coastguard Worker 
171*c8dee2aaSAndroid Build Coastguard Worker     // corners
172*c8dee2aaSAndroid Build Coastguard Worker     0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5,
173*c8dee2aaSAndroid Build Coastguard Worker     6, 11, 10, 6, 10, 9, 6, 9, 8, 6, 8, 7,
174*c8dee2aaSAndroid Build Coastguard Worker     12, 17, 16, 12, 16, 15, 12, 15, 14, 12, 14, 13,
175*c8dee2aaSAndroid Build Coastguard Worker     18, 19, 20, 18, 20, 21, 18, 21, 22, 18, 22, 23,
176*c8dee2aaSAndroid Build Coastguard Worker 
177*c8dee2aaSAndroid Build Coastguard Worker     // edges
178*c8dee2aaSAndroid Build Coastguard Worker     0, 5, 11, 0, 11, 6,
179*c8dee2aaSAndroid Build Coastguard Worker     6, 7, 19, 6, 19, 18,
180*c8dee2aaSAndroid Build Coastguard Worker     18, 23, 17, 18, 17, 12,
181*c8dee2aaSAndroid Build Coastguard Worker     12, 13, 1, 12, 1, 0,
182*c8dee2aaSAndroid Build Coastguard Worker 
183*c8dee2aaSAndroid Build Coastguard Worker     // fill quad
184*c8dee2aaSAndroid Build Coastguard Worker     // we place this at the end so that we can skip these indices when rendering as stroked
185*c8dee2aaSAndroid Build Coastguard Worker     0, 6, 18, 0, 18, 12,
186*c8dee2aaSAndroid Build Coastguard Worker     // clang-format on
187*c8dee2aaSAndroid Build Coastguard Worker };
188*c8dee2aaSAndroid Build Coastguard Worker 
189*c8dee2aaSAndroid Build Coastguard Worker // overstroke count
190*c8dee2aaSAndroid Build Coastguard Worker static const int kIndicesPerOverstrokeRRect = std::size(gRRectIndices) - 6;
191*c8dee2aaSAndroid Build Coastguard Worker // simple stroke count skips overstroke indices
192*c8dee2aaSAndroid Build Coastguard Worker static const int kIndicesPerStrokeRRect = kIndicesPerOverstrokeRRect - 6*4;
193*c8dee2aaSAndroid Build Coastguard Worker // fill count adds final quad to stroke count
194*c8dee2aaSAndroid Build Coastguard Worker static const int kIndicesPerFillRRect = kIndicesPerStrokeRRect + 6;
195*c8dee2aaSAndroid Build Coastguard Worker static const int kVertsPerStrokeRRect = 24;
196*c8dee2aaSAndroid Build Coastguard Worker static const int kVertsPerOverstrokeRRect = 28;
197*c8dee2aaSAndroid Build Coastguard Worker static const int kVertsPerFillRRect = 24;
198*c8dee2aaSAndroid Build Coastguard Worker 
199*c8dee2aaSAndroid Build Coastguard Worker enum RRectType {
200*c8dee2aaSAndroid Build Coastguard Worker     kFill_RRectType,
201*c8dee2aaSAndroid Build Coastguard Worker     kStroke_RRectType,
202*c8dee2aaSAndroid Build Coastguard Worker     kOverstroke_RRectType,
203*c8dee2aaSAndroid Build Coastguard Worker };
204*c8dee2aaSAndroid Build Coastguard Worker 
rrect_type_to_vert_count(RRectType type)205*c8dee2aaSAndroid Build Coastguard Worker int rrect_type_to_vert_count(RRectType type) {
206*c8dee2aaSAndroid Build Coastguard Worker     switch (type) {
207*c8dee2aaSAndroid Build Coastguard Worker         case kFill_RRectType:
208*c8dee2aaSAndroid Build Coastguard Worker             return kVertsPerFillRRect;
209*c8dee2aaSAndroid Build Coastguard Worker         case kStroke_RRectType:
210*c8dee2aaSAndroid Build Coastguard Worker             return kVertsPerStrokeRRect;
211*c8dee2aaSAndroid Build Coastguard Worker         case kOverstroke_RRectType:
212*c8dee2aaSAndroid Build Coastguard Worker             return kVertsPerOverstrokeRRect;
213*c8dee2aaSAndroid Build Coastguard Worker     }
214*c8dee2aaSAndroid Build Coastguard Worker     SK_ABORT("Invalid type");
215*c8dee2aaSAndroid Build Coastguard Worker }
216*c8dee2aaSAndroid Build Coastguard Worker 
rrect_type_to_index_count(RRectType type)217*c8dee2aaSAndroid Build Coastguard Worker int rrect_type_to_index_count(RRectType type) {
218*c8dee2aaSAndroid Build Coastguard Worker     switch (type) {
219*c8dee2aaSAndroid Build Coastguard Worker         case kFill_RRectType:
220*c8dee2aaSAndroid Build Coastguard Worker             return kIndicesPerFillRRect;
221*c8dee2aaSAndroid Build Coastguard Worker         case kStroke_RRectType:
222*c8dee2aaSAndroid Build Coastguard Worker             return kIndicesPerStrokeRRect;
223*c8dee2aaSAndroid Build Coastguard Worker         case kOverstroke_RRectType:
224*c8dee2aaSAndroid Build Coastguard Worker             return kIndicesPerOverstrokeRRect;
225*c8dee2aaSAndroid Build Coastguard Worker     }
226*c8dee2aaSAndroid Build Coastguard Worker     SK_ABORT("Invalid type");
227*c8dee2aaSAndroid Build Coastguard Worker }
228*c8dee2aaSAndroid Build Coastguard Worker 
rrect_type_to_indices(RRectType type)229*c8dee2aaSAndroid Build Coastguard Worker const uint16_t* rrect_type_to_indices(RRectType type) {
230*c8dee2aaSAndroid Build Coastguard Worker     switch (type) {
231*c8dee2aaSAndroid Build Coastguard Worker         case kFill_RRectType:
232*c8dee2aaSAndroid Build Coastguard Worker         case kStroke_RRectType:
233*c8dee2aaSAndroid Build Coastguard Worker             return gRRectIndices + 6*4;
234*c8dee2aaSAndroid Build Coastguard Worker         case kOverstroke_RRectType:
235*c8dee2aaSAndroid Build Coastguard Worker             return gRRectIndices;
236*c8dee2aaSAndroid Build Coastguard Worker     }
237*c8dee2aaSAndroid Build Coastguard Worker     SK_ABORT("Invalid type");
238*c8dee2aaSAndroid Build Coastguard Worker }
239*c8dee2aaSAndroid Build Coastguard Worker 
240*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
241*c8dee2aaSAndroid Build Coastguard Worker 
242*c8dee2aaSAndroid Build Coastguard Worker class ShadowCircularRRectOp final : public GrMeshDrawOp {
243*c8dee2aaSAndroid Build Coastguard Worker public:
244*c8dee2aaSAndroid Build Coastguard Worker     DEFINE_OP_CLASS_ID
245*c8dee2aaSAndroid Build Coastguard Worker 
246*c8dee2aaSAndroid Build Coastguard Worker     // An insetWidth > 1/2 rect width or height indicates a simple fill.
ShadowCircularRRectOp(GrColor color,const SkRect & devRect,float devRadius,bool isCircle,float blurRadius,float insetWidth,GrSurfaceProxyView falloffView)247*c8dee2aaSAndroid Build Coastguard Worker     ShadowCircularRRectOp(GrColor color, const SkRect& devRect,
248*c8dee2aaSAndroid Build Coastguard Worker                           float devRadius, bool isCircle, float blurRadius, float insetWidth,
249*c8dee2aaSAndroid Build Coastguard Worker                           GrSurfaceProxyView falloffView)
250*c8dee2aaSAndroid Build Coastguard Worker             : INHERITED(ClassID())
251*c8dee2aaSAndroid Build Coastguard Worker             , fFalloffView(std::move(falloffView)) {
252*c8dee2aaSAndroid Build Coastguard Worker         SkRect bounds = devRect;
253*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(insetWidth > 0);
254*c8dee2aaSAndroid Build Coastguard Worker         SkScalar innerRadius = 0.0f;
255*c8dee2aaSAndroid Build Coastguard Worker         SkScalar outerRadius = devRadius;
256*c8dee2aaSAndroid Build Coastguard Worker         SkScalar umbraInset;
257*c8dee2aaSAndroid Build Coastguard Worker 
258*c8dee2aaSAndroid Build Coastguard Worker         RRectType type = kFill_RRectType;
259*c8dee2aaSAndroid Build Coastguard Worker         if (isCircle) {
260*c8dee2aaSAndroid Build Coastguard Worker             umbraInset = 0;
261*c8dee2aaSAndroid Build Coastguard Worker         } else {
262*c8dee2aaSAndroid Build Coastguard Worker             umbraInset = std::max(outerRadius, blurRadius);
263*c8dee2aaSAndroid Build Coastguard Worker         }
264*c8dee2aaSAndroid Build Coastguard Worker 
265*c8dee2aaSAndroid Build Coastguard Worker         // If stroke is greater than width or height, this is still a fill,
266*c8dee2aaSAndroid Build Coastguard Worker         // otherwise we compute stroke params.
267*c8dee2aaSAndroid Build Coastguard Worker         if (isCircle) {
268*c8dee2aaSAndroid Build Coastguard Worker             innerRadius = devRadius - insetWidth;
269*c8dee2aaSAndroid Build Coastguard Worker             type = innerRadius > 0 ? kStroke_RRectType : kFill_RRectType;
270*c8dee2aaSAndroid Build Coastguard Worker         } else {
271*c8dee2aaSAndroid Build Coastguard Worker             if (insetWidth <= 0.5f*std::min(devRect.width(), devRect.height())) {
272*c8dee2aaSAndroid Build Coastguard Worker                 // We don't worry about a real inner radius, we just need to know if we
273*c8dee2aaSAndroid Build Coastguard Worker                 // need to create overstroke vertices.
274*c8dee2aaSAndroid Build Coastguard Worker                 innerRadius = std::max(insetWidth - umbraInset, 0.0f);
275*c8dee2aaSAndroid Build Coastguard Worker                 type = innerRadius > 0 ? kOverstroke_RRectType : kStroke_RRectType;
276*c8dee2aaSAndroid Build Coastguard Worker             }
277*c8dee2aaSAndroid Build Coastguard Worker         }
278*c8dee2aaSAndroid Build Coastguard Worker 
279*c8dee2aaSAndroid Build Coastguard Worker         this->setBounds(bounds, HasAABloat::kNo, IsHairline::kNo);
280*c8dee2aaSAndroid Build Coastguard Worker 
281*c8dee2aaSAndroid Build Coastguard Worker         fGeoData.emplace_back(Geometry{color, outerRadius, umbraInset, innerRadius,
282*c8dee2aaSAndroid Build Coastguard Worker                                        blurRadius, bounds, type, isCircle});
283*c8dee2aaSAndroid Build Coastguard Worker         if (isCircle) {
284*c8dee2aaSAndroid Build Coastguard Worker             fVertCount = circle_type_to_vert_count(kStroke_RRectType == type);
285*c8dee2aaSAndroid Build Coastguard Worker             fIndexCount = circle_type_to_index_count(kStroke_RRectType == type);
286*c8dee2aaSAndroid Build Coastguard Worker         } else {
287*c8dee2aaSAndroid Build Coastguard Worker             fVertCount = rrect_type_to_vert_count(type);
288*c8dee2aaSAndroid Build Coastguard Worker             fIndexCount = rrect_type_to_index_count(type);
289*c8dee2aaSAndroid Build Coastguard Worker         }
290*c8dee2aaSAndroid Build Coastguard Worker     }
291*c8dee2aaSAndroid Build Coastguard Worker 
name() const292*c8dee2aaSAndroid Build Coastguard Worker     const char* name() const override { return "ShadowCircularRRectOp"; }
293*c8dee2aaSAndroid Build Coastguard Worker 
fixedFunctionFlags() const294*c8dee2aaSAndroid Build Coastguard Worker     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
295*c8dee2aaSAndroid Build Coastguard Worker 
finalize(const GrCaps &,const GrAppliedClip *,GrClampType)296*c8dee2aaSAndroid Build Coastguard Worker     GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override {
297*c8dee2aaSAndroid Build Coastguard Worker         return GrProcessorSet::EmptySetAnalysis();
298*c8dee2aaSAndroid Build Coastguard Worker     }
299*c8dee2aaSAndroid Build Coastguard Worker 
300*c8dee2aaSAndroid Build Coastguard Worker private:
301*c8dee2aaSAndroid Build Coastguard Worker     struct Geometry {
302*c8dee2aaSAndroid Build Coastguard Worker         GrColor   fColor;
303*c8dee2aaSAndroid Build Coastguard Worker         SkScalar  fOuterRadius;
304*c8dee2aaSAndroid Build Coastguard Worker         SkScalar  fUmbraInset;
305*c8dee2aaSAndroid Build Coastguard Worker         SkScalar  fInnerRadius;
306*c8dee2aaSAndroid Build Coastguard Worker         SkScalar  fBlurRadius;
307*c8dee2aaSAndroid Build Coastguard Worker         SkRect    fDevBounds;
308*c8dee2aaSAndroid Build Coastguard Worker         RRectType fType;
309*c8dee2aaSAndroid Build Coastguard Worker         bool      fIsCircle;
310*c8dee2aaSAndroid Build Coastguard Worker     };
311*c8dee2aaSAndroid Build Coastguard Worker 
312*c8dee2aaSAndroid Build Coastguard Worker     struct CircleVertex {
313*c8dee2aaSAndroid Build Coastguard Worker         SkPoint fPos;
314*c8dee2aaSAndroid Build Coastguard Worker         GrColor fColor;
315*c8dee2aaSAndroid Build Coastguard Worker         SkPoint fOffset;
316*c8dee2aaSAndroid Build Coastguard Worker         SkScalar fDistanceCorrection;
317*c8dee2aaSAndroid Build Coastguard Worker     };
318*c8dee2aaSAndroid Build Coastguard Worker 
fillInCircleVerts(const Geometry & args,bool isStroked,CircleVertex ** verts) const319*c8dee2aaSAndroid Build Coastguard Worker     void fillInCircleVerts(const Geometry& args, bool isStroked, CircleVertex** verts) const {
320*c8dee2aaSAndroid Build Coastguard Worker 
321*c8dee2aaSAndroid Build Coastguard Worker         GrColor color = args.fColor;
322*c8dee2aaSAndroid Build Coastguard Worker         SkScalar outerRadius = args.fOuterRadius;
323*c8dee2aaSAndroid Build Coastguard Worker         SkScalar innerRadius = args.fInnerRadius;
324*c8dee2aaSAndroid Build Coastguard Worker         SkScalar blurRadius = args.fBlurRadius;
325*c8dee2aaSAndroid Build Coastguard Worker         SkScalar distanceCorrection = outerRadius / blurRadius;
326*c8dee2aaSAndroid Build Coastguard Worker 
327*c8dee2aaSAndroid Build Coastguard Worker         const SkRect& bounds = args.fDevBounds;
328*c8dee2aaSAndroid Build Coastguard Worker 
329*c8dee2aaSAndroid Build Coastguard Worker         // The inner radius in the vertex data must be specified in normalized space.
330*c8dee2aaSAndroid Build Coastguard Worker         innerRadius = innerRadius / outerRadius;
331*c8dee2aaSAndroid Build Coastguard Worker 
332*c8dee2aaSAndroid Build Coastguard Worker         SkPoint center = SkPoint::Make(bounds.centerX(), bounds.centerY());
333*c8dee2aaSAndroid Build Coastguard Worker         SkScalar halfWidth = 0.5f * bounds.width();
334*c8dee2aaSAndroid Build Coastguard Worker         SkScalar octOffset = 0.41421356237f;  // sqrt(2) - 1
335*c8dee2aaSAndroid Build Coastguard Worker 
336*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fPos = center + SkPoint::Make(-octOffset * halfWidth, -halfWidth);
337*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fColor = color;
338*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fOffset = SkPoint::Make(-octOffset, -1);
339*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fDistanceCorrection = distanceCorrection;
340*c8dee2aaSAndroid Build Coastguard Worker         (*verts)++;
341*c8dee2aaSAndroid Build Coastguard Worker 
342*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fPos = center + SkPoint::Make(octOffset * halfWidth, -halfWidth);
343*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fColor = color;
344*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fOffset = SkPoint::Make(octOffset, -1);
345*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fDistanceCorrection = distanceCorrection;
346*c8dee2aaSAndroid Build Coastguard Worker         (*verts)++;
347*c8dee2aaSAndroid Build Coastguard Worker 
348*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fPos = center + SkPoint::Make(halfWidth, -octOffset * halfWidth);
349*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fColor = color;
350*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fOffset = SkPoint::Make(1, -octOffset);
351*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fDistanceCorrection = distanceCorrection;
352*c8dee2aaSAndroid Build Coastguard Worker         (*verts)++;
353*c8dee2aaSAndroid Build Coastguard Worker 
354*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fPos = center + SkPoint::Make(halfWidth, octOffset * halfWidth);
355*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fColor = color;
356*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fOffset = SkPoint::Make(1, octOffset);
357*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fDistanceCorrection = distanceCorrection;
358*c8dee2aaSAndroid Build Coastguard Worker         (*verts)++;
359*c8dee2aaSAndroid Build Coastguard Worker 
360*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fPos = center + SkPoint::Make(octOffset * halfWidth, halfWidth);
361*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fColor = color;
362*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fOffset = SkPoint::Make(octOffset, 1);
363*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fDistanceCorrection = distanceCorrection;
364*c8dee2aaSAndroid Build Coastguard Worker         (*verts)++;
365*c8dee2aaSAndroid Build Coastguard Worker 
366*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fPos = center + SkPoint::Make(-octOffset * halfWidth, halfWidth);
367*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fColor = color;
368*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fOffset = SkPoint::Make(-octOffset, 1);
369*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fDistanceCorrection = distanceCorrection;
370*c8dee2aaSAndroid Build Coastguard Worker         (*verts)++;
371*c8dee2aaSAndroid Build Coastguard Worker 
372*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fPos = center + SkPoint::Make(-halfWidth, octOffset * halfWidth);
373*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fColor = color;
374*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fOffset = SkPoint::Make(-1, octOffset);
375*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fDistanceCorrection = distanceCorrection;
376*c8dee2aaSAndroid Build Coastguard Worker         (*verts)++;
377*c8dee2aaSAndroid Build Coastguard Worker 
378*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fPos = center + SkPoint::Make(-halfWidth, -octOffset * halfWidth);
379*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fColor = color;
380*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fOffset = SkPoint::Make(-1, -octOffset);
381*c8dee2aaSAndroid Build Coastguard Worker         (*verts)->fDistanceCorrection = distanceCorrection;
382*c8dee2aaSAndroid Build Coastguard Worker         (*verts)++;
383*c8dee2aaSAndroid Build Coastguard Worker 
384*c8dee2aaSAndroid Build Coastguard Worker         if (isStroked) {
385*c8dee2aaSAndroid Build Coastguard Worker             // compute the inner ring
386*c8dee2aaSAndroid Build Coastguard Worker 
387*c8dee2aaSAndroid Build Coastguard Worker             // cosine and sine of pi/8
388*c8dee2aaSAndroid Build Coastguard Worker             SkScalar c = 0.923579533f;
389*c8dee2aaSAndroid Build Coastguard Worker             SkScalar s = 0.382683432f;
390*c8dee2aaSAndroid Build Coastguard Worker             SkScalar r = args.fInnerRadius;
391*c8dee2aaSAndroid Build Coastguard Worker 
392*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = center + SkPoint::Make(-s * r, -c * r);
393*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
394*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = SkPoint::Make(-s * innerRadius, -c * innerRadius);
395*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
396*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
397*c8dee2aaSAndroid Build Coastguard Worker 
398*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = center + SkPoint::Make(s * r, -c * r);
399*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
400*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = SkPoint::Make(s * innerRadius, -c * innerRadius);
401*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
402*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
403*c8dee2aaSAndroid Build Coastguard Worker 
404*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = center + SkPoint::Make(c * r, -s * r);
405*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
406*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = SkPoint::Make(c * innerRadius, -s * innerRadius);
407*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
408*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
409*c8dee2aaSAndroid Build Coastguard Worker 
410*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = center + SkPoint::Make(c * r, s * r);
411*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
412*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = SkPoint::Make(c * innerRadius, s * innerRadius);
413*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
414*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
415*c8dee2aaSAndroid Build Coastguard Worker 
416*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = center + SkPoint::Make(s * r, c * r);
417*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
418*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = SkPoint::Make(s * innerRadius, c * innerRadius);
419*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
420*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
421*c8dee2aaSAndroid Build Coastguard Worker 
422*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = center + SkPoint::Make(-s * r, c * r);
423*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
424*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = SkPoint::Make(-s * innerRadius, c * innerRadius);
425*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
426*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
427*c8dee2aaSAndroid Build Coastguard Worker 
428*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = center + SkPoint::Make(-c * r, s * r);
429*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
430*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = SkPoint::Make(-c * innerRadius, s * innerRadius);
431*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
432*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
433*c8dee2aaSAndroid Build Coastguard Worker 
434*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = center + SkPoint::Make(-c * r, -s * r);
435*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
436*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = SkPoint::Make(-c * innerRadius, -s * innerRadius);
437*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
438*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
439*c8dee2aaSAndroid Build Coastguard Worker         } else {
440*c8dee2aaSAndroid Build Coastguard Worker             // filled
441*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = center;
442*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
443*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = SkPoint::Make(0, 0);
444*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
445*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
446*c8dee2aaSAndroid Build Coastguard Worker         }
447*c8dee2aaSAndroid Build Coastguard Worker     }
448*c8dee2aaSAndroid Build Coastguard Worker 
fillInRRectVerts(const Geometry & args,CircleVertex ** verts) const449*c8dee2aaSAndroid Build Coastguard Worker     void fillInRRectVerts(const Geometry& args, CircleVertex** verts) const {
450*c8dee2aaSAndroid Build Coastguard Worker         GrColor color = args.fColor;
451*c8dee2aaSAndroid Build Coastguard Worker         SkScalar outerRadius = args.fOuterRadius;
452*c8dee2aaSAndroid Build Coastguard Worker 
453*c8dee2aaSAndroid Build Coastguard Worker         const SkRect& bounds = args.fDevBounds;
454*c8dee2aaSAndroid Build Coastguard Worker 
455*c8dee2aaSAndroid Build Coastguard Worker         SkScalar umbraInset = args.fUmbraInset;
456*c8dee2aaSAndroid Build Coastguard Worker         SkScalar minDim = 0.5f*std::min(bounds.width(), bounds.height());
457*c8dee2aaSAndroid Build Coastguard Worker         if (umbraInset > minDim) {
458*c8dee2aaSAndroid Build Coastguard Worker             umbraInset = minDim;
459*c8dee2aaSAndroid Build Coastguard Worker         }
460*c8dee2aaSAndroid Build Coastguard Worker 
461*c8dee2aaSAndroid Build Coastguard Worker         SkScalar xInner[4] = { bounds.fLeft + umbraInset, bounds.fRight - umbraInset,
462*c8dee2aaSAndroid Build Coastguard Worker             bounds.fLeft + umbraInset, bounds.fRight - umbraInset };
463*c8dee2aaSAndroid Build Coastguard Worker         SkScalar xMid[4] = { bounds.fLeft + outerRadius, bounds.fRight - outerRadius,
464*c8dee2aaSAndroid Build Coastguard Worker             bounds.fLeft + outerRadius, bounds.fRight - outerRadius };
465*c8dee2aaSAndroid Build Coastguard Worker         SkScalar xOuter[4] = { bounds.fLeft, bounds.fRight,
466*c8dee2aaSAndroid Build Coastguard Worker             bounds.fLeft, bounds.fRight };
467*c8dee2aaSAndroid Build Coastguard Worker         SkScalar yInner[4] = { bounds.fTop + umbraInset, bounds.fTop + umbraInset,
468*c8dee2aaSAndroid Build Coastguard Worker             bounds.fBottom - umbraInset, bounds.fBottom - umbraInset };
469*c8dee2aaSAndroid Build Coastguard Worker         SkScalar yMid[4] = { bounds.fTop + outerRadius, bounds.fTop + outerRadius,
470*c8dee2aaSAndroid Build Coastguard Worker             bounds.fBottom - outerRadius, bounds.fBottom - outerRadius };
471*c8dee2aaSAndroid Build Coastguard Worker         SkScalar yOuter[4] = { bounds.fTop, bounds.fTop,
472*c8dee2aaSAndroid Build Coastguard Worker             bounds.fBottom, bounds.fBottom };
473*c8dee2aaSAndroid Build Coastguard Worker 
474*c8dee2aaSAndroid Build Coastguard Worker         SkScalar blurRadius = args.fBlurRadius;
475*c8dee2aaSAndroid Build Coastguard Worker 
476*c8dee2aaSAndroid Build Coastguard Worker         // In the case where we have to inset more for the umbra, our two triangles in the
477*c8dee2aaSAndroid Build Coastguard Worker         // corner get skewed to a diamond rather than a square. To correct for that,
478*c8dee2aaSAndroid Build Coastguard Worker         // we also skew the vectors we send to the shader that help define the circle.
479*c8dee2aaSAndroid Build Coastguard Worker         // By doing so, we end up with a quarter circle in the corner rather than the
480*c8dee2aaSAndroid Build Coastguard Worker         // elliptical curve.
481*c8dee2aaSAndroid Build Coastguard Worker 
482*c8dee2aaSAndroid Build Coastguard Worker         // This is a bit magical, but it gives us the correct results at extrema:
483*c8dee2aaSAndroid Build Coastguard Worker         //   a) umbraInset == outerRadius produces an orthogonal vector
484*c8dee2aaSAndroid Build Coastguard Worker         //   b) outerRadius == 0 produces a diagonal vector
485*c8dee2aaSAndroid Build Coastguard Worker         // And visually the corner looks correct.
486*c8dee2aaSAndroid Build Coastguard Worker         SkVector outerVec = SkVector::Make(outerRadius - umbraInset, -outerRadius - umbraInset);
487*c8dee2aaSAndroid Build Coastguard Worker         outerVec.normalize();
488*c8dee2aaSAndroid Build Coastguard Worker         // We want the circle edge to fall fractionally along the diagonal at
489*c8dee2aaSAndroid Build Coastguard Worker         //      (sqrt(2)*(umbraInset - outerRadius) + outerRadius)/sqrt(2)*umbraInset
490*c8dee2aaSAndroid Build Coastguard Worker         //
491*c8dee2aaSAndroid Build Coastguard Worker         // Setting the components of the diagonal offset to the following value will give us that.
492*c8dee2aaSAndroid Build Coastguard Worker         SkScalar diagVal = umbraInset / (SK_ScalarSqrt2*(outerRadius - umbraInset) - outerRadius);
493*c8dee2aaSAndroid Build Coastguard Worker         SkVector diagVec = SkVector::Make(diagVal, diagVal);
494*c8dee2aaSAndroid Build Coastguard Worker         SkScalar distanceCorrection = umbraInset / blurRadius;
495*c8dee2aaSAndroid Build Coastguard Worker 
496*c8dee2aaSAndroid Build Coastguard Worker         // build corner by corner
497*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < 4; ++i) {
498*c8dee2aaSAndroid Build Coastguard Worker             // inner point
499*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = SkPoint::Make(xInner[i], yInner[i]);
500*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
501*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = SkVector::Make(0, 0);
502*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
503*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
504*c8dee2aaSAndroid Build Coastguard Worker 
505*c8dee2aaSAndroid Build Coastguard Worker             // outer points
506*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = SkPoint::Make(xOuter[i], yInner[i]);
507*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
508*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = SkVector::Make(0, -1);
509*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
510*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
511*c8dee2aaSAndroid Build Coastguard Worker 
512*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = SkPoint::Make(xOuter[i], yMid[i]);
513*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
514*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = outerVec;
515*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
516*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
517*c8dee2aaSAndroid Build Coastguard Worker 
518*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = SkPoint::Make(xOuter[i], yOuter[i]);
519*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
520*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = diagVec;
521*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
522*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
523*c8dee2aaSAndroid Build Coastguard Worker 
524*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = SkPoint::Make(xMid[i], yOuter[i]);
525*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
526*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = outerVec;
527*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
528*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
529*c8dee2aaSAndroid Build Coastguard Worker 
530*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = SkPoint::Make(xInner[i], yOuter[i]);
531*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
532*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = SkVector::Make(0, -1);
533*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
534*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
535*c8dee2aaSAndroid Build Coastguard Worker         }
536*c8dee2aaSAndroid Build Coastguard Worker 
537*c8dee2aaSAndroid Build Coastguard Worker         // Add the additional vertices for overstroked rrects.
538*c8dee2aaSAndroid Build Coastguard Worker         // Effectively this is an additional stroked rrect, with its
539*c8dee2aaSAndroid Build Coastguard Worker         // parameters equal to those in the center of the 9-patch. This will
540*c8dee2aaSAndroid Build Coastguard Worker         // give constant values across this inner ring.
541*c8dee2aaSAndroid Build Coastguard Worker         if (kOverstroke_RRectType == args.fType) {
542*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(args.fInnerRadius > 0.0f);
543*c8dee2aaSAndroid Build Coastguard Worker 
544*c8dee2aaSAndroid Build Coastguard Worker             SkScalar inset =  umbraInset + args.fInnerRadius;
545*c8dee2aaSAndroid Build Coastguard Worker 
546*c8dee2aaSAndroid Build Coastguard Worker             // TL
547*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = SkPoint::Make(bounds.fLeft + inset, bounds.fTop + inset);
548*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
549*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = SkPoint::Make(0, 0);
550*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
551*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
552*c8dee2aaSAndroid Build Coastguard Worker 
553*c8dee2aaSAndroid Build Coastguard Worker             // TR
554*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = SkPoint::Make(bounds.fRight - inset, bounds.fTop + inset);
555*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
556*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = SkPoint::Make(0, 0);
557*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
558*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
559*c8dee2aaSAndroid Build Coastguard Worker 
560*c8dee2aaSAndroid Build Coastguard Worker             // BL
561*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = SkPoint::Make(bounds.fLeft + inset, bounds.fBottom - inset);
562*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
563*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = SkPoint::Make(0, 0);
564*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
565*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
566*c8dee2aaSAndroid Build Coastguard Worker 
567*c8dee2aaSAndroid Build Coastguard Worker             // BR
568*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fPos = SkPoint::Make(bounds.fRight - inset, bounds.fBottom - inset);
569*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fColor = color;
570*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fOffset = SkPoint::Make(0, 0);
571*c8dee2aaSAndroid Build Coastguard Worker             (*verts)->fDistanceCorrection = distanceCorrection;
572*c8dee2aaSAndroid Build Coastguard Worker             (*verts)++;
573*c8dee2aaSAndroid Build Coastguard Worker         }
574*c8dee2aaSAndroid Build Coastguard Worker 
575*c8dee2aaSAndroid Build Coastguard Worker     }
576*c8dee2aaSAndroid Build Coastguard Worker 
programInfo()577*c8dee2aaSAndroid Build Coastguard Worker     GrProgramInfo* programInfo() override { return fProgramInfo; }
578*c8dee2aaSAndroid Build Coastguard Worker 
onCreateProgramInfo(const GrCaps * caps,SkArenaAlloc * arena,const GrSurfaceProxyView & writeView,bool usesMSAASurface,GrAppliedClip && appliedClip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)579*c8dee2aaSAndroid Build Coastguard Worker     void onCreateProgramInfo(const GrCaps* caps,
580*c8dee2aaSAndroid Build Coastguard Worker                              SkArenaAlloc* arena,
581*c8dee2aaSAndroid Build Coastguard Worker                              const GrSurfaceProxyView& writeView,
582*c8dee2aaSAndroid Build Coastguard Worker                              bool usesMSAASurface,
583*c8dee2aaSAndroid Build Coastguard Worker                              GrAppliedClip&& appliedClip,
584*c8dee2aaSAndroid Build Coastguard Worker                              const GrDstProxyView& dstProxyView,
585*c8dee2aaSAndroid Build Coastguard Worker                              GrXferBarrierFlags renderPassXferBarriers,
586*c8dee2aaSAndroid Build Coastguard Worker                              GrLoadOp colorLoadOp) override {
587*c8dee2aaSAndroid Build Coastguard Worker         GrGeometryProcessor* gp = GrRRectShadowGeoProc::Make(arena, fFalloffView);
588*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(sizeof(CircleVertex) == gp->vertexStride());
589*c8dee2aaSAndroid Build Coastguard Worker 
590*c8dee2aaSAndroid Build Coastguard Worker         fProgramInfo = GrSimpleMeshDrawOpHelper::CreateProgramInfo(caps, arena, writeView,
591*c8dee2aaSAndroid Build Coastguard Worker                                                                    usesMSAASurface,
592*c8dee2aaSAndroid Build Coastguard Worker                                                                    std::move(appliedClip),
593*c8dee2aaSAndroid Build Coastguard Worker                                                                    dstProxyView, gp,
594*c8dee2aaSAndroid Build Coastguard Worker                                                                    GrProcessorSet::MakeEmptySet(),
595*c8dee2aaSAndroid Build Coastguard Worker                                                                    GrPrimitiveType::kTriangles,
596*c8dee2aaSAndroid Build Coastguard Worker                                                                    renderPassXferBarriers,
597*c8dee2aaSAndroid Build Coastguard Worker                                                                    colorLoadOp,
598*c8dee2aaSAndroid Build Coastguard Worker                                                                    GrPipeline::InputFlags::kNone,
599*c8dee2aaSAndroid Build Coastguard Worker                                                                    &GrUserStencilSettings::kUnused);
600*c8dee2aaSAndroid Build Coastguard Worker     }
601*c8dee2aaSAndroid Build Coastguard Worker 
onPrepareDraws(GrMeshDrawTarget * target)602*c8dee2aaSAndroid Build Coastguard Worker     void onPrepareDraws(GrMeshDrawTarget* target) override {
603*c8dee2aaSAndroid Build Coastguard Worker         int instanceCount = fGeoData.size();
604*c8dee2aaSAndroid Build Coastguard Worker 
605*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<const GrBuffer> vertexBuffer;
606*c8dee2aaSAndroid Build Coastguard Worker         int firstVertex;
607*c8dee2aaSAndroid Build Coastguard Worker         CircleVertex* verts = (CircleVertex*)target->makeVertexSpace(
608*c8dee2aaSAndroid Build Coastguard Worker                 sizeof(CircleVertex), fVertCount, &vertexBuffer, &firstVertex);
609*c8dee2aaSAndroid Build Coastguard Worker         if (!verts) {
610*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf("Could not allocate vertices\n");
611*c8dee2aaSAndroid Build Coastguard Worker             return;
612*c8dee2aaSAndroid Build Coastguard Worker         }
613*c8dee2aaSAndroid Build Coastguard Worker 
614*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<const GrBuffer> indexBuffer;
615*c8dee2aaSAndroid Build Coastguard Worker         int firstIndex = 0;
616*c8dee2aaSAndroid Build Coastguard Worker         uint16_t* indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
617*c8dee2aaSAndroid Build Coastguard Worker         if (!indices) {
618*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf("Could not allocate indices\n");
619*c8dee2aaSAndroid Build Coastguard Worker             return;
620*c8dee2aaSAndroid Build Coastguard Worker         }
621*c8dee2aaSAndroid Build Coastguard Worker 
622*c8dee2aaSAndroid Build Coastguard Worker         int currStartVertex = 0;
623*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < instanceCount; i++) {
624*c8dee2aaSAndroid Build Coastguard Worker             const Geometry& args = fGeoData[i];
625*c8dee2aaSAndroid Build Coastguard Worker 
626*c8dee2aaSAndroid Build Coastguard Worker             if (args.fIsCircle) {
627*c8dee2aaSAndroid Build Coastguard Worker                 bool isStroked = SkToBool(kStroke_RRectType == args.fType);
628*c8dee2aaSAndroid Build Coastguard Worker                 this->fillInCircleVerts(args, isStroked, &verts);
629*c8dee2aaSAndroid Build Coastguard Worker 
630*c8dee2aaSAndroid Build Coastguard Worker                 const uint16_t* primIndices = circle_type_to_indices(isStroked);
631*c8dee2aaSAndroid Build Coastguard Worker                 const int primIndexCount = circle_type_to_index_count(isStroked);
632*c8dee2aaSAndroid Build Coastguard Worker                 for (int j = 0; j < primIndexCount; ++j) {
633*c8dee2aaSAndroid Build Coastguard Worker                     *indices++ = primIndices[j] + currStartVertex;
634*c8dee2aaSAndroid Build Coastguard Worker                 }
635*c8dee2aaSAndroid Build Coastguard Worker 
636*c8dee2aaSAndroid Build Coastguard Worker                 currStartVertex += circle_type_to_vert_count(isStroked);
637*c8dee2aaSAndroid Build Coastguard Worker 
638*c8dee2aaSAndroid Build Coastguard Worker             } else {
639*c8dee2aaSAndroid Build Coastguard Worker                 this->fillInRRectVerts(args, &verts);
640*c8dee2aaSAndroid Build Coastguard Worker 
641*c8dee2aaSAndroid Build Coastguard Worker                 const uint16_t* primIndices = rrect_type_to_indices(args.fType);
642*c8dee2aaSAndroid Build Coastguard Worker                 const int primIndexCount = rrect_type_to_index_count(args.fType);
643*c8dee2aaSAndroid Build Coastguard Worker                 for (int j = 0; j < primIndexCount; ++j) {
644*c8dee2aaSAndroid Build Coastguard Worker                     *indices++ = primIndices[j] + currStartVertex;
645*c8dee2aaSAndroid Build Coastguard Worker                 }
646*c8dee2aaSAndroid Build Coastguard Worker 
647*c8dee2aaSAndroid Build Coastguard Worker                 currStartVertex += rrect_type_to_vert_count(args.fType);
648*c8dee2aaSAndroid Build Coastguard Worker             }
649*c8dee2aaSAndroid Build Coastguard Worker         }
650*c8dee2aaSAndroid Build Coastguard Worker 
651*c8dee2aaSAndroid Build Coastguard Worker         fMesh = target->allocMesh();
652*c8dee2aaSAndroid Build Coastguard Worker         fMesh->setIndexed(std::move(indexBuffer), fIndexCount, firstIndex, 0,
653*c8dee2aaSAndroid Build Coastguard Worker                           SkTo<uint16_t>(fVertCount - 1),
654*c8dee2aaSAndroid Build Coastguard Worker                           GrPrimitiveRestart::kNo, std::move(vertexBuffer), firstVertex);
655*c8dee2aaSAndroid Build Coastguard Worker     }
656*c8dee2aaSAndroid Build Coastguard Worker 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)657*c8dee2aaSAndroid Build Coastguard Worker     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
658*c8dee2aaSAndroid Build Coastguard Worker         if (!fProgramInfo) {
659*c8dee2aaSAndroid Build Coastguard Worker             this->createProgramInfo(flushState);
660*c8dee2aaSAndroid Build Coastguard Worker         }
661*c8dee2aaSAndroid Build Coastguard Worker 
662*c8dee2aaSAndroid Build Coastguard Worker         if (!fProgramInfo || !fMesh) {
663*c8dee2aaSAndroid Build Coastguard Worker             return;
664*c8dee2aaSAndroid Build Coastguard Worker         }
665*c8dee2aaSAndroid Build Coastguard Worker 
666*c8dee2aaSAndroid Build Coastguard Worker         flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
667*c8dee2aaSAndroid Build Coastguard Worker         flushState->bindTextures(fProgramInfo->geomProc(), *fFalloffView.proxy(),
668*c8dee2aaSAndroid Build Coastguard Worker                                  fProgramInfo->pipeline());
669*c8dee2aaSAndroid Build Coastguard Worker         flushState->drawMesh(*fMesh);
670*c8dee2aaSAndroid Build Coastguard Worker     }
671*c8dee2aaSAndroid Build Coastguard Worker 
onCombineIfPossible(GrOp * t,SkArenaAlloc *,const GrCaps & caps)672*c8dee2aaSAndroid Build Coastguard Worker     CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override {
673*c8dee2aaSAndroid Build Coastguard Worker         ShadowCircularRRectOp* that = t->cast<ShadowCircularRRectOp>();
674*c8dee2aaSAndroid Build Coastguard Worker 
675*c8dee2aaSAndroid Build Coastguard Worker         // Cannot combine if the net number of indices would overflow int32, or if the net number
676*c8dee2aaSAndroid Build Coastguard Worker         // of vertices would overflow uint16 (since the index values are 16-bit that point into
677*c8dee2aaSAndroid Build Coastguard Worker         // the vertex buffer).
678*c8dee2aaSAndroid Build Coastguard Worker         if ((fIndexCount > INT32_MAX - that->fIndexCount) ||
679*c8dee2aaSAndroid Build Coastguard Worker             (fVertCount > SkToInt(UINT16_MAX) - that->fVertCount)) {
680*c8dee2aaSAndroid Build Coastguard Worker             return CombineResult::kCannotCombine;
681*c8dee2aaSAndroid Build Coastguard Worker         }
682*c8dee2aaSAndroid Build Coastguard Worker 
683*c8dee2aaSAndroid Build Coastguard Worker         fGeoData.push_back_n(that->fGeoData.size(), that->fGeoData.begin());
684*c8dee2aaSAndroid Build Coastguard Worker         fVertCount += that->fVertCount;
685*c8dee2aaSAndroid Build Coastguard Worker         fIndexCount += that->fIndexCount;
686*c8dee2aaSAndroid Build Coastguard Worker         return CombineResult::kMerged;
687*c8dee2aaSAndroid Build Coastguard Worker     }
688*c8dee2aaSAndroid Build Coastguard Worker 
689*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
onDumpInfo() const690*c8dee2aaSAndroid Build Coastguard Worker     SkString onDumpInfo() const override {
691*c8dee2aaSAndroid Build Coastguard Worker         SkString string;
692*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < fGeoData.size(); ++i) {
693*c8dee2aaSAndroid Build Coastguard Worker             string.appendf(
694*c8dee2aaSAndroid Build Coastguard Worker                     "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f],"
695*c8dee2aaSAndroid Build Coastguard Worker                     "OuterRad: %.2f, Umbra: %.2f, InnerRad: %.2f, BlurRad: %.2f\n",
696*c8dee2aaSAndroid Build Coastguard Worker                     fGeoData[i].fColor, fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.fTop,
697*c8dee2aaSAndroid Build Coastguard Worker                     fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds.fBottom,
698*c8dee2aaSAndroid Build Coastguard Worker                     fGeoData[i].fOuterRadius, fGeoData[i].fUmbraInset,
699*c8dee2aaSAndroid Build Coastguard Worker                     fGeoData[i].fInnerRadius, fGeoData[i].fBlurRadius);
700*c8dee2aaSAndroid Build Coastguard Worker         }
701*c8dee2aaSAndroid Build Coastguard Worker         return string;
702*c8dee2aaSAndroid Build Coastguard Worker     }
703*c8dee2aaSAndroid Build Coastguard Worker #endif
704*c8dee2aaSAndroid Build Coastguard Worker 
visitProxies(const GrVisitProxyFunc & func) const705*c8dee2aaSAndroid Build Coastguard Worker     void visitProxies(const GrVisitProxyFunc& func) const override {
706*c8dee2aaSAndroid Build Coastguard Worker         func(fFalloffView.proxy(), skgpu::Mipmapped(false));
707*c8dee2aaSAndroid Build Coastguard Worker         if (fProgramInfo) {
708*c8dee2aaSAndroid Build Coastguard Worker             fProgramInfo->visitFPProxies(func);
709*c8dee2aaSAndroid Build Coastguard Worker         }
710*c8dee2aaSAndroid Build Coastguard Worker     }
711*c8dee2aaSAndroid Build Coastguard Worker 
712*c8dee2aaSAndroid Build Coastguard Worker     STArray<1, Geometry, true> fGeoData;
713*c8dee2aaSAndroid Build Coastguard Worker     int fVertCount;
714*c8dee2aaSAndroid Build Coastguard Worker     int fIndexCount;
715*c8dee2aaSAndroid Build Coastguard Worker     GrSurfaceProxyView fFalloffView;
716*c8dee2aaSAndroid Build Coastguard Worker 
717*c8dee2aaSAndroid Build Coastguard Worker     GrSimpleMesh*      fMesh = nullptr;
718*c8dee2aaSAndroid Build Coastguard Worker     GrProgramInfo*     fProgramInfo = nullptr;
719*c8dee2aaSAndroid Build Coastguard Worker 
720*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = GrMeshDrawOp;
721*c8dee2aaSAndroid Build Coastguard Worker };
722*c8dee2aaSAndroid Build Coastguard Worker 
723*c8dee2aaSAndroid Build Coastguard Worker }  // anonymous namespace
724*c8dee2aaSAndroid Build Coastguard Worker 
725*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
726*c8dee2aaSAndroid Build Coastguard Worker 
727*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::ganesh::ShadowRRectOp {
728*c8dee2aaSAndroid Build Coastguard Worker 
create_falloff_texture(GrRecordingContext * rContext)729*c8dee2aaSAndroid Build Coastguard Worker static GrSurfaceProxyView create_falloff_texture(GrRecordingContext* rContext) {
730*c8dee2aaSAndroid Build Coastguard Worker     static const skgpu::UniqueKey::Domain kDomain = skgpu::UniqueKey::GenerateDomain();
731*c8dee2aaSAndroid Build Coastguard Worker     skgpu::UniqueKey key;
732*c8dee2aaSAndroid Build Coastguard Worker     skgpu::UniqueKey::Builder builder(&key, kDomain, 0, "Shadow Gaussian Falloff");
733*c8dee2aaSAndroid Build Coastguard Worker     builder.finish();
734*c8dee2aaSAndroid Build Coastguard Worker 
735*c8dee2aaSAndroid Build Coastguard Worker     auto threadSafeCache = rContext->priv().threadSafeCache();
736*c8dee2aaSAndroid Build Coastguard Worker 
737*c8dee2aaSAndroid Build Coastguard Worker     GrSurfaceProxyView view = threadSafeCache->find(key);
738*c8dee2aaSAndroid Build Coastguard Worker     if (view) {
739*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(view.origin() == kTopLeft_GrSurfaceOrigin);
740*c8dee2aaSAndroid Build Coastguard Worker         return view;
741*c8dee2aaSAndroid Build Coastguard Worker     }
742*c8dee2aaSAndroid Build Coastguard Worker 
743*c8dee2aaSAndroid Build Coastguard Worker     static const int kWidth = 128;
744*c8dee2aaSAndroid Build Coastguard Worker     static const size_t kRowBytes = kWidth * GrColorTypeBytesPerPixel(GrColorType::kAlpha_8);
745*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo ii = SkImageInfo::MakeA8(kWidth, 1);
746*c8dee2aaSAndroid Build Coastguard Worker 
747*c8dee2aaSAndroid Build Coastguard Worker     SkBitmap bitmap;
748*c8dee2aaSAndroid Build Coastguard Worker     bitmap.allocPixels(ii, kRowBytes);
749*c8dee2aaSAndroid Build Coastguard Worker 
750*c8dee2aaSAndroid Build Coastguard Worker     unsigned char* values = (unsigned char*)bitmap.getPixels();
751*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 128; ++i) {
752*c8dee2aaSAndroid Build Coastguard Worker         SkScalar d = SK_Scalar1 - i / SkIntToScalar(127);
753*c8dee2aaSAndroid Build Coastguard Worker         values[i] = SkScalarRoundToInt((SkScalarExp(-4 * d * d) - 0.018f) * 255);
754*c8dee2aaSAndroid Build Coastguard Worker     }
755*c8dee2aaSAndroid Build Coastguard Worker     bitmap.setImmutable();
756*c8dee2aaSAndroid Build Coastguard Worker 
757*c8dee2aaSAndroid Build Coastguard Worker     view = std::get<0>(GrMakeUncachedBitmapProxyView(rContext, bitmap));
758*c8dee2aaSAndroid Build Coastguard Worker     if (!view) {
759*c8dee2aaSAndroid Build Coastguard Worker         return {};
760*c8dee2aaSAndroid Build Coastguard Worker     }
761*c8dee2aaSAndroid Build Coastguard Worker 
762*c8dee2aaSAndroid Build Coastguard Worker     view = threadSafeCache->add(key, view);
763*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(view.origin() == kTopLeft_GrSurfaceOrigin);
764*c8dee2aaSAndroid Build Coastguard Worker     return view;
765*c8dee2aaSAndroid Build Coastguard Worker }
766*c8dee2aaSAndroid Build Coastguard Worker 
Make(GrRecordingContext * context,GrColor color,const SkMatrix & viewMatrix,const SkRRect & rrect,SkScalar blurWidth,SkScalar insetWidth)767*c8dee2aaSAndroid Build Coastguard Worker GrOp::Owner Make(GrRecordingContext* context,
768*c8dee2aaSAndroid Build Coastguard Worker                  GrColor color,
769*c8dee2aaSAndroid Build Coastguard Worker                  const SkMatrix& viewMatrix,
770*c8dee2aaSAndroid Build Coastguard Worker                  const SkRRect& rrect,
771*c8dee2aaSAndroid Build Coastguard Worker                  SkScalar blurWidth,
772*c8dee2aaSAndroid Build Coastguard Worker                  SkScalar insetWidth) {
773*c8dee2aaSAndroid Build Coastguard Worker     // Shadow rrect ops only handle simple circular rrects.
774*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(viewMatrix.isSimilarity() && SkRRectPriv::EqualRadii(rrect));
775*c8dee2aaSAndroid Build Coastguard Worker 
776*c8dee2aaSAndroid Build Coastguard Worker     GrSurfaceProxyView falloffView = create_falloff_texture(context);
777*c8dee2aaSAndroid Build Coastguard Worker     if (!falloffView) {
778*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
779*c8dee2aaSAndroid Build Coastguard Worker     }
780*c8dee2aaSAndroid Build Coastguard Worker 
781*c8dee2aaSAndroid Build Coastguard Worker     // Do any matrix crunching before we reset the draw state for device coords.
782*c8dee2aaSAndroid Build Coastguard Worker     const SkRect& rrectBounds = rrect.getBounds();
783*c8dee2aaSAndroid Build Coastguard Worker     SkRect bounds;
784*c8dee2aaSAndroid Build Coastguard Worker     viewMatrix.mapRect(&bounds, rrectBounds);
785*c8dee2aaSAndroid Build Coastguard Worker 
786*c8dee2aaSAndroid Build Coastguard Worker     // Map radius and inset. As the matrix is a similarity matrix, this should be isotropic.
787*c8dee2aaSAndroid Build Coastguard Worker     SkScalar radius = SkRRectPriv::GetSimpleRadii(rrect).fX;
788*c8dee2aaSAndroid Build Coastguard Worker     SkScalar matrixFactor = viewMatrix[SkMatrix::kMScaleX] + viewMatrix[SkMatrix::kMSkewX];
789*c8dee2aaSAndroid Build Coastguard Worker     SkScalar scaledRadius = SkScalarAbs(radius*matrixFactor);
790*c8dee2aaSAndroid Build Coastguard Worker     SkScalar scaledInsetWidth = SkScalarAbs(insetWidth*matrixFactor);
791*c8dee2aaSAndroid Build Coastguard Worker 
792*c8dee2aaSAndroid Build Coastguard Worker     if (scaledInsetWidth <= 0) {
793*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
794*c8dee2aaSAndroid Build Coastguard Worker     }
795*c8dee2aaSAndroid Build Coastguard Worker 
796*c8dee2aaSAndroid Build Coastguard Worker     return GrOp::Make<ShadowCircularRRectOp>(context,
797*c8dee2aaSAndroid Build Coastguard Worker                                              color,
798*c8dee2aaSAndroid Build Coastguard Worker                                              bounds,
799*c8dee2aaSAndroid Build Coastguard Worker                                              scaledRadius,
800*c8dee2aaSAndroid Build Coastguard Worker                                              rrect.isOval(),
801*c8dee2aaSAndroid Build Coastguard Worker                                              blurWidth,
802*c8dee2aaSAndroid Build Coastguard Worker                                              scaledInsetWidth,
803*c8dee2aaSAndroid Build Coastguard Worker                                              std::move(falloffView));
804*c8dee2aaSAndroid Build Coastguard Worker }
805*c8dee2aaSAndroid Build Coastguard Worker 
806*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skgpu::ganesh::ShadowRRectOp
807*c8dee2aaSAndroid Build Coastguard Worker 
808*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
809*c8dee2aaSAndroid Build Coastguard Worker 
810*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
811*c8dee2aaSAndroid Build Coastguard Worker 
GR_DRAW_OP_TEST_DEFINE(ShadowRRectOp)812*c8dee2aaSAndroid Build Coastguard Worker GR_DRAW_OP_TEST_DEFINE(ShadowRRectOp) {
813*c8dee2aaSAndroid Build Coastguard Worker     // We may choose matrix and inset values that cause the factory to fail. We loop until we find
814*c8dee2aaSAndroid Build Coastguard Worker     // an acceptable combination.
815*c8dee2aaSAndroid Build Coastguard Worker     do {
816*c8dee2aaSAndroid Build Coastguard Worker         // create a similarity matrix
817*c8dee2aaSAndroid Build Coastguard Worker         SkScalar rotate = random->nextSScalar1() * 360.f;
818*c8dee2aaSAndroid Build Coastguard Worker         SkScalar translateX = random->nextSScalar1() * 1000.f;
819*c8dee2aaSAndroid Build Coastguard Worker         SkScalar translateY = random->nextSScalar1() * 1000.f;
820*c8dee2aaSAndroid Build Coastguard Worker         SkScalar scale = random->nextSScalar1() * 100.f;
821*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix viewMatrix;
822*c8dee2aaSAndroid Build Coastguard Worker         viewMatrix.setRotate(rotate);
823*c8dee2aaSAndroid Build Coastguard Worker         viewMatrix.postTranslate(translateX, translateY);
824*c8dee2aaSAndroid Build Coastguard Worker         viewMatrix.postScale(scale, scale);
825*c8dee2aaSAndroid Build Coastguard Worker         SkScalar insetWidth = random->nextSScalar1() * 72.f;
826*c8dee2aaSAndroid Build Coastguard Worker         SkScalar blurWidth = random->nextSScalar1() * 72.f;
827*c8dee2aaSAndroid Build Coastguard Worker         bool isCircle = random->nextBool();
828*c8dee2aaSAndroid Build Coastguard Worker         // This op doesn't use a full GrPaint, just a color.
829*c8dee2aaSAndroid Build Coastguard Worker         GrColor color = paint.getColor4f().toBytes_RGBA();
830*c8dee2aaSAndroid Build Coastguard Worker         if (isCircle) {
831*c8dee2aaSAndroid Build Coastguard Worker             SkRect circle = GrTest::TestSquare(random);
832*c8dee2aaSAndroid Build Coastguard Worker             SkRRect rrect = SkRRect::MakeOval(circle);
833*c8dee2aaSAndroid Build Coastguard Worker             if (auto op = skgpu::ganesh::ShadowRRectOp::Make(
834*c8dee2aaSAndroid Build Coastguard Worker                         context, color, viewMatrix, rrect, blurWidth, insetWidth)) {
835*c8dee2aaSAndroid Build Coastguard Worker                 return op;
836*c8dee2aaSAndroid Build Coastguard Worker             }
837*c8dee2aaSAndroid Build Coastguard Worker         } else {
838*c8dee2aaSAndroid Build Coastguard Worker             SkRRect rrect;
839*c8dee2aaSAndroid Build Coastguard Worker             do {
840*c8dee2aaSAndroid Build Coastguard Worker                 // This may return a rrect with elliptical corners, which will cause an assert.
841*c8dee2aaSAndroid Build Coastguard Worker                 rrect = GrTest::TestRRectSimple(random);
842*c8dee2aaSAndroid Build Coastguard Worker             } while (!SkRRectPriv::IsSimpleCircular(rrect));
843*c8dee2aaSAndroid Build Coastguard Worker             if (auto op = skgpu::ganesh::ShadowRRectOp::Make(
844*c8dee2aaSAndroid Build Coastguard Worker                         context, color, viewMatrix, rrect, blurWidth, insetWidth)) {
845*c8dee2aaSAndroid Build Coastguard Worker                 return op;
846*c8dee2aaSAndroid Build Coastguard Worker             }
847*c8dee2aaSAndroid Build Coastguard Worker         }
848*c8dee2aaSAndroid Build Coastguard Worker     } while (true);
849*c8dee2aaSAndroid Build Coastguard Worker }
850*c8dee2aaSAndroid Build Coastguard Worker 
851*c8dee2aaSAndroid Build Coastguard Worker #endif // defined(GPU_TEST_UTILS)
852