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