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