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 name()92 const char* name() const override { return "Conic"; } 93 inPosition()94 inline const Attribute* inPosition() const { return fInPosition; } inConicCoeffs()95 inline const Attribute* inConicCoeffs() const { return fInConicCoeffs; } isAntiAliased()96 inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); } isFilled()97 inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); } getEdgeType()98 inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } color()99 GrColor color() const { return fColor; } colorIgnored()100 bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } viewMatrix()101 const SkMatrix& viewMatrix() const { return fViewMatrix; } localMatrix()102 const SkMatrix& localMatrix() const { return fLocalMatrix; } usesLocalCoords()103 bool usesLocalCoords() const { return fUsesLocalCoords; } coverageScale()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 name()172 const char* name() const override { return "Quad"; } 173 inPosition()174 inline const Attribute* inPosition() const { return fInPosition; } inHairQuadEdge()175 inline const Attribute* inHairQuadEdge() const { return fInHairQuadEdge; } isAntiAliased()176 inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); } isFilled()177 inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); } getEdgeType()178 inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } color()179 GrColor color() const { return fColor; } colorIgnored()180 bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } viewMatrix()181 const SkMatrix& viewMatrix() const { return fViewMatrix; } localMatrix()182 const SkMatrix& localMatrix() const { return fLocalMatrix; } usesLocalCoords()183 bool usesLocalCoords() const { return fUsesLocalCoords; } coverageScale()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: Create(GrColor color,const SkMatrix & viewMatrix,const GrPrimitiveEdgeType edgeType,const GrCaps & caps)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 name()247 const char* name() const override { return "Cubic"; } 248 inPosition()249 inline const Attribute* inPosition() const { return fInPosition; } inCubicCoeffs()250 inline const Attribute* inCubicCoeffs() const { return fInCubicCoeffs; } isAntiAliased()251 inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); } isFilled()252 inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); } getEdgeType()253 inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } color()254 GrColor color() const { return fColor; } colorIgnored()255 bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } viewMatrix()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