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