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