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 "GrConvexPolyEffect.h"
      9 
     10 #include "gl/GrGLEffect.h"
     11 #include "gl/GrGLSL.h"
     12 #include "GrTBackendEffectFactory.h"
     13 
     14 #include "SkPath.h"
     15 
     16 //////////////////////////////////////////////////////////////////////////////
     17 class GLAARectEffect;
     18 
     19 class AARectEffect : public GrEffect {
     20 public:
     21     typedef GLAARectEffect GLEffect;
     22 
     23     const SkRect& getRect() const { return fRect; }
     24 
     25     static const char* Name() { return "AARect"; }
     26 
     27     static GrEffectRef* Create(GrEffectEdgeType edgeType, const SkRect& rect) {
     28         return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(AARectEffect, (edgeType, rect))));
     29     }
     30 
     31     virtual void getConstantColorComponents(GrColor* color,
     32                                             uint32_t* validFlags) const SK_OVERRIDE {
     33         if (fRect.isEmpty()) {
     34             // An empty rect will have no coverage anywhere.
     35             *color = 0x00000000;
     36             *validFlags = kRGBA_GrColorComponentFlags;
     37         } else {
     38             *validFlags = 0;
     39         }
     40     }
     41 
     42     GrEffectEdgeType getEdgeType() const { return fEdgeType; }
     43 
     44     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
     45 
     46 private:
     47     AARectEffect(GrEffectEdgeType edgeType, const SkRect& rect) : fRect(rect), fEdgeType(edgeType) {
     48         this->setWillReadFragmentPosition();
     49     }
     50 
     51     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
     52         const AARectEffect& aare = CastEffect<AARectEffect>(other);
     53         return fRect == aare.fRect;
     54     }
     55 
     56     SkRect fRect;
     57     GrEffectEdgeType fEdgeType;
     58 
     59     typedef GrEffect INHERITED;
     60 
     61     GR_DECLARE_EFFECT_TEST;
     62 
     63 };
     64 
     65 GR_DEFINE_EFFECT_TEST(AARectEffect);
     66 
     67 GrEffectRef* AARectEffect::TestCreate(SkRandom* random,
     68                                       GrContext*,
     69                                       const GrDrawTargetCaps& caps,
     70                                       GrTexture*[]) {
     71     SkRect rect = SkRect::MakeLTRB(random->nextSScalar1(),
     72                                    random->nextSScalar1(),
     73                                    random->nextSScalar1(),
     74                                    random->nextSScalar1());
     75     GrEffectRef* effect;
     76     do {
     77         GrEffectEdgeType edgeType = static_cast<GrEffectEdgeType>(random->nextULessThan(
     78                                                                     kGrEffectEdgeTypeCnt));
     79 
     80         effect = AARectEffect::Create(edgeType, rect);
     81     } while (NULL == effect);
     82     return effect;
     83 }
     84 
     85 //////////////////////////////////////////////////////////////////////////////
     86 
     87 class GLAARectEffect : public GrGLEffect {
     88 public:
     89     GLAARectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
     90 
     91     virtual void emitCode(GrGLShaderBuilder* builder,
     92                           const GrDrawEffect& drawEffect,
     93                           EffectKey key,
     94                           const char* outputColor,
     95                           const char* inputColor,
     96                           const TransformedCoordsArray&,
     97                           const TextureSamplerArray&) SK_OVERRIDE;
     98 
     99     static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
    100 
    101     virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
    102 
    103 private:
    104     GrGLUniformManager::UniformHandle   fRectUniform;
    105     SkRect                              fPrevRect;
    106     typedef GrGLEffect INHERITED;
    107 };
    108 
    109 GLAARectEffect::GLAARectEffect(const GrBackendEffectFactory& factory,
    110                                const GrDrawEffect& drawEffect)
    111     : INHERITED (factory) {
    112     fPrevRect.fLeft = SK_ScalarNaN;
    113 }
    114 
    115 void GLAARectEffect::emitCode(GrGLShaderBuilder* builder,
    116                               const GrDrawEffect& drawEffect,
    117                               EffectKey key,
    118                               const char* outputColor,
    119                               const char* inputColor,
    120                               const TransformedCoordsArray&,
    121                               const TextureSamplerArray& samplers) {
    122     const AARectEffect& aare = drawEffect.castEffect<AARectEffect>();
    123     const char *rectName;
    124     // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5),
    125     // respectively.
    126     fRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
    127                                        kVec4f_GrSLType,
    128                                        "rect",
    129                                        &rectName);
    130     const char* fragmentPos = builder->fragmentPosition();
    131     if (GrEffectEdgeTypeIsAA(aare.getEdgeType())) {
    132         // The amount of coverage removed in x and y by the edges is computed as a pair of negative
    133         // numbers, xSub and ySub.
    134         builder->fsCodeAppend("\t\tfloat xSub, ySub;\n");
    135         builder->fsCodeAppendf("\t\txSub = min(%s.x - %s.x, 0.0);\n", fragmentPos, rectName);
    136         builder->fsCodeAppendf("\t\txSub += min(%s.z - %s.x, 0.0);\n", rectName, fragmentPos);
    137         builder->fsCodeAppendf("\t\tySub = min(%s.y - %s.y, 0.0);\n", fragmentPos, rectName);
    138         builder->fsCodeAppendf("\t\tySub += min(%s.w - %s.y, 0.0);\n", rectName, fragmentPos);
    139         // Now compute coverage in x and y and multiply them to get the fraction of the pixel
    140         // covered.
    141         builder->fsCodeAppendf("\t\tfloat alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n");
    142     } else {
    143         builder->fsCodeAppendf("\t\tfloat alpha = 1.0;\n");
    144         builder->fsCodeAppendf("\t\talpha *= (%s.x - %s.x) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName);
    145         builder->fsCodeAppendf("\t\talpha *= (%s.z - %s.x) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos);
    146         builder->fsCodeAppendf("\t\talpha *= (%s.y - %s.y) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName);
    147         builder->fsCodeAppendf("\t\talpha *= (%s.w - %s.y) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos);
    148     }
    149 
    150     if (GrEffectEdgeTypeIsInverseFill(aare.getEdgeType())) {
    151         builder->fsCodeAppend("\t\talpha = 1.0 - alpha;\n");
    152     }
    153     builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
    154                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
    155 }
    156 
    157 void GLAARectEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) {
    158     const AARectEffect& aare = drawEffect.castEffect<AARectEffect>();
    159     const SkRect& rect = aare.getRect();
    160     if (rect != fPrevRect) {
    161         uman.set4f(fRectUniform, rect.fLeft + 0.5f, rect.fTop + 0.5f,
    162                    rect.fRight - 0.5f, rect.fBottom - 0.5f);
    163         fPrevRect = rect;
    164     }
    165 }
    166 
    167 GrGLEffect::EffectKey GLAARectEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
    168     const AARectEffect& aare = drawEffect.castEffect<AARectEffect>();
    169     return aare.getEdgeType();
    170 }
    171 
    172 const GrBackendEffectFactory& AARectEffect::getFactory() const {
    173     return GrTBackendEffectFactory<AARectEffect>::getInstance();
    174 }
    175 
    176 //////////////////////////////////////////////////////////////////////////////
    177 
    178 class GrGLConvexPolyEffect : public GrGLEffect {
    179 public:
    180     GrGLConvexPolyEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
    181 
    182     virtual void emitCode(GrGLShaderBuilder* builder,
    183                           const GrDrawEffect& drawEffect,
    184                           EffectKey key,
    185                           const char* outputColor,
    186                           const char* inputColor,
    187                           const TransformedCoordsArray&,
    188                           const TextureSamplerArray&) SK_OVERRIDE;
    189 
    190     static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
    191 
    192     virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
    193 
    194 private:
    195     GrGLUniformManager::UniformHandle   fEdgeUniform;
    196     SkScalar                            fPrevEdges[3 * GrConvexPolyEffect::kMaxEdges];
    197     typedef GrGLEffect INHERITED;
    198 };
    199 
    200 GrGLConvexPolyEffect::GrGLConvexPolyEffect(const GrBackendEffectFactory& factory,
    201                                            const GrDrawEffect& drawEffect)
    202     : INHERITED (factory) {
    203     fPrevEdges[0] = SK_ScalarNaN;
    204 }
    205 
    206 void GrGLConvexPolyEffect::emitCode(GrGLShaderBuilder* builder,
    207                                     const GrDrawEffect& drawEffect,
    208                                     EffectKey key,
    209                                     const char* outputColor,
    210                                     const char* inputColor,
    211                                     const TransformedCoordsArray&,
    212                                     const TextureSamplerArray& samplers) {
    213     const GrConvexPolyEffect& cpe = drawEffect.castEffect<GrConvexPolyEffect>();
    214 
    215     const char *edgeArrayName;
    216     fEdgeUniform = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibility,
    217                                             kVec3f_GrSLType,
    218                                             "edges",
    219                                             cpe.getEdgeCount(),
    220                                             &edgeArrayName);
    221     builder->fsCodeAppend("\t\tfloat alpha = 1.0;\n");
    222     builder->fsCodeAppend("\t\tfloat edge;\n");
    223     const char* fragmentPos = builder->fragmentPosition();
    224     for (int i = 0; i < cpe.getEdgeCount(); ++i) {
    225         builder->fsCodeAppendf("\t\tedge = dot(%s[%d], vec3(%s.x, %s.y, 1));\n",
    226                                edgeArrayName, i, fragmentPos, fragmentPos);
    227         if (GrEffectEdgeTypeIsAA(cpe.getEdgeType())) {
    228             builder->fsCodeAppend("\t\tedge = clamp(edge, 0.0, 1.0);\n");
    229         } else {
    230             builder->fsCodeAppend("\t\tedge = edge >= 0.5 ? 1.0 : 0.0;\n");
    231         }
    232         builder->fsCodeAppend("\t\talpha *= edge;\n");
    233     }
    234 
    235     // Woe is me. See skbug.com/2149.
    236     if (kTegra2_GrGLRenderer == builder->ctxInfo().renderer()) {
    237         builder->fsCodeAppend("\t\tif (-1.0 == alpha) {\n\t\t\tdiscard;\n\t\t}\n");
    238     }
    239 
    240     if (GrEffectEdgeTypeIsInverseFill(cpe.getEdgeType())) {
    241         builder->fsCodeAppend("\talpha = 1.0 - alpha;\n");
    242     }
    243     builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
    244                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
    245 }
    246 
    247 void GrGLConvexPolyEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) {
    248     const GrConvexPolyEffect& cpe = drawEffect.castEffect<GrConvexPolyEffect>();
    249     size_t byteSize = 3 * cpe.getEdgeCount() * sizeof(SkScalar);
    250     if (0 != memcmp(fPrevEdges, cpe.getEdges(), byteSize)) {
    251         uman.set3fv(fEdgeUniform, cpe.getEdgeCount(), cpe.getEdges());
    252         memcpy(fPrevEdges, cpe.getEdges(), byteSize);
    253     }
    254 }
    255 
    256 GrGLEffect::EffectKey GrGLConvexPolyEffect::GenKey(const GrDrawEffect& drawEffect,
    257                                                    const GrGLCaps&) {
    258     const GrConvexPolyEffect& cpe = drawEffect.castEffect<GrConvexPolyEffect>();
    259     GR_STATIC_ASSERT(kGrEffectEdgeTypeCnt <= 8);
    260     return (cpe.getEdgeCount() << 3) | cpe.getEdgeType();
    261 }
    262 
    263 //////////////////////////////////////////////////////////////////////////////
    264 
    265 GrEffectRef* GrConvexPolyEffect::Create(GrEffectEdgeType type, const SkPath& path, const SkVector* offset) {
    266     if (kHairlineAA_GrEffectEdgeType == type) {
    267         return NULL;
    268     }
    269     if (path.getSegmentMasks() != SkPath::kLine_SegmentMask ||
    270         !path.isConvex()) {
    271         return NULL;
    272     }
    273 
    274     if (path.countPoints() > kMaxEdges) {
    275         return NULL;
    276     }
    277 
    278     SkPoint pts[kMaxEdges];
    279     SkScalar edges[3 * kMaxEdges];
    280 
    281     SkPath::Direction dir;
    282     SkAssertResult(path.cheapComputeDirection(&dir));
    283 
    284     SkVector t;
    285     if (NULL == offset) {
    286         t.set(0, 0);
    287     } else {
    288         t = *offset;
    289     }
    290 
    291     int count = path.getPoints(pts, kMaxEdges);
    292     int n = 0;
    293     for (int lastPt = count - 1, i = 0; i < count; lastPt = i++) {
    294         if (pts[lastPt] != pts[i]) {
    295             SkVector v = pts[i] - pts[lastPt];
    296             v.normalize();
    297             if (SkPath::kCCW_Direction == dir) {
    298                 edges[3 * n] = v.fY;
    299                 edges[3 * n + 1] = -v.fX;
    300             } else {
    301                 edges[3 * n] = -v.fY;
    302                 edges[3 * n + 1] = v.fX;
    303             }
    304             SkPoint p = pts[i] + t;
    305             edges[3 * n + 2] = -(edges[3 * n] * p.fX + edges[3 * n + 1] * p.fY);
    306             ++n;
    307         }
    308     }
    309     if (path.isInverseFillType()) {
    310         type = GrInvertEffectEdgeType(type);
    311     }
    312     return Create(type, n, edges);
    313 }
    314 
    315 GrEffectRef* GrConvexPolyEffect::Create(GrEffectEdgeType edgeType, const SkRect& rect) {
    316     if (kHairlineAA_GrEffectEdgeType == edgeType){
    317         return NULL;
    318     }
    319     return AARectEffect::Create(edgeType, rect);
    320 }
    321 
    322 GrConvexPolyEffect::~GrConvexPolyEffect() {}
    323 
    324 void GrConvexPolyEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
    325     *validFlags = 0;
    326 }
    327 
    328 const GrBackendEffectFactory& GrConvexPolyEffect::getFactory() const {
    329     return GrTBackendEffectFactory<GrConvexPolyEffect>::getInstance();
    330 }
    331 
    332 GrConvexPolyEffect::GrConvexPolyEffect(GrEffectEdgeType edgeType, int n, const SkScalar edges[])
    333     : fEdgeType(edgeType)
    334     , fEdgeCount(n) {
    335     // Factory function should have already ensured this.
    336     SkASSERT(n <= kMaxEdges);
    337     memcpy(fEdges, edges, 3 * n * sizeof(SkScalar));
    338     // Outset the edges by 0.5 so that a pixel with center on an edge is 50% covered in the AA case
    339     // and 100% covered in the non-AA case.
    340     for (int i = 0; i < n; ++i) {
    341         fEdges[3 * i + 2] += SK_ScalarHalf;
    342     }
    343     this->setWillReadFragmentPosition();
    344 }
    345 
    346 bool GrConvexPolyEffect::onIsEqual(const GrEffect& other) const {
    347     const GrConvexPolyEffect& cpe = CastEffect<GrConvexPolyEffect>(other);
    348     // ignore the fact that 0 == -0 and just use memcmp.
    349     return (cpe.fEdgeType == fEdgeType && cpe.fEdgeCount == fEdgeCount &&
    350             0 == memcmp(cpe.fEdges, fEdges, 3 * fEdgeCount * sizeof(SkScalar)));
    351 }
    352 
    353 //////////////////////////////////////////////////////////////////////////////
    354 
    355 GR_DEFINE_EFFECT_TEST(GrConvexPolyEffect);
    356 
    357 GrEffectRef* GrConvexPolyEffect::TestCreate(SkRandom* random,
    358                                             GrContext*,
    359                                             const GrDrawTargetCaps& caps,
    360                                             GrTexture*[]) {
    361     int count = random->nextULessThan(kMaxEdges) + 1;
    362     SkScalar edges[kMaxEdges * 3];
    363     for (int i = 0; i < 3 * count; ++i) {
    364         edges[i] = random->nextSScalar1();
    365     }
    366 
    367     GrEffectRef* effect;
    368     do {
    369         GrEffectEdgeType edgeType = static_cast<GrEffectEdgeType>(
    370                                         random->nextULessThan(kGrEffectEdgeTypeCnt));
    371         effect = GrConvexPolyEffect::Create(edgeType, count, edges);
    372     } while (NULL == effect);
    373     return effect;
    374 }
    375