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