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(const SkPMColor4f& color,
     61                                            const SkMatrix& viewMatrix,
     62                                            const GrClipEdgeType edgeType,
     63                                            const GrCaps& caps,
     64                                            const SkMatrix& localMatrix,
     65                                            bool usesLocalCoords,
     66                                            uint8_t coverage = 0xff) {
     67         switch (edgeType) {
     68             case GrClipEdgeType::kFillAA:
     69                 if (!caps.shaderCaps()->shaderDerivativeSupport()) {
     70                     return nullptr;
     71                 }
     72                 return sk_sp<GrGeometryProcessor>(
     73                     new GrConicEffect(color, viewMatrix, coverage, GrClipEdgeType::kFillAA,
     74                                       localMatrix, usesLocalCoords));
     75             case GrClipEdgeType::kHairlineAA:
     76                 if (!caps.shaderCaps()->shaderDerivativeSupport()) {
     77                     return nullptr;
     78                 }
     79                 return sk_sp<GrGeometryProcessor>(
     80                     new GrConicEffect(color, viewMatrix, coverage,
     81                                       GrClipEdgeType::kHairlineAA, localMatrix,
     82                                       usesLocalCoords));
     83             case GrClipEdgeType::kFillBW:
     84                 return sk_sp<GrGeometryProcessor>(
     85                     new GrConicEffect(color, viewMatrix, coverage, GrClipEdgeType::kFillBW,
     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 kAttributes[0]; }
     97     inline const Attribute& inConicCoeffs() const { return kAttributes[1]; }
     98     inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
     99     inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
    100     inline GrClipEdgeType getEdgeType() const { return fEdgeType; }
    101     const SkPMColor4f& 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(const SkPMColor4f&, const SkMatrix& viewMatrix, uint8_t coverage, GrClipEdgeType,
    113                   const SkMatrix& localMatrix, bool usesLocalCoords);
    114 
    115     SkPMColor4f         fColor;
    116     SkMatrix            fViewMatrix;
    117     SkMatrix            fLocalMatrix;
    118     bool                fUsesLocalCoords;
    119     uint8_t             fCoverageScale;
    120     GrClipEdgeType fEdgeType;
    121     static constexpr Attribute kAttributes[] = {
    122         {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType},
    123         {"inConicCoeffs", kFloat4_GrVertexAttribType, kHalf4_GrSLType}
    124     };
    125 
    126     GR_DECLARE_GEOMETRY_PROCESSOR_TEST
    127 
    128     typedef GrGeometryProcessor INHERITED;
    129 };
    130 
    131 ///////////////////////////////////////////////////////////////////////////////
    132 /**
    133  * The output of this effect is a hairline edge for quadratics.
    134  * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
    135  * two components of the vertex attribute. At the three control points that define
    136  * the Quadratic, u, v have the values {0,0}, {1/2, 0}, and {1, 1} respectively.
    137  * Coverage for AA is min(0, 1-distance). 3rd & 4th cimponent unused.
    138  * Requires shader derivative instruction support.
    139  */
    140 class GrGLQuadEffect;
    141 
    142 class GrQuadEffect : public GrGeometryProcessor {
    143 public:
    144     static sk_sp<GrGeometryProcessor> Make(const SkPMColor4f& color,
    145                                            const SkMatrix& viewMatrix,
    146                                            const GrClipEdgeType edgeType,
    147                                            const GrCaps& caps,
    148                                            const SkMatrix& localMatrix,
    149                                            bool usesLocalCoords,
    150                                            uint8_t coverage = 0xff) {
    151         switch (edgeType) {
    152             case GrClipEdgeType::kFillAA:
    153                 if (!caps.shaderCaps()->shaderDerivativeSupport()) {
    154                     return nullptr;
    155                 }
    156                 return sk_sp<GrGeometryProcessor>(
    157                     new GrQuadEffect(color, viewMatrix, coverage, GrClipEdgeType::kFillAA,
    158                                      localMatrix, usesLocalCoords));
    159             case GrClipEdgeType::kHairlineAA:
    160                 if (!caps.shaderCaps()->shaderDerivativeSupport()) {
    161                     return nullptr;
    162                 }
    163                 return sk_sp<GrGeometryProcessor>(
    164                     new GrQuadEffect(color, viewMatrix, coverage,
    165                                      GrClipEdgeType::kHairlineAA, localMatrix,
    166                                      usesLocalCoords));
    167             case GrClipEdgeType::kFillBW:
    168                 return sk_sp<GrGeometryProcessor>(
    169                     new GrQuadEffect(color, viewMatrix, coverage, GrClipEdgeType::kFillBW,
    170                                      localMatrix, usesLocalCoords));
    171             default:
    172                 return nullptr;
    173         }
    174     }
    175 
    176     ~GrQuadEffect() override;
    177 
    178     const char* name() const override { return "Quad"; }
    179 
    180     inline const Attribute& inPosition() const { return kAttributes[0]; }
    181     inline const Attribute& inHairQuadEdge() const { return kAttributes[1]; }
    182     inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
    183     inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
    184     inline GrClipEdgeType getEdgeType() const { return fEdgeType; }
    185     const SkPMColor4f& color() const { return fColor; }
    186     const SkMatrix& viewMatrix() const { return fViewMatrix; }
    187     const SkMatrix& localMatrix() const { return fLocalMatrix; }
    188     bool usesLocalCoords() const { return fUsesLocalCoords; }
    189     uint8_t coverageScale() const { return fCoverageScale; }
    190 
    191     void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
    192 
    193     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
    194 
    195 private:
    196     GrQuadEffect(const SkPMColor4f&, const SkMatrix& viewMatrix, uint8_t coverage, GrClipEdgeType,
    197                  const SkMatrix& localMatrix, bool usesLocalCoords);
    198 
    199     SkPMColor4f fColor;
    200     SkMatrix fViewMatrix;
    201     SkMatrix fLocalMatrix;
    202     bool fUsesLocalCoords;
    203     uint8_t fCoverageScale;
    204     GrClipEdgeType fEdgeType;
    205 
    206     static constexpr Attribute kAttributes[] = {
    207         {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType},
    208         {"inHairQuadEdge", kFloat4_GrVertexAttribType, kHalf4_GrSLType}
    209     };
    210 
    211     GR_DECLARE_GEOMETRY_PROCESSOR_TEST
    212 
    213     typedef GrGeometryProcessor INHERITED;
    214 };
    215 
    216 #endif
    217