1/* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "GrRRectEffect.h" 9 10#include "GrConvexPolyEffect.h" 11#include "GrFragmentProcessor.h" 12#include "GrOvalEffect.h" 13#include "GrShaderCaps.h" 14#include "SkRRectPriv.h" 15#include "SkTLazy.h" 16#include "glsl/GrGLSLFragmentProcessor.h" 17#include "glsl/GrGLSLFragmentShaderBuilder.h" 18#include "glsl/GrGLSLProgramDataManager.h" 19#include "glsl/GrGLSLUniformHandler.h" 20 21// The effects defined here only handle rrect radii >= kRadiusMin. 22static const SkScalar kRadiusMin = SK_ScalarHalf; 23 24////////////////////////////////////////////////////////////////////////////// 25 26class CircularRRectEffect : public GrFragmentProcessor { 27public: 28 29 enum CornerFlags { 30 kTopLeft_CornerFlag = (1 << SkRRect::kUpperLeft_Corner), 31 kTopRight_CornerFlag = (1 << SkRRect::kUpperRight_Corner), 32 kBottomRight_CornerFlag = (1 << SkRRect::kLowerRight_Corner), 33 kBottomLeft_CornerFlag = (1 << SkRRect::kLowerLeft_Corner), 34 35 kLeft_CornerFlags = kTopLeft_CornerFlag | kBottomLeft_CornerFlag, 36 kTop_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag, 37 kRight_CornerFlags = kTopRight_CornerFlag | kBottomRight_CornerFlag, 38 kBottom_CornerFlags = kBottomLeft_CornerFlag | kBottomRight_CornerFlag, 39 40 kAll_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag | 41 kBottomLeft_CornerFlag | kBottomRight_CornerFlag, 42 43 kNone_CornerFlags = 0 44 }; 45 46 // The flags are used to indicate which corners are circluar (unflagged corners are assumed to 47 // be square). 48 static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, 49 uint32_t circularCornerFlags, const SkRRect&); 50 51 ~CircularRRectEffect() override {} 52 53 const char* name() const override { return "CircularRRect"; } 54 55 std::unique_ptr<GrFragmentProcessor> clone() const override; 56 57 const SkRRect& getRRect() const { return fRRect; } 58 59 uint32_t getCircularCornerFlags() const { return fCircularCornerFlags; } 60 61 GrClipEdgeType getEdgeType() const { return fEdgeType; } 62 63private: 64 CircularRRectEffect(GrClipEdgeType, uint32_t circularCornerFlags, const SkRRect&); 65 66 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; 67 68 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 69 70 bool onIsEqual(const GrFragmentProcessor& other) const override; 71 72 SkRRect fRRect; 73 GrClipEdgeType fEdgeType; 74 uint32_t fCircularCornerFlags; 75 76 GR_DECLARE_FRAGMENT_PROCESSOR_TEST 77 78 typedef GrFragmentProcessor INHERITED; 79}; 80 81std::unique_ptr<GrFragmentProcessor> CircularRRectEffect::Make(GrClipEdgeType edgeType, 82 uint32_t circularCornerFlags, 83 const SkRRect& rrect) { 84 if (GrClipEdgeType::kFillAA != edgeType && GrClipEdgeType::kInverseFillAA != edgeType) { 85 return nullptr; 86 } 87 return std::unique_ptr<GrFragmentProcessor>( 88 new CircularRRectEffect(edgeType, circularCornerFlags, rrect)); 89} 90 91CircularRRectEffect::CircularRRectEffect(GrClipEdgeType edgeType, uint32_t circularCornerFlags, 92 const SkRRect& rrect) 93 : INHERITED(kCircularRRectEffect_ClassID, kCompatibleWithCoverageAsAlpha_OptimizationFlag) 94 , fRRect(rrect) 95 , fEdgeType(edgeType) 96 , fCircularCornerFlags(circularCornerFlags) { 97} 98 99std::unique_ptr<GrFragmentProcessor> CircularRRectEffect::clone() const { 100 return std::unique_ptr<GrFragmentProcessor>( 101 new CircularRRectEffect(fEdgeType, fCircularCornerFlags, fRRect)); 102} 103 104bool CircularRRectEffect::onIsEqual(const GrFragmentProcessor& other) const { 105 const CircularRRectEffect& crre = other.cast<CircularRRectEffect>(); 106 // The corner flags are derived from fRRect, so no need to check them. 107 return fEdgeType == crre.fEdgeType && fRRect == crre.fRRect; 108} 109 110////////////////////////////////////////////////////////////////////////////// 111 112GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircularRRectEffect); 113 114#if GR_TEST_UTILS 115std::unique_ptr<GrFragmentProcessor> CircularRRectEffect::TestCreate(GrProcessorTestData* d) { 116 SkScalar w = d->fRandom->nextRangeScalar(20.f, 1000.f); 117 SkScalar h = d->fRandom->nextRangeScalar(20.f, 1000.f); 118 SkScalar r = d->fRandom->nextRangeF(kRadiusMin, 9.f); 119 SkRRect rrect; 120 rrect.setRectXY(SkRect::MakeWH(w, h), r, r); 121 std::unique_ptr<GrFragmentProcessor> fp; 122 do { 123 GrClipEdgeType et = 124 (GrClipEdgeType)d->fRandom->nextULessThan(kGrClipEdgeTypeCnt); 125 fp = GrRRectEffect::Make(et, rrect, *d->caps()->shaderCaps()); 126 } while (nullptr == fp); 127 return fp; 128} 129#endif 130 131////////////////////////////////////////////////////////////////////////////// 132 133class GLCircularRRectEffect : public GrGLSLFragmentProcessor { 134public: 135 GLCircularRRectEffect() = default; 136 137 virtual void emitCode(EmitArgs&) override; 138 139 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); 140 141protected: 142 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; 143 144private: 145 GrGLSLProgramDataManager::UniformHandle fInnerRectUniform; 146 GrGLSLProgramDataManager::UniformHandle fRadiusPlusHalfUniform; 147 SkRRect fPrevRRect; 148 typedef GrGLSLFragmentProcessor INHERITED; 149}; 150 151void GLCircularRRectEffect::emitCode(EmitArgs& args) { 152 const CircularRRectEffect& crre = args.fFp.cast<CircularRRectEffect>(); 153 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 154 const char *rectName; 155 const char *radiusPlusHalfName; 156 // The inner rect is the rrect bounds inset by the radius. Its left, top, right, and bottom 157 // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has 158 // only rectangular corners, that side's value corresponds to the rect edge's value outset by 159 // half a pixel. 160 fInnerRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, 161 "innerRect", &rectName); 162 // x is (r + .5) and y is 1/(r + .5) 163 fRadiusPlusHalfUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType, 164 "radiusPlusHalf", &radiusPlusHalfName); 165 166 // If we're on a device where float != fp32 then the length calculation could overflow. 167 SkString clampedCircleDistance; 168 if (!args.fShaderCaps->floatIs32Bits()) { 169 clampedCircleDistance.printf("clamp(%s.x * (1.0 - length(dxy * %s.y)), 0.0, 1.0);", 170 radiusPlusHalfName, radiusPlusHalfName); 171 } else { 172 clampedCircleDistance.printf("clamp(%s.x - length(dxy), 0.0, 1.0);", radiusPlusHalfName); 173 } 174 175 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 176 // At each quarter-circle corner we compute a vector that is the offset of the fragment position 177 // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant 178 // to that corner. This means that points near the interior near the rrect top edge will have 179 // a vector that points straight up for both the TL left and TR corners. Computing an 180 // alpha from this vector at either the TR or TL corner will give the correct result. Similarly, 181 // fragments near the other three edges will get the correct AA. Fragments in the interior of 182 // the rrect will have a (0,0) vector at all four corners. So long as the radius > 0.5 they will 183 // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas. 184 // The code below is a simplified version of the above that performs maxs on the vector 185 // components before computing distances and alpha values so that only one distance computation 186 // need be computed to determine the min alpha. 187 // 188 // For the cases where one half of the rrect is rectangular we drop one of the x or y 189 // computations, compute a separate rect edge alpha for the rect side, and mul the two computed 190 // alphas together. 191 switch (crre.getCircularCornerFlags()) { 192 case CircularRRectEffect::kAll_CornerFlags: 193 fragBuilder->codeAppendf("float2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName); 194 fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName); 195 fragBuilder->codeAppend("float2 dxy = max(max(dxy0, dxy1), 0.0);"); 196 fragBuilder->codeAppendf("half alpha = %s;", clampedCircleDistance.c_str()); 197 break; 198 case CircularRRectEffect::kTopLeft_CornerFlag: 199 fragBuilder->codeAppendf("float2 dxy = max(%s.xy - sk_FragCoord.xy, 0.0);", 200 rectName); 201 fragBuilder->codeAppendf("half rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);", 202 rectName); 203 fragBuilder->codeAppendf("half bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);", 204 rectName); 205 fragBuilder->codeAppendf("half alpha = bottomAlpha * rightAlpha * %s;", 206 clampedCircleDistance.c_str()); 207 break; 208 case CircularRRectEffect::kTopRight_CornerFlag: 209 fragBuilder->codeAppendf("float2 dxy = max(float2(sk_FragCoord.x - %s.z, " 210 "%s.y - sk_FragCoord.y), 0.0);", 211 rectName, rectName); 212 fragBuilder->codeAppendf("half leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);", 213 rectName); 214 fragBuilder->codeAppendf("half bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);", 215 rectName); 216 fragBuilder->codeAppendf("half alpha = bottomAlpha * leftAlpha * %s;", 217 clampedCircleDistance.c_str()); 218 break; 219 case CircularRRectEffect::kBottomRight_CornerFlag: 220 fragBuilder->codeAppendf("float2 dxy = max(sk_FragCoord.xy - %s.zw, 0.0);", 221 rectName); 222 fragBuilder->codeAppendf("half leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);", 223 rectName); 224 fragBuilder->codeAppendf("half topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);", 225 rectName); 226 fragBuilder->codeAppendf("half alpha = topAlpha * leftAlpha * %s;", 227 clampedCircleDistance.c_str()); 228 break; 229 case CircularRRectEffect::kBottomLeft_CornerFlag: 230 fragBuilder->codeAppendf("float2 dxy = max(float2(%s.x - sk_FragCoord.x, " 231 "sk_FragCoord.y - %s.w), 0.0);", 232 rectName, rectName); 233 fragBuilder->codeAppendf("half rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);", 234 rectName); 235 fragBuilder->codeAppendf("half topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);", 236 rectName); 237 fragBuilder->codeAppendf("half alpha = topAlpha * rightAlpha * %s;", 238 clampedCircleDistance.c_str()); 239 break; 240 case CircularRRectEffect::kLeft_CornerFlags: 241 fragBuilder->codeAppendf("float2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName); 242 fragBuilder->codeAppendf("float dy1 = sk_FragCoord.y - %s.w;", rectName); 243 fragBuilder->codeAppend("float2 dxy = max(float2(dxy0.x, max(dxy0.y, dy1)), 0.0);"); 244 fragBuilder->codeAppendf("half rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);", 245 rectName); 246 fragBuilder->codeAppendf("half alpha = rightAlpha * %s;", 247 clampedCircleDistance.c_str()); 248 break; 249 case CircularRRectEffect::kTop_CornerFlags: 250 fragBuilder->codeAppendf("float2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName); 251 fragBuilder->codeAppendf("float dx1 = sk_FragCoord.x - %s.z;", rectName); 252 fragBuilder->codeAppend("float2 dxy = max(float2(max(dxy0.x, dx1), dxy0.y), 0.0);"); 253 fragBuilder->codeAppendf("half bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);", 254 rectName); 255 fragBuilder->codeAppendf("half alpha = bottomAlpha * %s;", 256 clampedCircleDistance.c_str()); 257 break; 258 case CircularRRectEffect::kRight_CornerFlags: 259 fragBuilder->codeAppendf("float dy0 = %s.y - sk_FragCoord.y;", rectName); 260 fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName); 261 fragBuilder->codeAppend("float2 dxy = max(float2(dxy1.x, max(dy0, dxy1.y)), 0.0);"); 262 fragBuilder->codeAppendf("half leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);", 263 rectName); 264 fragBuilder->codeAppendf("half alpha = leftAlpha * %s;", 265 clampedCircleDistance.c_str()); 266 break; 267 case CircularRRectEffect::kBottom_CornerFlags: 268 fragBuilder->codeAppendf("float dx0 = %s.x - sk_FragCoord.x;", rectName); 269 fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName); 270 fragBuilder->codeAppend("float2 dxy = max(float2(max(dx0, dxy1.x), dxy1.y), 0.0);"); 271 fragBuilder->codeAppendf("half topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);", 272 rectName); 273 fragBuilder->codeAppendf("half alpha = topAlpha * %s;", 274 clampedCircleDistance.c_str()); 275 break; 276 } 277 278 if (GrClipEdgeType::kInverseFillAA == crre.getEdgeType()) { 279 fragBuilder->codeAppend("alpha = 1.0 - alpha;"); 280 } 281 282 fragBuilder->codeAppendf("%s = %s * alpha;", args.fOutputColor, args.fInputColor); 283} 284 285void GLCircularRRectEffect::GenKey(const GrProcessor& processor, const GrShaderCaps&, 286 GrProcessorKeyBuilder* b) { 287 const CircularRRectEffect& crre = processor.cast<CircularRRectEffect>(); 288 GR_STATIC_ASSERT(kGrClipEdgeTypeCnt <= 8); 289 b->add32((crre.getCircularCornerFlags() << 3) | (int) crre.getEdgeType()); 290} 291 292void GLCircularRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman, 293 const GrFragmentProcessor& processor) { 294 const CircularRRectEffect& crre = processor.cast<CircularRRectEffect>(); 295 const SkRRect& rrect = crre.getRRect(); 296 if (rrect != fPrevRRect) { 297 SkRect rect = rrect.getBounds(); 298 SkScalar radius = 0; 299 switch (crre.getCircularCornerFlags()) { 300 case CircularRRectEffect::kAll_CornerFlags: 301 SkASSERT(SkRRectPriv::IsSimpleCircular(rrect)); 302 radius = SkRRectPriv::GetSimpleRadii(rrect).fX; 303 SkASSERT(radius >= kRadiusMin); 304 rect.inset(radius, radius); 305 break; 306 case CircularRRectEffect::kTopLeft_CornerFlag: 307 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX; 308 rect.fLeft += radius; 309 rect.fTop += radius; 310 rect.fRight += 0.5f; 311 rect.fBottom += 0.5f; 312 break; 313 case CircularRRectEffect::kTopRight_CornerFlag: 314 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX; 315 rect.fLeft -= 0.5f; 316 rect.fTop += radius; 317 rect.fRight -= radius; 318 rect.fBottom += 0.5f; 319 break; 320 case CircularRRectEffect::kBottomRight_CornerFlag: 321 radius = rrect.radii(SkRRect::kLowerRight_Corner).fX; 322 rect.fLeft -= 0.5f; 323 rect.fTop -= 0.5f; 324 rect.fRight -= radius; 325 rect.fBottom -= radius; 326 break; 327 case CircularRRectEffect::kBottomLeft_CornerFlag: 328 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX; 329 rect.fLeft += radius; 330 rect.fTop -= 0.5f; 331 rect.fRight += 0.5f; 332 rect.fBottom -= radius; 333 break; 334 case CircularRRectEffect::kLeft_CornerFlags: 335 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX; 336 rect.fLeft += radius; 337 rect.fTop += radius; 338 rect.fRight += 0.5f; 339 rect.fBottom -= radius; 340 break; 341 case CircularRRectEffect::kTop_CornerFlags: 342 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX; 343 rect.fLeft += radius; 344 rect.fTop += radius; 345 rect.fRight -= radius; 346 rect.fBottom += 0.5f; 347 break; 348 case CircularRRectEffect::kRight_CornerFlags: 349 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX; 350 rect.fLeft -= 0.5f; 351 rect.fTop += radius; 352 rect.fRight -= radius; 353 rect.fBottom -= radius; 354 break; 355 case CircularRRectEffect::kBottom_CornerFlags: 356 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX; 357 rect.fLeft += radius; 358 rect.fTop -= 0.5f; 359 rect.fRight -= radius; 360 rect.fBottom -= radius; 361 break; 362 default: 363 SK_ABORT("Should have been one of the above cases."); 364 } 365 pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); 366 radius += 0.5f; 367 pdman.set2f(fRadiusPlusHalfUniform, radius, 1.f / radius); 368 fPrevRRect = rrect; 369 } 370} 371 372//////////////////////////////////////////////////////////////////////////////////////////////////// 373 374void CircularRRectEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, 375 GrProcessorKeyBuilder* b) const { 376 GLCircularRRectEffect::GenKey(*this, caps, b); 377} 378 379GrGLSLFragmentProcessor* CircularRRectEffect::onCreateGLSLInstance() const { 380 return new GLCircularRRectEffect; 381} 382 383////////////////////////////////////////////////////////////////////////////// 384 385class EllipticalRRectEffect : public GrFragmentProcessor { 386public: 387 static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkRRect&); 388 389 ~EllipticalRRectEffect() override {} 390 391 const char* name() const override { return "EllipticalRRect"; } 392 393 std::unique_ptr<GrFragmentProcessor> clone() const override; 394 395 const SkRRect& getRRect() const { return fRRect; } 396 397 GrClipEdgeType getEdgeType() const { return fEdgeType; } 398 399private: 400 EllipticalRRectEffect(GrClipEdgeType, const SkRRect&); 401 402 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; 403 404 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 405 406 bool onIsEqual(const GrFragmentProcessor& other) const override; 407 408 SkRRect fRRect; 409 GrClipEdgeType fEdgeType; 410 411 GR_DECLARE_FRAGMENT_PROCESSOR_TEST 412 413 typedef GrFragmentProcessor INHERITED; 414}; 415 416std::unique_ptr<GrFragmentProcessor> EllipticalRRectEffect::Make(GrClipEdgeType edgeType, 417 const SkRRect& rrect) { 418 if (GrClipEdgeType::kFillAA != edgeType && GrClipEdgeType::kInverseFillAA != edgeType) { 419 return nullptr; 420 } 421 return std::unique_ptr<GrFragmentProcessor>(new EllipticalRRectEffect(edgeType, rrect)); 422} 423 424EllipticalRRectEffect::EllipticalRRectEffect(GrClipEdgeType edgeType, const SkRRect& rrect) 425 : INHERITED(kEllipticalRRectEffect_ClassID, kCompatibleWithCoverageAsAlpha_OptimizationFlag) 426 , fRRect(rrect) 427 , fEdgeType(edgeType) { 428} 429 430std::unique_ptr<GrFragmentProcessor> EllipticalRRectEffect::clone() const { 431 return std::unique_ptr<GrFragmentProcessor>(new EllipticalRRectEffect(fEdgeType, fRRect)); 432} 433 434bool EllipticalRRectEffect::onIsEqual(const GrFragmentProcessor& other) const { 435 const EllipticalRRectEffect& erre = other.cast<EllipticalRRectEffect>(); 436 return fEdgeType == erre.fEdgeType && fRRect == erre.fRRect; 437} 438 439////////////////////////////////////////////////////////////////////////////// 440 441GR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipticalRRectEffect); 442 443#if GR_TEST_UTILS 444std::unique_ptr<GrFragmentProcessor> EllipticalRRectEffect::TestCreate(GrProcessorTestData* d) { 445 SkScalar w = d->fRandom->nextRangeScalar(20.f, 1000.f); 446 SkScalar h = d->fRandom->nextRangeScalar(20.f, 1000.f); 447 SkVector r[4]; 448 r[SkRRect::kUpperLeft_Corner].fX = d->fRandom->nextRangeF(kRadiusMin, 9.f); 449 // ensure at least one corner really is elliptical 450 do { 451 r[SkRRect::kUpperLeft_Corner].fY = d->fRandom->nextRangeF(kRadiusMin, 9.f); 452 } while (r[SkRRect::kUpperLeft_Corner].fY == r[SkRRect::kUpperLeft_Corner].fX); 453 454 SkRRect rrect; 455 if (d->fRandom->nextBool()) { 456 // half the time create a four-radii rrect. 457 r[SkRRect::kLowerRight_Corner].fX = d->fRandom->nextRangeF(kRadiusMin, 9.f); 458 r[SkRRect::kLowerRight_Corner].fY = d->fRandom->nextRangeF(kRadiusMin, 9.f); 459 460 r[SkRRect::kUpperRight_Corner].fX = r[SkRRect::kLowerRight_Corner].fX; 461 r[SkRRect::kUpperRight_Corner].fY = r[SkRRect::kUpperLeft_Corner].fY; 462 463 r[SkRRect::kLowerLeft_Corner].fX = r[SkRRect::kUpperLeft_Corner].fX; 464 r[SkRRect::kLowerLeft_Corner].fY = r[SkRRect::kLowerRight_Corner].fY; 465 466 rrect.setRectRadii(SkRect::MakeWH(w, h), r); 467 } else { 468 rrect.setRectXY(SkRect::MakeWH(w, h), r[SkRRect::kUpperLeft_Corner].fX, 469 r[SkRRect::kUpperLeft_Corner].fY); 470 } 471 std::unique_ptr<GrFragmentProcessor> fp; 472 do { 473 GrClipEdgeType et = (GrClipEdgeType)d->fRandom->nextULessThan(kGrClipEdgeTypeCnt); 474 fp = GrRRectEffect::Make(et, rrect, *d->caps()->shaderCaps()); 475 } while (nullptr == fp); 476 return fp; 477} 478#endif 479 480////////////////////////////////////////////////////////////////////////////// 481 482class GLEllipticalRRectEffect : public GrGLSLFragmentProcessor { 483public: 484 GLEllipticalRRectEffect() = default; 485 486 void emitCode(EmitArgs&) override; 487 488 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); 489 490protected: 491 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; 492 493private: 494 GrGLSLProgramDataManager::UniformHandle fInnerRectUniform; 495 GrGLSLProgramDataManager::UniformHandle fInvRadiiSqdUniform; 496 GrGLSLProgramDataManager::UniformHandle fScaleUniform; 497 SkRRect fPrevRRect; 498 typedef GrGLSLFragmentProcessor INHERITED; 499}; 500 501void GLEllipticalRRectEffect::emitCode(EmitArgs& args) { 502 const EllipticalRRectEffect& erre = args.fFp.cast<EllipticalRRectEffect>(); 503 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 504 const char *rectName; 505 // The inner rect is the rrect bounds inset by the x/y radii 506 fInnerRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, 507 "innerRect", &rectName); 508 509 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 510 // At each quarter-ellipse corner we compute a vector that is the offset of the fragment pos 511 // to the ellipse center. The vector is pinned in x and y to be in the quarter-plane relevant 512 // to that corner. This means that points near the interior near the rrect top edge will have 513 // a vector that points straight up for both the TL left and TR corners. Computing an 514 // alpha from this vector at either the TR or TL corner will give the correct result. Similarly, 515 // fragments near the other three edges will get the correct AA. Fragments in the interior of 516 // the rrect will have a (0,0) vector at all four corners. So long as the radii > 0.5 they will 517 // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas. 518 // 519 // The code below is a simplified version of the above that performs maxs on the vector 520 // components before computing distances and alpha values so that only one distance computation 521 // need be computed to determine the min alpha. 522 fragBuilder->codeAppendf("float2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName); 523 fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName); 524 525 // If we're on a device where float != fp32 then we'll do the distance computation in a space 526 // that is normalized by the largest radius. The scale uniform will be scale, 1/scale. The 527 // radii uniform values are already in this normalized space. 528 const char* scaleName = nullptr; 529 if (!args.fShaderCaps->floatIs32Bits()) { 530 fScaleUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType, "scale", 531 &scaleName); 532 } 533 534 // The uniforms with the inv squared radii are highp to prevent underflow. 535 switch (erre.getRRect().getType()) { 536 case SkRRect::kSimple_Type: { 537 const char *invRadiiXYSqdName; 538 fInvRadiiSqdUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, 539 kHalf2_GrSLType, 540 "invRadiiXY", 541 &invRadiiXYSqdName); 542 fragBuilder->codeAppend("float2 dxy = max(max(dxy0, dxy1), 0.0);"); 543 if (scaleName) { 544 fragBuilder->codeAppendf("dxy *= %s.y;", scaleName); 545 } 546 // Z is the x/y offsets divided by squared radii. 547 fragBuilder->codeAppendf("float2 Z = dxy * %s.xy;", invRadiiXYSqdName); 548 break; 549 } 550 case SkRRect::kNinePatch_Type: { 551 const char *invRadiiLTRBSqdName; 552 fInvRadiiSqdUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, 553 kHalf4_GrSLType, 554 "invRadiiLTRB", 555 &invRadiiLTRBSqdName); 556 if (scaleName) { 557 fragBuilder->codeAppendf("dxy0 *= %s.y;", scaleName); 558 fragBuilder->codeAppendf("dxy1 *= %s.y;", scaleName); 559 } 560 fragBuilder->codeAppend("float2 dxy = max(max(dxy0, dxy1), 0.0);"); 561 // Z is the x/y offsets divided by squared radii. We only care about the (at most) one 562 // corner where both the x and y offsets are positive, hence the maxes. (The inverse 563 // squared radii will always be positive.) 564 fragBuilder->codeAppendf("float2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);", 565 invRadiiLTRBSqdName, invRadiiLTRBSqdName); 566 567 break; 568 } 569 default: 570 SK_ABORT("RRect should always be simple or nine-patch."); 571 } 572 // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1. 573 fragBuilder->codeAppend("float implicit = dot(Z, dxy) - 1.0;"); 574 // grad_dot is the squared length of the gradient of the implicit. 575 fragBuilder->codeAppend("float grad_dot = 4.0 * dot(Z, Z);"); 576 // avoid calling inversesqrt on zero. 577 fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);"); 578 fragBuilder->codeAppend("float approx_dist = implicit * inversesqrt(grad_dot);"); 579 if (scaleName) { 580 fragBuilder->codeAppendf("approx_dist *= %s.x;", scaleName); 581 } 582 583 if (GrClipEdgeType::kFillAA == erre.getEdgeType()) { 584 fragBuilder->codeAppend("half alpha = clamp(0.5 - approx_dist, 0.0, 1.0);"); 585 } else { 586 fragBuilder->codeAppend("half alpha = clamp(0.5 + approx_dist, 0.0, 1.0);"); 587 } 588 589 fragBuilder->codeAppendf("%s = %s * alpha;", args.fOutputColor, args.fInputColor); 590} 591 592void GLEllipticalRRectEffect::GenKey(const GrProcessor& effect, const GrShaderCaps&, 593 GrProcessorKeyBuilder* b) { 594 const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>(); 595 GR_STATIC_ASSERT((int) GrClipEdgeType::kLast < (1 << 3)); 596 b->add32(erre.getRRect().getType() | (int) erre.getEdgeType() << 3); 597} 598 599void GLEllipticalRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman, 600 const GrFragmentProcessor& effect) { 601 const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>(); 602 const SkRRect& rrect = erre.getRRect(); 603 // If we're using a scale factor to work around precision issues, choose the largest radius 604 // as the scale factor. The inv radii need to be pre-adjusted by the scale factor. 605 if (rrect != fPrevRRect) { 606 SkRect rect = rrect.getBounds(); 607 const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner); 608 SkASSERT(r0.fX >= kRadiusMin); 609 SkASSERT(r0.fY >= kRadiusMin); 610 switch (erre.getRRect().getType()) { 611 case SkRRect::kSimple_Type: 612 rect.inset(r0.fX, r0.fY); 613 if (fScaleUniform.isValid()) { 614 if (r0.fX > r0.fY) { 615 pdman.set2f(fInvRadiiSqdUniform, 1.f, (r0.fX * r0.fX) / (r0.fY * r0.fY)); 616 pdman.set2f(fScaleUniform, r0.fX, 1.f / r0.fX); 617 } else { 618 pdman.set2f(fInvRadiiSqdUniform, (r0.fY * r0.fY) / (r0.fX * r0.fX), 1.f); 619 pdman.set2f(fScaleUniform, r0.fY, 1.f / r0.fY); 620 } 621 } else { 622 pdman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), 623 1.f / (r0.fY * r0.fY)); 624 } 625 break; 626 case SkRRect::kNinePatch_Type: { 627 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner); 628 SkASSERT(r1.fX >= kRadiusMin); 629 SkASSERT(r1.fY >= kRadiusMin); 630 rect.fLeft += r0.fX; 631 rect.fTop += r0.fY; 632 rect.fRight -= r1.fX; 633 rect.fBottom -= r1.fY; 634 if (fScaleUniform.isValid()) { 635 float scale = SkTMax(SkTMax(r0.fX, r0.fY), SkTMax(r1.fX, r1.fY)); 636 float scaleSqd = scale * scale; 637 pdman.set4f(fInvRadiiSqdUniform, scaleSqd / (r0.fX * r0.fX), 638 scaleSqd / (r0.fY * r0.fY), 639 scaleSqd / (r1.fX * r1.fX), 640 scaleSqd / (r1.fY * r1.fY)); 641 pdman.set2f(fScaleUniform, scale, 1.f / scale); 642 } else { 643 pdman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), 644 1.f / (r0.fY * r0.fY), 645 1.f / (r1.fX * r1.fX), 646 1.f / (r1.fY * r1.fY)); 647 } 648 break; 649 } 650 default: 651 SK_ABORT("RRect should always be simple or nine-patch."); 652 } 653 pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); 654 fPrevRRect = rrect; 655 } 656} 657 658//////////////////////////////////////////////////////////////////////////////////////////////////// 659 660void EllipticalRRectEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, 661 GrProcessorKeyBuilder* b) const { 662 GLEllipticalRRectEffect::GenKey(*this, caps, b); 663} 664 665GrGLSLFragmentProcessor* EllipticalRRectEffect::onCreateGLSLInstance() const { 666 return new GLEllipticalRRectEffect; 667} 668 669////////////////////////////////////////////////////////////////////////////// 670 671std::unique_ptr<GrFragmentProcessor> GrRRectEffect::Make(GrClipEdgeType edgeType, 672 const SkRRect& rrect, 673 const GrShaderCaps& caps) { 674 if (rrect.isRect()) { 675 return GrConvexPolyEffect::Make(edgeType, rrect.getBounds()); 676 } 677 678 if (rrect.isOval()) { 679 return GrOvalEffect::Make(edgeType, rrect.getBounds(), caps); 680 } 681 682 if (rrect.isSimple()) { 683 if (SkRRectPriv::GetSimpleRadii(rrect).fX < kRadiusMin || 684 SkRRectPriv::GetSimpleRadii(rrect).fY < kRadiusMin) { 685 // In this case the corners are extremely close to rectangular and we collapse the 686 // clip to a rectangular clip. 687 return GrConvexPolyEffect::Make(edgeType, rrect.getBounds()); 688 } 689 if (SkRRectPriv::GetSimpleRadii(rrect).fX == SkRRectPriv::GetSimpleRadii(rrect).fY) { 690 return CircularRRectEffect::Make(edgeType, CircularRRectEffect::kAll_CornerFlags, 691 rrect); 692 } else { 693 return EllipticalRRectEffect::Make(edgeType, rrect); 694 } 695 } 696 697 if (rrect.isComplex() || rrect.isNinePatch()) { 698 // Check for the "tab" cases - two adjacent circular corners and two square corners. 699 SkScalar circularRadius = 0; 700 uint32_t cornerFlags = 0; 701 702 SkVector radii[4]; 703 bool squashedRadii = false; 704 for (int c = 0; c < 4; ++c) { 705 radii[c] = rrect.radii((SkRRect::Corner)c); 706 SkASSERT((0 == radii[c].fX) == (0 == radii[c].fY)); 707 if (0 == radii[c].fX) { 708 // The corner is square, so no need to squash or flag as circular. 709 continue; 710 } 711 if (radii[c].fX < kRadiusMin || radii[c].fY < kRadiusMin) { 712 radii[c].set(0, 0); 713 squashedRadii = true; 714 continue; 715 } 716 if (radii[c].fX != radii[c].fY) { 717 cornerFlags = ~0U; 718 break; 719 } 720 if (!cornerFlags) { 721 circularRadius = radii[c].fX; 722 cornerFlags = 1 << c; 723 } else { 724 if (radii[c].fX != circularRadius) { 725 cornerFlags = ~0U; 726 break; 727 } 728 cornerFlags |= 1 << c; 729 } 730 } 731 732 switch (cornerFlags) { 733 case CircularRRectEffect::kAll_CornerFlags: 734 // This rrect should have been caught in the simple case above. Though, it would 735 // be correctly handled in the fallthrough code. 736 SkASSERT(false); 737 case CircularRRectEffect::kTopLeft_CornerFlag: 738 case CircularRRectEffect::kTopRight_CornerFlag: 739 case CircularRRectEffect::kBottomRight_CornerFlag: 740 case CircularRRectEffect::kBottomLeft_CornerFlag: 741 case CircularRRectEffect::kLeft_CornerFlags: 742 case CircularRRectEffect::kTop_CornerFlags: 743 case CircularRRectEffect::kRight_CornerFlags: 744 case CircularRRectEffect::kBottom_CornerFlags: { 745 SkTCopyOnFirstWrite<SkRRect> rr(rrect); 746 if (squashedRadii) { 747 rr.writable()->setRectRadii(rrect.getBounds(), radii); 748 } 749 return CircularRRectEffect::Make(edgeType, cornerFlags, *rr); 750 } 751 case CircularRRectEffect::kNone_CornerFlags: 752 return GrConvexPolyEffect::Make(edgeType, rrect.getBounds()); 753 default: { 754 if (squashedRadii) { 755 // If we got here then we squashed some but not all the radii to zero. (If all 756 // had been squashed cornerFlags would be 0.) The elliptical effect doesn't 757 // support some rounded and some square corners. 758 return nullptr; 759 } 760 if (rrect.isNinePatch()) { 761 return EllipticalRRectEffect::Make(edgeType, rrect); 762 } 763 return nullptr; 764 } 765 } 766 } 767 768 return nullptr; 769} 770