Home | History | Annotate | Download | only in effects
      1 /*
      2  * Copyright 2013 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 #ifndef GrBezierEffect_DEFINED
      9 #define GrBezierEffect_DEFINED
     10 
     11 #include "GrDrawTargetCaps.h"
     12 #include "GrProcessor.h"
     13 #include "GrGeometryProcessor.h"
     14 #include "GrTypesPriv.h"
     15 
     16 /**
     17  * Shader is based off of Loop-Blinn Quadratic GPU Rendering
     18  * The output of this effect is a hairline edge for conics.
     19  * Conics specified by implicit equation K^2 - LM.
     20  * K, L, and M, are the first three values of the vertex attribute,
     21  * the fourth value is not used. Distance is calculated using a
     22  * first order approximation from the taylor series.
     23  * Coverage for AA is max(0, 1-distance).
     24  *
     25  * Test were also run using a second order distance approximation.
     26  * There were two versions of the second order approx. The first version
     27  * is of roughly the form:
     28  * f(q) = |f(p)| - ||f'(p)||*||q-p|| - ||f''(p)||*||q-p||^2.
     29  * The second is similar:
     30  * f(q) = |f(p)| + ||f'(p)||*||q-p|| + ||f''(p)||*||q-p||^2.
     31  * The exact version of the equations can be found in the paper
     32  * "Distance Approximations for Rasterizing Implicit Curves" by Gabriel Taubin
     33  *
     34  * In both versions we solve the quadratic for ||q-p||.
     35  * Version 1:
     36  * gFM is magnitude of first partials and gFM2 is magnitude of 2nd partials (as derived from paper)
     37  * builder->fsCodeAppend("\t\tedgeAlpha = (sqrt(gFM*gFM+4.0*func*gF2M) - gFM)/(2.0*gF2M);\n");
     38  * Version 2:
     39  * builder->fsCodeAppend("\t\tedgeAlpha = (gFM - sqrt(gFM*gFM-4.0*func*gF2M))/(2.0*gF2M);\n");
     40  *
     41  * Also note that 2nd partials of k,l,m are zero
     42  *
     43  * When comparing the two second order approximations to the first order approximations,
     44  * the following results were found. Version 1 tends to underestimate the distances, thus it
     45  * basically increases all the error that we were already seeing in the first order
     46  * approx. So this version is not the one to use. Version 2 has the opposite effect
     47  * and tends to overestimate the distances. This is much closer to what we are
     48  * looking for. It is able to render ellipses (even thin ones) without the need to chop.
     49  * However, it can not handle thin hyperbolas well and thus would still rely on
     50  * chopping to tighten the clipping. Another side effect of the overestimating is
     51  * that the curves become much thinner and "ropey". If all that was ever rendered
     52  * were "not too thin" curves and ellipses then 2nd order may have an advantage since
     53  * only one geometry would need to be rendered. However no benches were run comparing
     54  * chopped first order and non chopped 2nd order.
     55  */
     56 class GrGLConicEffect;
     57 
     58 class GrConicEffect : public GrGeometryProcessor {
     59 public:
     60     static GrGeometryProcessor* Create(const GrPrimitiveEdgeType edgeType,
     61                                        const GrDrawTargetCaps& caps) {
     62         GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gConicFillAA, GrConicEffect,
     63                                             (kFillAA_GrProcessorEdgeType));
     64         GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gConicHairAA, GrConicEffect,
     65                                             (kHairlineAA_GrProcessorEdgeType));
     66         GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gConicFillBW, GrConicEffect,
     67                                             (kFillBW_GrProcessorEdgeType));
     68         switch (edgeType) {
     69             case kFillAA_GrProcessorEdgeType:
     70                 if (!caps.shaderDerivativeSupport()) {
     71                     return NULL;
     72                 }
     73                 gConicFillAA->ref();
     74                 return gConicFillAA;
     75             case kHairlineAA_GrProcessorEdgeType:
     76                 if (!caps.shaderDerivativeSupport()) {
     77                     return NULL;
     78                 }
     79                 gConicHairAA->ref();
     80                 return gConicHairAA;
     81             case kFillBW_GrProcessorEdgeType:
     82                 gConicFillBW->ref();
     83                 return gConicFillBW;
     84             default:
     85                 return NULL;
     86         }
     87     }
     88 
     89     virtual ~GrConicEffect();
     90 
     91     static const char* Name() { return "Conic"; }
     92 
     93     inline const GrShaderVar& inConicCoeffs() const { return fInConicCoeffs; }
     94     inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
     95     inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
     96     inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
     97 
     98     typedef GrGLConicEffect GLProcessor;
     99 
    100     virtual void getConstantColorComponents(GrColor* color,
    101                                             uint32_t* validFlags) const SK_OVERRIDE {
    102         *validFlags = 0;
    103     }
    104 
    105     virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE;
    106 
    107 private:
    108     GrConicEffect(GrPrimitiveEdgeType);
    109 
    110     virtual bool onIsEqual(const GrProcessor& other) const SK_OVERRIDE;
    111 
    112     GrPrimitiveEdgeType   fEdgeType;
    113     const GrShaderVar& fInConicCoeffs;
    114 
    115     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
    116 
    117     typedef GrGeometryProcessor INHERITED;
    118 };
    119 
    120 ///////////////////////////////////////////////////////////////////////////////
    121 /**
    122  * The output of this effect is a hairline edge for quadratics.
    123  * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
    124  * two components of the vertex attribute. At the three control points that define
    125  * the Quadratic, u, v have the values {0,0}, {1/2, 0}, and {1, 1} respectively.
    126  * Coverage for AA is min(0, 1-distance). 3rd & 4th cimponent unused.
    127  * Requires shader derivative instruction support.
    128  */
    129 class GrGLQuadEffect;
    130 
    131 class GrQuadEffect : public GrGeometryProcessor {
    132 public:
    133     static GrGeometryProcessor* Create(const GrPrimitiveEdgeType edgeType,
    134                                        const GrDrawTargetCaps& caps) {
    135         GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gQuadFillAA, GrQuadEffect,
    136                                             (kFillAA_GrProcessorEdgeType));
    137         GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gQuadHairAA, GrQuadEffect,
    138                                             (kHairlineAA_GrProcessorEdgeType));
    139         GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gQuadFillBW, GrQuadEffect,
    140                                             (kFillBW_GrProcessorEdgeType));
    141         switch (edgeType) {
    142             case kFillAA_GrProcessorEdgeType:
    143                 if (!caps.shaderDerivativeSupport()) {
    144                     return NULL;
    145                 }
    146                 gQuadFillAA->ref();
    147                 return gQuadFillAA;
    148             case kHairlineAA_GrProcessorEdgeType:
    149                 if (!caps.shaderDerivativeSupport()) {
    150                     return NULL;
    151                 }
    152                 gQuadHairAA->ref();
    153                 return gQuadHairAA;
    154             case kFillBW_GrProcessorEdgeType:
    155                 gQuadFillBW->ref();
    156                 return gQuadFillBW;
    157             default:
    158                 return NULL;
    159         }
    160     }
    161 
    162     virtual ~GrQuadEffect();
    163 
    164     static const char* Name() { return "Quad"; }
    165 
    166     inline const GrShaderVar& inHairQuadEdge() const { return fInHairQuadEdge; }
    167     inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
    168     inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
    169     inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
    170 
    171     typedef GrGLQuadEffect GLProcessor;
    172 
    173     virtual void getConstantColorComponents(GrColor* color,
    174                                             uint32_t* validFlags) const SK_OVERRIDE {
    175         *validFlags = 0;
    176     }
    177 
    178     virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE;
    179 
    180 private:
    181     GrQuadEffect(GrPrimitiveEdgeType);
    182 
    183     virtual bool onIsEqual(const GrProcessor& other) const SK_OVERRIDE;
    184 
    185     GrPrimitiveEdgeType   fEdgeType;
    186     const GrShaderVar& fInHairQuadEdge;
    187 
    188     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
    189 
    190     typedef GrGeometryProcessor INHERITED;
    191 };
    192 
    193 //////////////////////////////////////////////////////////////////////////////
    194 /**
    195  * Shader is based off of "Resolution Independent Curve Rendering using
    196  * Programmable Graphics Hardware" by Loop and Blinn.
    197  * The output of this effect is a hairline edge for non rational cubics.
    198  * Cubics are specified by implicit equation K^3 - LM.
    199  * K, L, and M, are the first three values of the vertex attribute,
    200  * the fourth value is not used. Distance is calculated using a
    201  * first order approximation from the taylor series.
    202  * Coverage for AA is max(0, 1-distance).
    203  */
    204 class GrGLCubicEffect;
    205 
    206 class GrCubicEffect : public GrGeometryProcessor {
    207 public:
    208     static GrGeometryProcessor* Create(const GrPrimitiveEdgeType edgeType,
    209                                        const GrDrawTargetCaps& caps) {
    210         GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gCubicFillAA, GrCubicEffect,
    211                                             (kFillAA_GrProcessorEdgeType));
    212         GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gCubicHairAA, GrCubicEffect,
    213                                             (kHairlineAA_GrProcessorEdgeType));
    214         GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gCubicFillBW, GrCubicEffect,
    215                                             (kFillBW_GrProcessorEdgeType));
    216         switch (edgeType) {
    217             case kFillAA_GrProcessorEdgeType:
    218                 if (!caps.shaderDerivativeSupport()) {
    219                     return NULL;
    220                 }
    221                 gCubicFillAA->ref();
    222                 return gCubicFillAA;
    223             case kHairlineAA_GrProcessorEdgeType:
    224                 if (!caps.shaderDerivativeSupport()) {
    225                     return NULL;
    226                 }
    227                 gCubicHairAA->ref();
    228                 return gCubicHairAA;
    229             case kFillBW_GrProcessorEdgeType:
    230                 gCubicFillBW->ref();
    231                 return gCubicFillBW;
    232             default:
    233                 return NULL;
    234         }
    235     }
    236 
    237     virtual ~GrCubicEffect();
    238 
    239     static const char* Name() { return "Cubic"; }
    240 
    241     inline const GrShaderVar& inCubicCoeffs() const { return fInCubicCoeffs; }
    242     inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
    243     inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
    244     inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
    245 
    246     typedef GrGLCubicEffect GLProcessor;
    247 
    248     virtual void getConstantColorComponents(GrColor* color,
    249                                             uint32_t* validFlags) const SK_OVERRIDE {
    250         *validFlags = 0;
    251     }
    252 
    253     virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE;
    254 
    255 private:
    256     GrCubicEffect(GrPrimitiveEdgeType);
    257 
    258     virtual bool onIsEqual(const GrProcessor& other) const SK_OVERRIDE;
    259 
    260     GrPrimitiveEdgeType   fEdgeType;
    261     const GrShaderVar& fInCubicCoeffs;
    262 
    263     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
    264 
    265     typedef GrGeometryProcessor INHERITED;
    266 };
    267 
    268 #endif
    269