LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu/effects - GrRRectEffect.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 375 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 36 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13