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