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