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