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