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