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 "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 sk_sp<GrGeometryProcessor> Make(GrColor color,
     61                                            const SkMatrix& viewMatrix,
     62                                            const GrPrimitiveEdgeType edgeType,
     63                                            const GrCaps& caps,
     64                                            const SkMatrix& localMatrix,
     65                                            bool usesLocalCoords,
     66                                            uint8_t coverage = 0xff) {
     67         switch (edgeType) {
     68             case kFillAA_GrProcessorEdgeType:
     69                 if (!caps.shaderCaps()->shaderDerivativeSupport()) {
     70                     return nullptr;
     71                 }
     72                 return sk_sp<GrGeometryProcessor>(
     73                     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 sk_sp<GrGeometryProcessor>(
     80                     new GrConicEffect(color, viewMatrix, coverage,
     81                                       kHairlineAA_GrProcessorEdgeType, localMatrix,
     82                                       usesLocalCoords));
     83             case kFillBW_GrProcessorEdgeType:
     84                 return sk_sp<GrGeometryProcessor>(
     85                     new GrConicEffect(color, viewMatrix, coverage, kFillBW_GrProcessorEdgeType,
     86                                       localMatrix, usesLocalCoords));
     87             default:
     88                 return nullptr;
     89         }
     90     }
     91 
     92     ~GrConicEffect() override;
     93 
     94     const char* name() const override { return "Conic"; }
     95 
     96     inline const Attribute* inPosition() const { return fInPosition; }
     97     inline const Attribute* inConicCoeffs() const { return fInConicCoeffs; }
     98     inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
     99     inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
    100     inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
    101     GrColor color() const { return fColor; }
    102     const SkMatrix& viewMatrix() const { return fViewMatrix; }
    103     const SkMatrix& localMatrix() const { return fLocalMatrix; }
    104     bool usesLocalCoords() const { return fUsesLocalCoords; }
    105     uint8_t coverageScale() const { return fCoverageScale; }
    106 
    107     void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
    108 
    109     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
    110 
    111 private:
    112     GrConicEffect(GrColor, const SkMatrix& viewMatrix, uint8_t coverage, GrPrimitiveEdgeType,
    113                   const SkMatrix& localMatrix, bool usesLocalCoords);
    114 
    115     GrColor             fColor;
    116     SkMatrix            fViewMatrix;
    117     SkMatrix            fLocalMatrix;
    118     bool                fUsesLocalCoords;
    119     uint8_t             fCoverageScale;
    120     GrPrimitiveEdgeType fEdgeType;
    121     const Attribute*    fInPosition;
    122     const Attribute*    fInConicCoeffs;
    123 
    124     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
    125 
    126     typedef GrGeometryProcessor INHERITED;
    127 };
    128 
    129 ///////////////////////////////////////////////////////////////////////////////
    130 /**
    131  * The output of this effect is a hairline edge for quadratics.
    132  * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
    133  * two components of the vertex attribute. At the three control points that define
    134  * the Quadratic, u, v have the values {0,0}, {1/2, 0}, and {1, 1} respectively.
    135  * Coverage for AA is min(0, 1-distance). 3rd & 4th cimponent unused.
    136  * Requires shader derivative instruction support.
    137  */
    138 class GrGLQuadEffect;
    139 
    140 class GrQuadEffect : public GrGeometryProcessor {
    141 public:
    142     static sk_sp<GrGeometryProcessor> Make(GrColor color,
    143                                            const SkMatrix& viewMatrix,
    144                                            const GrPrimitiveEdgeType edgeType,
    145                                            const GrCaps& caps,
    146                                            const SkMatrix& localMatrix,
    147                                            bool usesLocalCoords,
    148                                            uint8_t coverage = 0xff) {
    149         switch (edgeType) {
    150             case kFillAA_GrProcessorEdgeType:
    151                 if (!caps.shaderCaps()->shaderDerivativeSupport()) {
    152                     return nullptr;
    153                 }
    154                 return sk_sp<GrGeometryProcessor>(
    155                     new GrQuadEffect(color, viewMatrix, coverage, kFillAA_GrProcessorEdgeType,
    156                                      localMatrix, usesLocalCoords));
    157             case kHairlineAA_GrProcessorEdgeType:
    158                 if (!caps.shaderCaps()->shaderDerivativeSupport()) {
    159                     return nullptr;
    160                 }
    161                 return sk_sp<GrGeometryProcessor>(
    162                     new GrQuadEffect(color, viewMatrix, coverage,
    163                                      kHairlineAA_GrProcessorEdgeType, localMatrix,
    164                                      usesLocalCoords));
    165             case kFillBW_GrProcessorEdgeType:
    166                 return sk_sp<GrGeometryProcessor>(
    167                     new GrQuadEffect(color, viewMatrix, coverage, kFillBW_GrProcessorEdgeType,
    168                                      localMatrix, usesLocalCoords));
    169             default:
    170                 return nullptr;
    171         }
    172     }
    173 
    174     ~GrQuadEffect() override;
    175 
    176     const char* name() const override { return "Quad"; }
    177 
    178     inline const Attribute* inPosition() const { return fInPosition; }
    179     inline const Attribute* inHairQuadEdge() const { return fInHairQuadEdge; }
    180     inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
    181     inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
    182     inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
    183     GrColor color() const { return fColor; }
    184     const SkMatrix& viewMatrix() const { return fViewMatrix; }
    185     const SkMatrix& localMatrix() const { return fLocalMatrix; }
    186     bool usesLocalCoords() const { return fUsesLocalCoords; }
    187     uint8_t coverageScale() const { return fCoverageScale; }
    188 
    189     void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
    190 
    191     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
    192 
    193 private:
    194     GrQuadEffect(GrColor, const SkMatrix& viewMatrix, uint8_t coverage, GrPrimitiveEdgeType,
    195                  const SkMatrix& localMatrix, bool usesLocalCoords);
    196 
    197     GrColor             fColor;
    198     SkMatrix            fViewMatrix;
    199     SkMatrix            fLocalMatrix;
    200     bool                fUsesLocalCoords;
    201     uint8_t             fCoverageScale;
    202     GrPrimitiveEdgeType fEdgeType;
    203     const Attribute*    fInPosition;
    204     const Attribute*    fInHairQuadEdge;
    205 
    206     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
    207 
    208     typedef GrGeometryProcessor INHERITED;
    209 };
    210 
    211 //////////////////////////////////////////////////////////////////////////////
    212 /**
    213  * Shader is based off of "Resolution Independent Curve Rendering using
    214  * Programmable Graphics Hardware" by Loop and Blinn.
    215  * The output of this effect is a hairline edge for non rational cubics.
    216  * Cubics are specified by implicit equation K^3 - LM.
    217  * K, L, and M, are the first three values of the vertex attribute,
    218  * the fourth value is not used. Distance is calculated using a
    219  * first order approximation from the taylor series.
    220  * Coverage for AA is max(0, 1-distance).
    221  */
    222 class GrGLCubicEffect;
    223 
    224 class GrCubicEffect : public GrGeometryProcessor {
    225 public:
    226     static sk_sp<GrGeometryProcessor> Make(GrColor color,
    227                                            const SkMatrix& viewMatrix,
    228                                            const GrPrimitiveEdgeType edgeType,
    229                                            const GrCaps& caps) {
    230         switch (edgeType) {
    231             case kFillAA_GrProcessorEdgeType:
    232                 if (!caps.shaderCaps()->shaderDerivativeSupport()) {
    233                     return nullptr;
    234                 }
    235                 return sk_sp<GrGeometryProcessor>(
    236                     new GrCubicEffect(color, viewMatrix, kFillAA_GrProcessorEdgeType));
    237             case kHairlineAA_GrProcessorEdgeType:
    238                 if (!caps.shaderCaps()->shaderDerivativeSupport()) {
    239                     return nullptr;
    240                 }
    241                 return sk_sp<GrGeometryProcessor>(
    242                     new GrCubicEffect(color, viewMatrix, kHairlineAA_GrProcessorEdgeType));
    243             case kFillBW_GrProcessorEdgeType:
    244                 return sk_sp<GrGeometryProcessor>(
    245                     new GrCubicEffect(color, viewMatrix, kFillBW_GrProcessorEdgeType));
    246             default:
    247                 return nullptr;
    248         }
    249     }
    250 
    251     ~GrCubicEffect() override;
    252 
    253     const char* name() const override { return "Cubic"; }
    254 
    255     inline const Attribute* inPosition() const { return fInPosition; }
    256     inline const Attribute* inCubicCoeffs() const { return fInCubicCoeffs; }
    257     inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
    258     inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
    259     inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
    260     GrColor color() const { return fColor; }
    261     bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
    262     const SkMatrix& viewMatrix() const { return fViewMatrix; }
    263 
    264     void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
    265 
    266     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
    267 
    268 private:
    269     GrCubicEffect(GrColor, const SkMatrix& viewMatrix, GrPrimitiveEdgeType);
    270 
    271     GrColor             fColor;
    272     SkMatrix            fViewMatrix;
    273     GrPrimitiveEdgeType fEdgeType;
    274     const Attribute*    fInPosition;
    275     const Attribute*    fInCubicCoeffs;
    276 
    277     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
    278 
    279     typedef GrGeometryProcessor INHERITED;
    280 };
    281 
    282 #endif
    283