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 "SkRRect.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. 22 static const SkScalar kRadiusMin = SK_ScalarHalf; 23 24 ////////////////////////////////////////////////////////////////////////////// 25 26 class CircularRRectEffect : public GrFragmentProcessor { 27 public: 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 sk_sp<GrFragmentProcessor> Make(GrPrimitiveEdgeType, uint32_t circularCornerFlags, 49 const SkRRect&); 50 51 ~CircularRRectEffect() override {} 52 53 const char* name() const override { return "CircularRRect"; } 54 55 const SkRRect& getRRect() const { return fRRect; } 56 57 uint32_t getCircularCornerFlags() const { return fCircularCornerFlags; } 58 59 GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } 60 61 private: 62 CircularRRectEffect(GrPrimitiveEdgeType, uint32_t circularCornerFlags, const SkRRect&); 63 64 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; 65 66 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 67 68 bool onIsEqual(const GrFragmentProcessor& other) const override; 69 70 SkRRect fRRect; 71 GrPrimitiveEdgeType fEdgeType; 72 uint32_t fCircularCornerFlags; 73 74 GR_DECLARE_FRAGMENT_PROCESSOR_TEST 75 76 typedef GrFragmentProcessor INHERITED; 77 }; 78 79 sk_sp<GrFragmentProcessor> CircularRRectEffect::Make(GrPrimitiveEdgeType edgeType, 80 uint32_t circularCornerFlags, 81 const SkRRect& rrect) { 82 if (kFillAA_GrProcessorEdgeType != edgeType && kInverseFillAA_GrProcessorEdgeType != edgeType) { 83 return nullptr; 84 } 85 return sk_sp<GrFragmentProcessor>( 86 new CircularRRectEffect(edgeType, circularCornerFlags, rrect)); 87 } 88 89 CircularRRectEffect::CircularRRectEffect(GrPrimitiveEdgeType edgeType, uint32_t circularCornerFlags, 90 const SkRRect& rrect) 91 : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag) 92 , fRRect(rrect) 93 , fEdgeType(edgeType) 94 , fCircularCornerFlags(circularCornerFlags) { 95 this->initClassID<CircularRRectEffect>(); 96 } 97 98 bool CircularRRectEffect::onIsEqual(const GrFragmentProcessor& other) const { 99 const CircularRRectEffect& crre = other.cast<CircularRRectEffect>(); 100 // The corner flags are derived from fRRect, so no need to check them. 101 return fEdgeType == crre.fEdgeType && fRRect == crre.fRRect; 102 } 103 104 ////////////////////////////////////////////////////////////////////////////// 105 106 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircularRRectEffect); 107 108 #if GR_TEST_UTILS 109 sk_sp<GrFragmentProcessor> CircularRRectEffect::TestCreate(GrProcessorTestData* d) { 110 SkScalar w = d->fRandom->nextRangeScalar(20.f, 1000.f); 111 SkScalar h = d->fRandom->nextRangeScalar(20.f, 1000.f); 112 SkScalar r = d->fRandom->nextRangeF(kRadiusMin, 9.f); 113 SkRRect rrect; 114 rrect.setRectXY(SkRect::MakeWH(w, h), r, r); 115 sk_sp<GrFragmentProcessor> fp; 116 do { 117 GrPrimitiveEdgeType et = 118 (GrPrimitiveEdgeType)d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt); 119 fp = GrRRectEffect::Make(et, rrect); 120 } while (nullptr == fp); 121 return fp; 122 } 123 #endif 124 125 ////////////////////////////////////////////////////////////////////////////// 126 127 class GLCircularRRectEffect : public GrGLSLFragmentProcessor { 128 public: 129 GLCircularRRectEffect() { 130 fPrevRRect.setEmpty(); 131 } 132 133 virtual void emitCode(EmitArgs&) override; 134 135 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); 136 137 protected: 138 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; 139 140 private: 141 GrGLSLProgramDataManager::UniformHandle fInnerRectUniform; 142 GrGLSLProgramDataManager::UniformHandle fRadiusPlusHalfUniform; 143 SkRRect fPrevRRect; 144 typedef GrGLSLFragmentProcessor INHERITED; 145 }; 146 147 void GLCircularRRectEffect::emitCode(EmitArgs& args) { 148 const CircularRRectEffect& crre = args.fFp.cast<CircularRRectEffect>(); 149 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 150 const char *rectName; 151 const char *radiusPlusHalfName; 152 // The inner rect is the rrect bounds inset by the radius. Its left, top, right, and bottom 153 // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has 154 // only rectangular corners, that side's value corresponds to the rect edge's value outset by 155 // half a pixel. 156 fInnerRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, 157 kVec4f_GrSLType, kDefault_GrSLPrecision, 158 "innerRect", 159 &rectName); 160 // x is (r + .5) and y is 1/(r + .5) 161 fRadiusPlusHalfUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, 162 kVec2f_GrSLType, kDefault_GrSLPrecision, 163 "radiusPlusHalf", 164 &radiusPlusHalfName); 165 166 // If we're on a device with a "real" mediump then the length calculation could overflow. 167 SkString clampedCircleDistance; 168 if (args.fShaderCaps->floatPrecisionVaries()) { 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("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName); 194 fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName); 195 fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);"); 196 fragBuilder->codeAppendf("float alpha = %s;", clampedCircleDistance.c_str()); 197 break; 198 case CircularRRectEffect::kTopLeft_CornerFlag: 199 fragBuilder->codeAppendf("vec2 dxy = max(%s.xy - sk_FragCoord.xy, 0.0);", 200 rectName); 201 fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);", 202 rectName); 203 fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);", 204 rectName); 205 fragBuilder->codeAppendf("float alpha = bottomAlpha * rightAlpha * %s;", 206 clampedCircleDistance.c_str()); 207 break; 208 case CircularRRectEffect::kTopRight_CornerFlag: 209 fragBuilder->codeAppendf("vec2 dxy = max(vec2(sk_FragCoord.x - %s.z, " 210 "%s.y - sk_FragCoord.y), 0.0);", 211 rectName, rectName); 212 fragBuilder->codeAppendf("float leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);", 213 rectName); 214 fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);", 215 rectName); 216 fragBuilder->codeAppendf("float alpha = bottomAlpha * leftAlpha * %s;", 217 clampedCircleDistance.c_str()); 218 break; 219 case CircularRRectEffect::kBottomRight_CornerFlag: 220 fragBuilder->codeAppendf("vec2 dxy = max(sk_FragCoord.xy - %s.zw, 0.0);", 221 rectName); 222 fragBuilder->codeAppendf("float leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);", 223 rectName); 224 fragBuilder->codeAppendf("float topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);", 225 rectName); 226 fragBuilder->codeAppendf("float alpha = topAlpha * leftAlpha * %s;", 227 clampedCircleDistance.c_str()); 228 break; 229 case CircularRRectEffect::kBottomLeft_CornerFlag: 230 fragBuilder->codeAppendf("vec2 dxy = max(vec2(%s.x - sk_FragCoord.x, sk_FragCoord.y - " 231 "%s.w), 0.0);", 232 rectName, rectName); 233 fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);", 234 rectName); 235 fragBuilder->codeAppendf("float topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);", 236 rectName); 237 fragBuilder->codeAppendf("float alpha = topAlpha * rightAlpha * %s;", 238 clampedCircleDistance.c_str()); 239 break; 240 case CircularRRectEffect::kLeft_CornerFlags: 241 fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName); 242 fragBuilder->codeAppendf("float dy1 = sk_FragCoord.y - %s.w;", rectName); 243 fragBuilder->codeAppend("vec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);"); 244 fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);", 245 rectName); 246 fragBuilder->codeAppendf("float alpha = rightAlpha * %s;", 247 clampedCircleDistance.c_str()); 248 break; 249 case CircularRRectEffect::kTop_CornerFlags: 250 fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName); 251 fragBuilder->codeAppendf("float dx1 = sk_FragCoord.x - %s.z;", rectName); 252 fragBuilder->codeAppend("vec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);"); 253 fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);", 254 rectName); 255 fragBuilder->codeAppendf("float 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("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName); 261 fragBuilder->codeAppend("vec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);"); 262 fragBuilder->codeAppendf("float leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);", 263 rectName); 264 fragBuilder->codeAppendf("float 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("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName); 270 fragBuilder->codeAppend("vec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);"); 271 fragBuilder->codeAppendf("float topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);", 272 rectName); 273 fragBuilder->codeAppendf("float alpha = topAlpha * %s;", 274 clampedCircleDistance.c_str()); 275 break; 276 } 277 278 if (kInverseFillAA_GrProcessorEdgeType == crre.getEdgeType()) { 279 fragBuilder->codeAppend("alpha = 1.0 - alpha;"); 280 } 281 282 fragBuilder->codeAppendf("%s = %s * alpha;", args.fOutputColor, args.fInputColor); 283 } 284 285 void GLCircularRRectEffect::GenKey(const GrProcessor& processor, const GrShaderCaps&, 286 GrProcessorKeyBuilder* b) { 287 const CircularRRectEffect& crre = processor.cast<CircularRRectEffect>(); 288 GR_STATIC_ASSERT(kGrProcessorEdgeTypeCnt <= 8); 289 b->add32((crre.getCircularCornerFlags() << 3) | crre.getEdgeType()); 290 } 291 292 void 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(rrect.isSimpleCircular()); 302 radius = rrect.getSimpleRadii().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 SkFAIL("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 374 void CircularRRectEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, 375 GrProcessorKeyBuilder* b) const { 376 GLCircularRRectEffect::GenKey(*this, caps, b); 377 } 378 379 GrGLSLFragmentProcessor* CircularRRectEffect::onCreateGLSLInstance() const { 380 return new GLCircularRRectEffect; 381 } 382 383 ////////////////////////////////////////////////////////////////////////////// 384 385 class EllipticalRRectEffect : public GrFragmentProcessor { 386 public: 387 static sk_sp<GrFragmentProcessor> Make(GrPrimitiveEdgeType, const SkRRect&); 388 389 ~EllipticalRRectEffect() override {} 390 391 const char* name() const override { return "EllipticalRRect"; } 392 393 const SkRRect& getRRect() const { return fRRect; } 394 395 GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } 396 397 private: 398 EllipticalRRectEffect(GrPrimitiveEdgeType, const SkRRect&); 399 400 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; 401 402 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 403 404 bool onIsEqual(const GrFragmentProcessor& other) const override; 405 406 SkRRect fRRect; 407 GrPrimitiveEdgeType fEdgeType; 408 409 GR_DECLARE_FRAGMENT_PROCESSOR_TEST 410 411 typedef GrFragmentProcessor INHERITED; 412 }; 413 414 sk_sp<GrFragmentProcessor> 415 EllipticalRRectEffect::Make(GrPrimitiveEdgeType edgeType, const SkRRect& rrect) { 416 if (kFillAA_GrProcessorEdgeType != edgeType && kInverseFillAA_GrProcessorEdgeType != edgeType) { 417 return nullptr; 418 } 419 return sk_sp<GrFragmentProcessor>(new EllipticalRRectEffect(edgeType, rrect)); 420 } 421 422 EllipticalRRectEffect::EllipticalRRectEffect(GrPrimitiveEdgeType edgeType, const SkRRect& rrect) 423 : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag) 424 , fRRect(rrect) 425 , fEdgeType(edgeType) { 426 this->initClassID<EllipticalRRectEffect>(); 427 } 428 429 bool EllipticalRRectEffect::onIsEqual(const GrFragmentProcessor& other) const { 430 const EllipticalRRectEffect& erre = other.cast<EllipticalRRectEffect>(); 431 return fEdgeType == erre.fEdgeType && fRRect == erre.fRRect; 432 } 433 434 ////////////////////////////////////////////////////////////////////////////// 435 436 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipticalRRectEffect); 437 438 #if GR_TEST_UTILS 439 sk_sp<GrFragmentProcessor> EllipticalRRectEffect::TestCreate(GrProcessorTestData* d) { 440 SkScalar w = d->fRandom->nextRangeScalar(20.f, 1000.f); 441 SkScalar h = d->fRandom->nextRangeScalar(20.f, 1000.f); 442 SkVector r[4]; 443 r[SkRRect::kUpperLeft_Corner].fX = d->fRandom->nextRangeF(kRadiusMin, 9.f); 444 // ensure at least one corner really is elliptical 445 do { 446 r[SkRRect::kUpperLeft_Corner].fY = d->fRandom->nextRangeF(kRadiusMin, 9.f); 447 } while (r[SkRRect::kUpperLeft_Corner].fY == r[SkRRect::kUpperLeft_Corner].fX); 448 449 SkRRect rrect; 450 if (d->fRandom->nextBool()) { 451 // half the time create a four-radii rrect. 452 r[SkRRect::kLowerRight_Corner].fX = d->fRandom->nextRangeF(kRadiusMin, 9.f); 453 r[SkRRect::kLowerRight_Corner].fY = d->fRandom->nextRangeF(kRadiusMin, 9.f); 454 455 r[SkRRect::kUpperRight_Corner].fX = r[SkRRect::kLowerRight_Corner].fX; 456 r[SkRRect::kUpperRight_Corner].fY = r[SkRRect::kUpperLeft_Corner].fY; 457 458 r[SkRRect::kLowerLeft_Corner].fX = r[SkRRect::kUpperLeft_Corner].fX; 459 r[SkRRect::kLowerLeft_Corner].fY = r[SkRRect::kLowerRight_Corner].fY; 460 461 rrect.setRectRadii(SkRect::MakeWH(w, h), r); 462 } else { 463 rrect.setRectXY(SkRect::MakeWH(w, h), r[SkRRect::kUpperLeft_Corner].fX, 464 r[SkRRect::kUpperLeft_Corner].fY); 465 } 466 sk_sp<GrFragmentProcessor> fp; 467 do { 468 GrPrimitiveEdgeType et = 469 (GrPrimitiveEdgeType)d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt); 470 fp = GrRRectEffect::Make(et, rrect); 471 } while (nullptr == fp); 472 return fp; 473 } 474 #endif 475 476 ////////////////////////////////////////////////////////////////////////////// 477 478 class GLEllipticalRRectEffect : public GrGLSLFragmentProcessor { 479 public: 480 GLEllipticalRRectEffect() { 481 fPrevRRect.setEmpty(); 482 } 483 484 void emitCode(EmitArgs&) override; 485 486 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); 487 488 protected: 489 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; 490 491 private: 492 GrGLSLProgramDataManager::UniformHandle fInnerRectUniform; 493 GrGLSLProgramDataManager::UniformHandle fInvRadiiSqdUniform; 494 GrGLSLProgramDataManager::UniformHandle fScaleUniform; 495 SkRRect fPrevRRect; 496 typedef GrGLSLFragmentProcessor INHERITED; 497 }; 498 499 void GLEllipticalRRectEffect::emitCode(EmitArgs& args) { 500 const EllipticalRRectEffect& erre = args.fFp.cast<EllipticalRRectEffect>(); 501 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 502 const char *rectName; 503 // The inner rect is the rrect bounds inset by the x/y radii 504 fInnerRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, 505 kVec4f_GrSLType, kDefault_GrSLPrecision, 506 "innerRect", 507 &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("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName); 523 fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName); 524 525 // If we're on a device with a "real" mediump 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->floatPrecisionVaries()) { 530 fScaleUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, 531 kVec2f_GrSLType, kDefault_GrSLPrecision, 532 "scale", &scaleName); 533 } 534 535 // The uniforms with the inv squared radii are highp to prevent underflow. 536 switch (erre.getRRect().getType()) { 537 case SkRRect::kSimple_Type: { 538 const char *invRadiiXYSqdName; 539 fInvRadiiSqdUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, 540 kVec2f_GrSLType, 541 kDefault_GrSLPrecision, 542 "invRadiiXY", 543 &invRadiiXYSqdName); 544 fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);"); 545 if (scaleName) { 546 fragBuilder->codeAppendf("dxy *= %s.y;", scaleName); 547 } 548 // Z is the x/y offsets divided by squared radii. 549 fragBuilder->codeAppendf("vec2 Z = dxy * %s.xy;", invRadiiXYSqdName); 550 break; 551 } 552 case SkRRect::kNinePatch_Type: { 553 const char *invRadiiLTRBSqdName; 554 fInvRadiiSqdUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, 555 kVec4f_GrSLType, 556 kDefault_GrSLPrecision, 557 "invRadiiLTRB", 558 &invRadiiLTRBSqdName); 559 if (scaleName) { 560 fragBuilder->codeAppendf("dxy0 *= %s.y;", scaleName); 561 fragBuilder->codeAppendf("dxy1 *= %s.y;", scaleName); 562 } 563 fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);"); 564 // Z is the x/y offsets divided by squared radii. We only care about the (at most) one 565 // corner where both the x and y offsets are positive, hence the maxes. (The inverse 566 // squared radii will always be positive.) 567 fragBuilder->codeAppendf("vec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);", 568 invRadiiLTRBSqdName, invRadiiLTRBSqdName); 569 570 break; 571 } 572 default: 573 SkFAIL("RRect should always be simple or nine-patch."); 574 } 575 // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1. 576 fragBuilder->codeAppend("float implicit = dot(Z, dxy) - 1.0;"); 577 // grad_dot is the squared length of the gradient of the implicit. 578 fragBuilder->codeAppend("float grad_dot = 4.0 * dot(Z, Z);"); 579 // avoid calling inversesqrt on zero. 580 fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);"); 581 fragBuilder->codeAppend("float approx_dist = implicit * inversesqrt(grad_dot);"); 582 if (scaleName) { 583 fragBuilder->codeAppendf("approx_dist *= %s.x;", scaleName); 584 } 585 586 if (kFillAA_GrProcessorEdgeType == erre.getEdgeType()) { 587 fragBuilder->codeAppend("float alpha = clamp(0.5 - approx_dist, 0.0, 1.0);"); 588 } else { 589 fragBuilder->codeAppend("float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);"); 590 } 591 592 fragBuilder->codeAppendf("%s = %s * alpha;", args.fOutputColor, args.fInputColor); 593 } 594 595 void GLEllipticalRRectEffect::GenKey(const GrProcessor& effect, const GrShaderCaps&, 596 GrProcessorKeyBuilder* b) { 597 const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>(); 598 GR_STATIC_ASSERT(kLast_GrProcessorEdgeType < (1 << 3)); 599 b->add32(erre.getRRect().getType() | erre.getEdgeType() << 3); 600 } 601 602 void GLEllipticalRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman, 603 const GrFragmentProcessor& effect) { 604 const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>(); 605 const SkRRect& rrect = erre.getRRect(); 606 // If we're using a scale factor to work around precision issues, choose the largest radius 607 // as the scale factor. The inv radii need to be pre-adjusted by the scale factor. 608 if (rrect != fPrevRRect) { 609 SkRect rect = rrect.getBounds(); 610 const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner); 611 SkASSERT(r0.fX >= kRadiusMin); 612 SkASSERT(r0.fY >= kRadiusMin); 613 switch (erre.getRRect().getType()) { 614 case SkRRect::kSimple_Type: 615 rect.inset(r0.fX, r0.fY); 616 if (fScaleUniform.isValid()) { 617 if (r0.fX > r0.fY) { 618 pdman.set2f(fInvRadiiSqdUniform, 1.f, (r0.fX * r0.fX) / (r0.fY * r0.fY)); 619 pdman.set2f(fScaleUniform, r0.fX, 1.f / r0.fX); 620 } else { 621 pdman.set2f(fInvRadiiSqdUniform, (r0.fY * r0.fY) / (r0.fX * r0.fX), 1.f); 622 pdman.set2f(fScaleUniform, r0.fY, 1.f / r0.fY); 623 } 624 } else { 625 pdman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), 626 1.f / (r0.fY * r0.fY)); 627 } 628 break; 629 case SkRRect::kNinePatch_Type: { 630 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner); 631 SkASSERT(r1.fX >= kRadiusMin); 632 SkASSERT(r1.fY >= kRadiusMin); 633 rect.fLeft += r0.fX; 634 rect.fTop += r0.fY; 635 rect.fRight -= r1.fX; 636 rect.fBottom -= r1.fY; 637 if (fScaleUniform.isValid()) { 638 float scale = SkTMax(SkTMax(r0.fX, r0.fY), SkTMax(r1.fX, r1.fY)); 639 float scaleSqd = scale * scale; 640 pdman.set4f(fInvRadiiSqdUniform, scaleSqd / (r0.fX * r0.fX), 641 scaleSqd / (r0.fY * r0.fY), 642 scaleSqd / (r1.fX * r1.fX), 643 scaleSqd / (r1.fY * r1.fY)); 644 pdman.set2f(fScaleUniform, scale, 1.f / scale); 645 } else { 646 pdman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), 647 1.f / (r0.fY * r0.fY), 648 1.f / (r1.fX * r1.fX), 649 1.f / (r1.fY * r1.fY)); 650 } 651 break; 652 } 653 default: 654 SkFAIL("RRect should always be simple or nine-patch."); 655 } 656 pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); 657 fPrevRRect = rrect; 658 } 659 } 660 661 //////////////////////////////////////////////////////////////////////////////////////////////////// 662 663 void EllipticalRRectEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, 664 GrProcessorKeyBuilder* b) const { 665 GLEllipticalRRectEffect::GenKey(*this, caps, b); 666 } 667 668 GrGLSLFragmentProcessor* EllipticalRRectEffect::onCreateGLSLInstance() const { 669 return new GLEllipticalRRectEffect; 670 } 671 672 ////////////////////////////////////////////////////////////////////////////// 673 674 sk_sp<GrFragmentProcessor> GrRRectEffect::Make(GrPrimitiveEdgeType edgeType, const SkRRect& rrect) { 675 if (rrect.isRect()) { 676 return GrConvexPolyEffect::Make(edgeType, rrect.getBounds()); 677 } 678 679 if (rrect.isOval()) { 680 return GrOvalEffect::Make(edgeType, rrect.getBounds()); 681 } 682 683 if (rrect.isSimple()) { 684 if (rrect.getSimpleRadii().fX < kRadiusMin || rrect.getSimpleRadii().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 (rrect.getSimpleRadii().fX == rrect.getSimpleRadii().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